summaryrefslogtreecommitdiff
path: root/spec/ruby/language/predefined/fixtures/data1.rb
diff options
context:
space:
mode:
Diffstat (limited to 'spec/ruby/language/predefined/fixtures/data1.rb')
-rw-r--r--spec/ruby/language/predefined/fixtures/data1.rb4
1 files changed, 4 insertions, 0 deletions
diff --git a/spec/ruby/language/predefined/fixtures/data1.rb b/spec/ruby/language/predefined/fixtures/data1.rb
new file mode 100644
index 0000000000..cb9572255b
--- /dev/null
+++ b/spec/ruby/language/predefined/fixtures/data1.rb
@@ -0,0 +1,4 @@
+puts Object.const_defined?(:DATA)
+
+__END__
+data1
' width='100%'> -rw-r--r--doc/ChangeLog/ChangeLog-2.4.06
-rw-r--r--doc/NEWS/NEWS-3.0.0.md6
-rw-r--r--doc/NEWS/NEWS-3.1.0.md4
-rw-r--r--doc/NEWS/NEWS-3.2.0.md4
-rw-r--r--doc/NEWS/NEWS-3.3.0.md529
-rw-r--r--doc/NEWS/NEWS-3.4.0.md962
-rw-r--r--doc/NEWS/NEWS-4.0.0.md802
-rw-r--r--doc/_regexp.rdoc1291
-rw-r--r--doc/_timezones.rdoc163
-rw-r--r--doc/command_injection.rdoc29
-rw-r--r--doc/contributing.md12
-rw-r--r--doc/contributing/bug_triaging.rdoc (renamed from doc/bug_triaging.rdoc)0
-rw-r--r--doc/contributing/building_ruby.md287
-rw-r--r--doc/contributing/concurrency_guide.md154
-rw-r--r--doc/contributing/contributing.md35
-rw-r--r--doc/contributing/documentation_guide.md363
-rw-r--r--doc/contributing/dtrace_probes.rdoc (renamed from doc/dtrace_probes.rdoc)0
-rw-r--r--doc/contributing/glossary.md20
-rw-r--r--doc/contributing/making_changes_to_stdlibs.md16
-rw-r--r--doc/contributing/memory_view.md (renamed from doc/memory_view.md)0
-rw-r--r--doc/contributing/reporting_issues.md37
-rw-r--r--doc/contributing/testing_ruby.md123
-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.rdoc63
-rw-r--r--doc/csv/options/common/quote_char.rdoc42
-rw-r--r--doc/csv/options/common/row_sep.rdoc100
-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.rdoc33
-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.rdoc19
-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.rdoc156
-rw-r--r--doc/csv/recipes/generating.rdoc244
-rw-r--r--doc/csv/recipes/parsing.rdoc543
-rw-r--r--doc/csv/recipes/recipes.rdoc6
-rw-r--r--doc/distribution/distribution.md (renamed from doc/distribution.md)7
-rw-r--r--doc/distribution/windows.md (renamed from doc/windows.md)178
-rw-r--r--doc/examples/files.rdoc8
-rw-r--r--doc/extension.ja.rdoc54
-rw-r--r--doc/extension.rdoc308
-rw-r--r--doc/file/filename_globbing.md299
-rw-r--r--doc/file/filename_matching.md471
-rw-r--r--doc/file/timestamps.md83
-rw-r--r--doc/float.rb128
-rw-r--r--doc/forwardable.rd.ja80
-rw-r--r--doc/globals.rdoc69
-rw-r--r--doc/index.md65
-rw-r--r--doc/irb/irb-tools.rd.ja184
-rw-r--r--doc/irb/irb.rd.ja427
-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)2
-rw-r--r--doc/language/calendars.rdoc (renamed from doc/date/calendars.rdoc)4
-rw-r--r--doc/language/case_mapping.rdoc (renamed from doc/case_mapping.rdoc)34
-rw-r--r--doc/language/character_selectors.rdoc (renamed from doc/character_selectors.rdoc)11
-rw-r--r--doc/language/dig_methods.rdoc (renamed from doc/dig_methods.rdoc)0
-rw-r--r--doc/language/encodings.rdoc (renamed from doc/encodings.rdoc)181
-rw-r--r--doc/language/exceptions.md521
-rw-r--r--doc/language/fiber.md (renamed from doc/fiber.md)72
-rw-r--r--doc/language/format_specifications.rdoc (renamed from doc/format_specifications.rdoc)108
-rw-r--r--doc/language/globals.md611
-rw-r--r--doc/language/hash_inclusion.rdoc31
-rw-r--r--doc/language/implicit_conversion.rdoc (renamed from doc/implicit_conversion.rdoc)10
-rw-r--r--doc/language/marshal.rdoc (renamed from doc/marshal.rdoc)9
-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.rdoc41
-rw-r--r--doc/language/regexp/unicode_properties.rdoc718
-rw-r--r--doc/language/signals.rdoc (renamed from doc/signals.rdoc)2
-rw-r--r--doc/language/strftime_formatting.rdoc (renamed from doc/strftime_formatting.rdoc)60
-rw-r--r--doc/maintainers.md684
-rw-r--r--doc/matchdata/begin.rdoc12
-rw-r--r--doc/matchdata/bytebegin.rdoc30
-rw-r--r--doc/matchdata/byteend.rdoc30
-rw-r--r--doc/matchdata/end.rdoc12
-rw-r--r--doc/matchdata/offset.rdoc12
-rw-r--r--doc/math/math.rdoc2
-rw-r--r--doc/optparse/argument_converters.rdoc72
-rw-r--r--doc/optparse/option_params.rdoc45
-rw-r--r--doc/optparse/ruby/argument_abbreviation.rb9
-rw-r--r--doc/optparse/ruby/matched_values.rb6
-rw-r--r--doc/optparse/tutorial.rdoc123
-rw-r--r--doc/packed_data.rdoc590
-rw-r--r--doc/pty/README.expect.ja32
-rw-r--r--doc/pty/README.ja50
-rw-r--r--doc/ractor.md952
-rw-r--r--doc/rdoc/markup_reference.rb1257
-rw-r--r--doc/regexp.rdoc810
-rw-r--r--doc/rjit/rjit.md45
-rw-r--r--doc/security/command_injection.rdoc15
-rw-r--r--doc/security/security.rdoc (renamed from doc/security.rdoc)22
-rw-r--r--doc/standard_library.md223
-rw-r--r--doc/standard_library.rdoc132
-rw-r--r--doc/string.rb421
-rw-r--r--doc/string/aref.rdoc96
-rw-r--r--doc/string/aset.rdoc179
-rw-r--r--doc/string/b.rdoc2
-rw-r--r--doc/string/bytes.rdoc5
-rw-r--r--doc/string/bytesize.rdoc17
-rw-r--r--doc/string/byteslice.rdoc54
-rw-r--r--doc/string/bytesplice.rdoc65
-rw-r--r--doc/string/capitalize.rdoc26
-rw-r--r--doc/string/center.rdoc21
-rw-r--r--doc/string/chars.rdoc4
-rw-r--r--doc/string/chomp.rdoc8
-rw-r--r--doc/string/chop.rdoc7
-rw-r--r--doc/string/chr.rdoc7
-rw-r--r--doc/string/codepoints.rdoc4
-rw-r--r--doc/string/concat.rdoc11
-rw-r--r--doc/string/count.rdoc74
-rw-r--r--doc/string/delete.rdoc75
-rw-r--r--doc/string/delete_prefix.rdoc11
-rw-r--r--doc/string/delete_suffix.rdoc10
-rw-r--r--doc/string/downcase.rdoc20
-rw-r--r--doc/string/dump.rdoc89
-rw-r--r--doc/string/each_byte.rdoc22
-rw-r--r--doc/string/each_char.rdoc26
-rw-r--r--doc/string/each_codepoint.rdoc28
-rw-r--r--doc/string/each_grapheme_cluster.rdoc19
-rw-r--r--doc/string/each_line.rdoc24
-rw-r--r--doc/string/encode.rdoc5
-rw-r--r--doc/string/end_with_p.rdoc16
-rw-r--r--doc/string/eql_p.rdoc18
-rw-r--r--doc/string/force_encoding.rdoc15
-rw-r--r--doc/string/getbyte.rdoc23
-rw-r--r--doc/string/grapheme_clusters.rdoc15
-rw-r--r--doc/string/hash.rdoc19
-rw-r--r--doc/string/index.rdoc30
-rw-r--r--doc/string/insert.rdoc15
-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/new.rdoc44
-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.rdoc131
-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/helper_methods.md124
-rw-r--r--doc/strscan/link_refs.txt17
-rw-r--r--doc/strscan/methods/get_byte.md27
-rw-r--r--doc/strscan/methods/get_charpos.md16
-rw-r--r--doc/strscan/methods/get_pos.md11
-rw-r--r--doc/strscan/methods/getch.md40
-rw-r--r--doc/strscan/methods/scan.md48
-rw-r--r--doc/strscan/methods/scan_until.md49
-rw-r--r--doc/strscan/methods/set_pos.md23
-rw-r--r--doc/strscan/methods/skip.md40
-rw-r--r--doc/strscan/methods/skip_until.md48
-rw-r--r--doc/strscan/methods/terminate.md27
-rw-r--r--doc/strscan/strscan.md544
-rw-r--r--doc/syntax.rdoc8
-rw-r--r--doc/syntax/assignment.rdoc8
-rw-r--r--doc/syntax/calling_methods.rdoc101
-rw-r--r--doc/syntax/comments.rdoc4
-rw-r--r--doc/syntax/control_expressions.rdoc72
-rw-r--r--doc/syntax/exceptions.rdoc10
-rw-r--r--doc/syntax/keywords.rdoc (renamed from doc/keywords.rdoc)2
-rw-r--r--doc/syntax/layout.rdoc118
-rw-r--r--doc/syntax/literals.rdoc224
-rw-r--r--doc/syntax/methods.rdoc1
-rw-r--r--doc/syntax/modules_and_classes.rdoc28
-rw-r--r--doc/syntax/operators.rdoc75
-rw-r--r--doc/syntax/pattern_matching.rdoc16
-rw-r--r--doc/syntax/refinements.rdoc71
-rw-r--r--doc/timezones.rdoc108
-rw-r--r--doc/yarvarch.en7
-rw-r--r--doc/yarvarch.ja454
-rw-r--r--doc/yjit/yjit.md360
-rw-r--r--doc/yjit/yjit_hacking.md75
220 files changed, 18384 insertions, 8652 deletions
diff --git a/doc/.document b/doc/.document
index 5ef2d99651..337289a662 100644
--- a/doc/.document
+++ b/doc/.document
@@ -1,8 +1,14 @@
-*.md
-*.rb
-*.rdoc
+[^_]*.md
+[^_]*.rb
+[^_]*.rdoc
contributing
+distribution
NEWS
syntax
optparse
-rdoc
+jit
+security
+language
+strscan
+file
+
diff --git a/doc/ChangeLog/ChangeLog-1.9.3 b/doc/ChangeLog/ChangeLog-1.9.3
index 0f80eed2d5..03a7f3eabf 100644
--- a/doc/ChangeLog/ChangeLog-1.9.3
+++ b/doc/ChangeLog/ChangeLog-1.9.3
@@ -9012,7 +9012,7 @@ Thu Dec 2 01:24:39 2010 NARUSE, Yui <naruse@ruby-lang.org>
Thu Dec 2 01:02:03 2010 NARUSE, Yui <naruse@ruby-lang.org>
- * ext/json: Update github/flori/json from 1.4.2+ to
+ * ext/json: Update github/ruby/json from 1.4.2+ to
e22b2f2bdfe6a9b0. this fixes some bugs.
Thu Dec 2 00:05:44 2010 NARUSE, Yui <naruse@ruby-lang.org>
diff --git a/doc/ChangeLog/ChangeLog-2.0.0 b/doc/ChangeLog/ChangeLog-2.0.0
index 9e654db189..de47b66a69 100644
--- a/doc/ChangeLog/ChangeLog-2.0.0
+++ b/doc/ChangeLog/ChangeLog-2.0.0
@@ -14426,7 +14426,7 @@ Tue May 8 02:34:26 2012 NARUSE, Yui <naruse@ruby-lang.org>
Mon May 7 21:19:17 2012 NARUSE, Yui <naruse@ruby-lang.org>
* ext/json: Merge JSON 1.7.1.
- https://github.com/flori/json/commit/e5b9a9465c1159fae533bca320d950b772bcb4ac
+ https://github.com/ruby/json/commit/e5b9a9465c1159fae533bca320d950b772bcb4ac
Mon May 7 22:54:22 2012 Martin Bosslet <Martin.Bosslet@googlemail.com>
diff --git a/doc/ChangeLog/ChangeLog-2.1.0 b/doc/ChangeLog/ChangeLog-2.1.0
index 5b670b31c9..b6977dbccd 100644
--- a/doc/ChangeLog/ChangeLog-2.1.0
+++ b/doc/ChangeLog/ChangeLog-2.1.0
@@ -659,7 +659,7 @@ Mon Dec 9 02:10:32 2013 NARUSE, Yui <naruse@ruby-lang.org>
* lib/net/http/responses.rb:
Add `HTTPIMUsed`, as it is also supported by rack/rails.
- RFC - http://tools.ietf.org/html/rfc3229
+ RFC - https://www.rfc-editor.org/rfc/rfc3229
by Vipul A M <vipulnsward@gmail.com>
https://github.com/ruby/ruby/pull/447 fix GH-447
@@ -2167,7 +2167,7 @@ Wed Nov 20 11:46:38 2013 NARUSE, Yui <naruse@ruby-lang.org>
* ext/json: merge JSON 1.8.1.
https://github.com/nurse/json/compare/002ac2771ce32776b32ccd2d06e5604de6c36dcd...e09ffc0d7da25d0393873936c118c188c78dbac3
* Remove Rubinius exception since transcoding should be working now.
- * Fix https://github.com/flori/json/issues/162 reported by Marc-Andre
+ * Fix https://github.com/ruby/json/issues/162 reported by Marc-Andre
Lafortune <github_rocks@marc-andre.ca>. Thanks!
* Applied patches by Yui NARUSE <naruse@airemix.jp> to suppress
warning with -Wchar-subscripts and better validate UTF-8 strings.
@@ -17913,7 +17913,7 @@ Tue Feb 12 12:02:35 2013 NARUSE, Yui <naruse@ruby-lang.org>
* ext/json: merge JSON 1.7.7.
This includes security fix. [CVE-2013-0269]
- https://github.com/flori/json/commit/d0a62f3ced7560daba2ad546d83f0479a5ae2cf2
+ https://github.com/ruby/json/commit/d0a62f3ced7560daba2ad546d83f0479a5ae2cf2
https://groups.google.com/d/topic/rubyonrails-security/4_YvCpLzL58/discussion
Mon Feb 11 23:08:48 2013 Tanaka Akira <akr@fsij.org>
diff --git a/doc/ChangeLog/ChangeLog-2.2.0 b/doc/ChangeLog/ChangeLog-2.2.0
index 5a7dbf826d..0edcf0122b 100644
--- a/doc/ChangeLog/ChangeLog-2.2.0
+++ b/doc/ChangeLog/ChangeLog-2.2.0
@@ -5648,7 +5648,7 @@ Wed Aug 6 04:16:05 2014 NARUSE, Yui <naruse@ruby-lang.org>
* lib/net/http/requests.rb (Net::HTTP::Options::RESPONSE_HAS_BODY):
OPTIONS requests may have response bodies. [Feature #8429]
- http://tools.ietf.org/html/rfc7231#section-4.3.7
+ https://www.rfc-editor.org/rfc/rfc7231#section-4.3.7
Wed Aug 6 03:18:04 2014 NARUSE, Yui <naruse@ruby-lang.org>
diff --git a/doc/ChangeLog/ChangeLog-2.3.0 b/doc/ChangeLog/ChangeLog-2.3.0
index 94996cffd0..e616183895 100644
--- a/doc/ChangeLog/ChangeLog-2.3.0
+++ b/doc/ChangeLog/ChangeLog-2.3.0
@@ -1211,7 +1211,7 @@ Sun Dec 6 08:39:05 2015 SHIBATA Hiroshi <hsbt@ruby-lang.org>
upstream changes.
https://github.com/ruby/ruby/commit/4d059bf9f5f10f3d3088de49fc87e5555db7770d
- https://github.com/flori/json/commit/d4c99de78905d96c3f301f48b2c789943bb3f098
+ https://github.com/ruby/json/commit/d4c99de78905d96c3f301f48b2c789943bb3f098
* ext/json/lib/json/version.rb: ditto.
@@ -10989,7 +10989,7 @@ Fri Feb 13 21:16:00 2015 Yusuke Endoh <mame@tsg.ne.jp>
Fri Feb 13 14:19:06 2015 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
- * ext/json: merge upstream from flori/json
+ * ext/json: merge upstream from ruby/json
change usage of TypedData. [Feature #10739][ruby-core:67564]
Thu Feb 12 18:34:01 2015 multisnow <infinity.blick.winkel@gmail.com>
@@ -11556,7 +11556,7 @@ Tue Jan 13 21:08:22 2015 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
* ext/json, test/json: merge JSON HEAD(259dee6)
separate implementation of Typed_Data macro.
- https://github.com/flori/json/compare/v1.8.1...v1.8.2
+ https://github.com/ruby/json/compare/v1.8.1...v1.8.2
Tue Jan 13 14:16:35 2015 Nobuyoshi Nakada <nobu@ruby-lang.org>
@@ -12009,7 +12009,7 @@ Mon Dec 29 10:37:27 2014 Thiago Lewin <thiago_lewin@yahoo.com.br>
Mon Dec 29 07:27:23 2014 SHIBATA Hiroshi <shibata.hiroshi@gmail.com>
* ext/json, test/json: merge JSON HEAD(17fe8e7)
- https://github.com/flori/json/compare/v1.8.1...17fe8e7
+ https://github.com/ruby/json/compare/v1.8.1...17fe8e7
Sun Dec 28 23:49:37 2014 Michal Papis <mpapis@gmail.com>
diff --git a/doc/ChangeLog/ChangeLog-2.4.0 b/doc/ChangeLog/ChangeLog-2.4.0
index a297a579d1..5e126fbd90 100644
--- a/doc/ChangeLog/ChangeLog-2.4.0
+++ b/doc/ChangeLog/ChangeLog-2.4.0
@@ -2668,8 +2668,8 @@ Wed Jul 6 07:11:27 2016 Shugo Maeda <shugo@ruby-lang.org>
Tue Jul 5 20:49:30 2016 SHIBATA Hiroshi <hsbt@ruby-lang.org>
* ext/json/*, test/json/*: Update json-2.0.1.
- Changes of 2.0.0: https://github.com/flori/json/blob/f679ebd0c69a94e3e70a897ac9a229f5779c2ee1/CHANGES.md#2015-09-11-200
- Changes of 2.0.1: https://github.com/flori/json/blob/f679ebd0c69a94e3e70a897ac9a229f5779c2ee1/CHANGES.md#2016-07-01-201
+ Changes of 2.0.0: https://github.com/ruby/json/blob/f679ebd0c69a94e3e70a897ac9a229f5779c2ee1/CHANGES.md#2015-09-11-200
+ Changes of 2.0.1: https://github.com/ruby/json/blob/f679ebd0c69a94e3e70a897ac9a229f5779c2ee1/CHANGES.md#2016-07-01-201
[Feature #12542][ruby-dev:49706][fix GH-1395]
Tue Jul 5 19:39:49 2016 Naohisa Goto <ngotogenome@gmail.com>
@@ -7356,7 +7356,7 @@ Thu Mar 17 11:51:48 2016 NARUSE, Yui <naruse@ruby-lang.org>
Note: CryptGenRandom function is PRNG and doesn't check its entropy,
so it won't block. [Bug #12139]
https://msdn.microsoft.com/ja-jp/library/windows/desktop/aa379942.aspx
- https://tools.ietf.org/html/rfc4086#section-7.1.3
+ https://www.rfc-editor.org/rfc/rfc4086#section-7.1.3
https://eprint.iacr.org/2007/419.pdf
http://www.cs.huji.ac.il/~dolev/pubs/thesis/msc-thesis-leo.pdf
diff --git a/doc/NEWS/NEWS-3.0.0.md b/doc/NEWS/NEWS-3.0.0.md
index bdbd47327b..9fbaf504b4 100644
--- a/doc/NEWS/NEWS-3.0.0.md
+++ b/doc/NEWS/NEWS-3.0.0.md
@@ -367,11 +367,11 @@ Outstanding ones only.
* Fiber.blocking? tells whether the current execution context is
blocking. [[Feature #16786]]
+* Thread
+
* Thread#join invokes the scheduler hooks `block`/`unblock` in a
non-blocking execution context. [[Feature #16786]]
-* Thread
-
* Thread.ignore_deadlock accessor has been added for disabling the
default deadlock detection, allowing the use of signal handlers to
break deadlock. [[Bug #13768]]
@@ -741,7 +741,7 @@ end
foo(42)
```
-```
+```console
$ typeprof test.rb
# Classes
class Object
diff --git a/doc/NEWS/NEWS-3.1.0.md b/doc/NEWS/NEWS-3.1.0.md
index fe292fc414..686003894e 100644
--- a/doc/NEWS/NEWS-3.1.0.md
+++ b/doc/NEWS/NEWS-3.1.0.md
@@ -552,7 +552,7 @@ Example: `title = json[:article][:title]`
If `json` is nil, it shows:
-```
+```console
$ ruby test.rb
test.rb:2:in `<main>': undefined method `[]' for nil:NilClass (NoMethodError)
@@ -562,7 +562,7 @@ title = json[:article][:title]
If `json[:article]` returns nil, it shows:
-```
+```console
$ ruby test.rb
test.rb:2:in `<main>': undefined method `[]' for nil:NilClass (NoMethodError)
diff --git a/doc/NEWS/NEWS-3.2.0.md b/doc/NEWS/NEWS-3.2.0.md
index 33a7b85c47..3a48c1964d 100644
--- a/doc/NEWS/NEWS-3.2.0.md
+++ b/doc/NEWS/NEWS-3.2.0.md
@@ -623,13 +623,13 @@ The following deprecated methods are removed.
Psych and fiddle supported the static build with specific version of libyaml
and libffi sources. You can build psych with libyaml-0.2.5 like this.
- ```bash
+ ```console
$ ./configure --with-libyaml-source-dir=/path/to/libyaml-0.2.5
```
And you can build fiddle with libffi-3.4.4 like this.
- ```bash
+ ```console
$ ./configure --with-libffi-source-dir=/path/to/libffi-3.4.4
```
diff --git a/doc/NEWS/NEWS-3.3.0.md b/doc/NEWS/NEWS-3.3.0.md
new file mode 100644
index 0000000000..364786d754
--- /dev/null
+++ b/doc/NEWS/NEWS-3.3.0.md
@@ -0,0 +1,529 @@
+# NEWS for Ruby 3.3.0
+
+This document is a list of user-visible feature changes
+since the **3.2.0** release, except for bug fixes.
+
+Note that each entry is kept to a minimum, see links for details.
+
+## Command line options
+
+* A new `performance` warning category was introduced.
+ They are not displayed by default even in verbose mode.
+ Turn them on with `-W:performance` or `Warning[:performance] = true`. [[Feature #19538]]
+
+* A new `RUBY_CRASH_REPORT` environment variable was introduced to allow
+ redirecting Ruby crash reports to a file or sub command. See the `BUG REPORT ENVIRONMENT`
+ section of the ruby manpage for further details. [[Feature #19790]]
+
+## Core classes updates
+
+Note: We're only listing outstanding class updates.
+
+* Array
+
+ * Array#pack now raises ArgumentError for unknown directives. [[Bug #19150]]
+
+* Dir
+
+ * Dir.for_fd added for returning a Dir object for the directory specified
+ by the provided directory file descriptor. [[Feature #19347]]
+ * Dir.fchdir added for changing the directory to the directory specified
+ by the provided directory file descriptor. [[Feature #19347]]
+ * Dir#chdir added for changing the directory to the directory specified by
+ the provided `Dir` object. [[Feature #19347]]
+
+* Encoding
+
+ * `Encoding#replicate` has been removed, it was already deprecated. [[Feature #18949]]
+
+* Fiber
+
+ * Introduce Fiber#kill. [[Bug #595]]
+
+ ```ruby
+ fiber = Fiber.new do
+ while true
+ puts "Yielding..."
+ Fiber.yield
+ end
+ ensure
+ puts "Exiting..."
+ end
+
+ fiber.resume
+ # Yielding...
+ fiber.kill
+ # Exiting...
+ ```
+
+* MatchData
+
+ * MatchData#named_captures now accepts optional `symbolize_names`
+ keyword. [[Feature #19591]]
+
+* Module
+
+ * Module#set_temporary_name added for setting a temporary name for a
+ module. [[Feature #19521]]
+
+* ObjectSpace::WeakKeyMap
+
+ * New core class to build collections with weak references.
+ The class use equality semantic to lookup keys like a regular hash,
+ but it doesn't hold strong references on the keys. [[Feature #18498]]
+
+* ObjectSpace::WeakMap
+
+ * ObjectSpace::WeakMap#delete was added to eagerly clear weak map
+ entries. [[Feature #19561]]
+
+* Proc
+ * Now Proc#dup and Proc#clone call `#initialize_dup` and `#initialize_clone`
+ hooks respectively. [[Feature #19362]]
+
+* Process
+
+ * New Process.warmup method that notify the Ruby virtual machine that the boot sequence is finished,
+ and that now is a good time to optimize the application. This is useful
+ for long-running applications. The actual optimizations performed are entirely
+ implementation-specific and may change in the future without notice. [[Feature #18885]]
+
+* Process::Status
+
+ * Process::Status#& and Process::Status#>> are deprecated. [[Bug #19868]]
+
+* Range
+
+ * Range#reverse_each can now process beginless ranges with an Integer endpoint. [[Feature #18515]]
+ * Range#reverse_each now raises TypeError for endless ranges. [[Feature #18551]]
+ * Range#overlap? added for checking if two ranges overlap. [[Feature #19839]]
+
+* Refinement
+
+ * Add Refinement#target as an alternative of Refinement#refined_class.
+ Refinement#refined_class is deprecated and will be removed in Ruby
+ 3.4. [[Feature #19714]]
+
+* Regexp
+
+ * The cache-based optimization now supports lookarounds and atomic groupings. That is, match
+ for Regexp containing these extensions can now also be performed in linear time to the length
+ of the input string. However, these cannot contain captures and cannot be nested. [[Feature #19725]]
+
+* String
+
+ * String#unpack now raises ArgumentError for unknown directives. [[Bug #19150]]
+ * String#bytesplice now accepts new arguments index/length or range of the
+ source string to be copied. [[Feature #19314]]
+
+* Thread::Queue
+
+ * Thread::Queue#freeze now raises TypeError. [[Bug #17146]]
+
+* Thread::SizedQueue
+
+ * Thread::SizedQueue#freeze now raises TypeError. [[Bug #17146]]
+
+* Time
+
+ * Time.new with a string argument became stricter. [[Bug #19293]]
+
+ ```ruby
+ Time.new('2023-12-20')
+ # no time information (ArgumentError)
+ ```
+
+* TracePoint
+
+ * TracePoint supports `rescue` event. When the raised exception was rescued,
+ the TracePoint will fire the hook. `rescue` event only supports Ruby-level
+ `rescue`. [[Feature #19572]]
+
+## Stdlib updates
+
+* RubyGems and Bundler warn if users do `require` the following gems without adding them to Gemfile or gemspec.
+ This is because they will become the bundled gems in the future version of Ruby. This warning is suppressed
+ if you use bootsnap gem. We recommend to run your application with `DISABLE_BOOTSNAP=1` environmental variable
+ at least once. This is limitation of this version.
+ [[Feature #19351]] [[Feature #19776]] [[Feature #19843]]
+ * abbrev
+ * base64
+ * bigdecimal
+ * csv
+ * drb
+ * getoptlong
+ * mutex_m
+ * nkf
+ * observer
+ * racc
+ * resolv-replace
+ * rinda
+ * syslog
+
+* Socket#recv and Socket#recv_nonblock returns `nil` instead of an empty string on closed
+ connections. Socket#recvmsg and Socket#recvmsg_nonblock returns `nil` instead of an empty packet on closed
+ connections. [[Bug #19012]]
+
+* Name resolution such as Socket.getaddrinfo, Socket.getnameinfo, Addrinfo.getaddrinfo, etc.
+ can now be interrupted. [[Feature #19965]]
+
+* Random::Formatter#alphanumeric is extended to accept optional `chars`
+ keyword argument. [[Feature #18183]]
+
+The following default gem is added.
+
+* prism 0.19.0
+
+The following default gems are updated.
+
+* RubyGems 3.5.3
+* abbrev 0.1.2
+* base64 0.2.0
+* benchmark 0.3.0
+* bigdecimal 3.1.5
+* bundler 2.5.3
+* cgi 0.4.1
+* csv 3.2.8
+* date 3.3.4
+* delegate 0.3.1
+* drb 2.2.0
+* english 0.8.0
+* erb 4.0.3
+* error_highlight 0.6.0
+* etc 1.4.3
+* fcntl 1.1.0
+* fiddle 1.1.2
+* fileutils 1.7.2
+* find 0.2.0
+* getoptlong 0.2.1
+* io-console 0.7.1
+* io-nonblock 0.3.0
+* io-wait 0.3.1
+* ipaddr 1.2.6
+* irb 1.11.0
+* json 2.7.1
+* logger 1.6.0
+* mutex_m 0.2.0
+* net-http 0.4.0
+* net-protocol 0.2.2
+* nkf 0.1.3
+* observer 0.1.2
+* open-uri 0.4.1
+* open3 0.2.1
+* openssl 3.2.0
+* optparse 0.4.0
+* ostruct 0.6.0
+* pathname 0.3.0
+* pp 0.5.0
+* prettyprint 0.2.0
+* pstore 0.1.3
+* psych 5.1.2
+* rdoc 6.6.2
+* readline 0.0.4
+* reline 0.4.1
+* resolv 0.3.0
+* rinda 0.2.0
+* securerandom 0.3.1
+* set 1.1.0
+* shellwords 0.2.0
+* singleton 0.2.0
+* stringio 3.1.0
+* strscan 3.0.7
+* syntax_suggest 2.0.0
+* syslog 0.1.2
+* tempfile 0.2.1
+* time 0.3.0
+* timeout 0.4.1
+* tmpdir 0.2.0
+* tsort 0.2.0
+* un 0.3.0
+* uri 0.13.0
+* weakref 0.1.3
+* win32ole 1.8.10
+* yaml 0.3.0
+* zlib 3.1.0
+
+The following bundled gem is promoted from default gems.
+
+* racc 1.7.3
+
+The following bundled gems are updated.
+
+* minitest 5.20.0
+* rake 13.1.0
+* test-unit 3.6.1
+* rexml 3.2.6
+* rss 0.3.0
+* net-ftp 0.3.3
+* net-imap 0.4.9
+* net-smtp 0.4.0
+* rbs 3.4.0
+* typeprof 0.21.9
+* debug 1.9.1
+
+See GitHub releases like [Logger](https://github.com/ruby/logger/releases) or
+changelog for details of the default gems or bundled gems.
+
+### Prism
+
+* Introduced [the Prism parser](https://github.com/ruby/prism) as a default gem
+ * Prism is a portable, error tolerant, and maintainable recursive descent parser for the Ruby language
+* Prism is production ready and actively maintained, you can use it in place of Ripper
+ * There is [extensive documentation](https://ruby.github.io/prism/) on how to use Prism
+ * Prism is both a C library that will be used internally by CRuby and a Ruby gem that can be used by any tooling which needs to parse Ruby code
+ * Notable methods in the Prism API are:
+ * `Prism.parse(source)` which returns the AST as part of a parse result object
+ * `Prism.parse_comments(source)` which returns the comments
+ * `Prism.parse_success?(source)` which returns true if there are no errors
+* You can make pull requests or issues directly on [the Prism repository](https://github.com/ruby/prism) if you are interested in contributing
+* You can now use `ruby --parser=prism` or `RUBYOPT="--parser=prism"` to experiment with the Prism compiler. Please note that this flag is for debugging only.
+
+## Compatibility issues
+
+* Subprocess creation/forking via the following file open methods is deprecated. [[Feature #19630]]
+ * Kernel#open
+ * URI.open
+ * IO.binread
+ * IO.foreach
+ * IO.readlines
+ * IO.read
+ * IO.write
+
+* When given a non-lambda, non-literal block, Kernel#lambda with now raises
+ ArgumentError instead of returning it unmodified. These usages have been
+ issuing warnings under the `Warning[:deprecated]` category since Ruby 3.0.0.
+ [[Feature #19777]]
+
+* The `RUBY_GC_HEAP_INIT_SLOTS` environment variable has been deprecated and
+ removed. Environment variables `RUBY_GC_HEAP_%d_INIT_SLOTS` should be
+ used instead. [[Feature #19785]]
+
+* `it` calls without arguments in a block with no ordinary parameters are
+ deprecated. `it` will be a reference to the first block parameter in Ruby 3.4.
+ [[Feature #18980]]
+
+* Error message for NoMethodError have changed to not use the target object's `#inspect`
+ for efficiency, and says "instance of ClassName" instead. [[Feature #18285]]
+
+ ```ruby
+ ([1] * 100).nonexisting
+ # undefined method `nonexisting' for an instance of Array (NoMethodError)
+ ```
+
+* Now anonymous parameters forwarding is disallowed inside a block
+ that uses anonymous parameters. [[Feature #19370]]
+
+## Stdlib compatibility issues
+
+* `racc` is promoted to bundled gems.
+ * You need to add `racc` to your `Gemfile` if you use `racc` under bundler environment.
+* `ext/readline` is retired
+ * We have `reline` that is pure Ruby implementation compatible with `ext/readline` API.
+ We rely on `reline` in the future. If you need to use `ext/readline`, you can install
+ `ext/readline` via rubygems.org with `gem install readline-ext`.
+ * We no longer need to install libraries like `libreadline` or `libedit`.
+
+## C API updates
+
+* `rb_postponed_job` updates
+ * New APIs and deprecated APIs (see comments for details)
+ * added: `rb_postponed_job_preregister()`
+ * added: `rb_postponed_job_trigger()`
+ * deprecated: `rb_postponed_job_register()` (and semantic change. see below)
+ * deprecated: `rb_postponed_job_register_one()`
+ * The postponed job APIs have been changed to address some rare crashes.
+ To solve the issue, we introduced new two APIs and deprecated current APIs.
+ The semantics of these functions have also changed slightly; `rb_postponed_job_register`
+ now behaves like the `once` variant in that multiple calls with the same
+ `func` might be coalesced into a single execution of the `func`
+ [[Feature #20057]]
+
+* Some updates for internal thread event hook APIs
+ * `rb_internal_thread_event_data_t` with a target Ruby thread (VALUE)
+ and callback functions (`rb_internal_thread_event_callback`) receive it.
+ https://github.com/ruby/ruby/pull/8885
+ * The following functions are introduced to manipulate Ruby thread local data
+ from internal thread event hook APIs (they are introduced since Ruby 3.2).
+ https://github.com/ruby/ruby/pull/8936
+ * `rb_internal_thread_specific_key_create()`
+ * `rb_internal_thread_specific_get()`
+ * `rb_internal_thread_specific_set()`
+
+* `rb_profile_thread_frames()` is introduced to get a frames from
+ a specific thread.
+ [[Feature #10602]]
+
+* `rb_data_define()` is introduced to define `Data`. [[Feature #19757]]
+
+* `rb_ext_resolve_symbol()` is introduced to search a function from
+ extension libraries. [[Feature #20005]]
+
+* IO related updates:
+ * The details of `rb_io_t` will be hidden and deprecated attributes
+ are added for each members. [[Feature #19057]]
+ * `rb_io_path(VALUE io)` is introduced to get a path of `io`.
+ * `rb_io_closed_p(VALUE io)` to get opening or closing of `io`.
+ * `rb_io_mode(VALUE io)` to get the mode of `io`.
+ * `rb_io_open_descriptor()` is introduced to make an IO object from a file
+ descriptor.
+
+## Implementation improvements
+
+### Parser
+
+* Replace Bison with [Lrama LALR parser generator](https://github.com/ruby/lrama).
+ No need to install Bison to build Ruby from source code anymore.
+ We will no longer suffer bison compatibility issues and we can use new features by just implementing it to Lrama. [[Feature #19637]]
+ * See [The future vision of Ruby Parser](https://rubykaigi.org/2023/presentations/spikeolaf.html) for detail.
+ * Lrama internal parser is a LR parser generated by Racc for maintainability.
+ * Parameterizing Rules `(?, *, +)` are supported, it will be used in Ruby parse.y.
+
+### GC / Memory management
+
+* Major performance improvements over Ruby 3.2
+ * Young objects referenced by old objects are no longer immediately
+ promoted to the old generation. This significantly reduces the frequency of
+ major GC collections. [[Feature #19678]]
+ * A new `REMEMBERED_WB_UNPROTECTED_OBJECTS_LIMIT_RATIO` tuning variable was
+ introduced to control the number of unprotected objects cause a major GC
+ collection to trigger. The default is set to `0.01` (1%). This significantly
+ reduces the frequency of major GC collection. [[Feature #19571]]
+ * Write Barriers were implemented for many core types that were missing them,
+ notably `Time`, `Enumerator`, `MatchData`, `Method`, `File::Stat`, `BigDecimal`
+ and several others. This significantly reduces minor GC collection time and major
+ GC collection frequency.
+ * Most core classes are now using Variable Width Allocation, notably `Hash`, `Time`,
+ `Thread::Backtrace`, `Thread::Backtrace::Location`, `File::Stat`, `Method`.
+ This makes these classes faster to allocate and free, use less memory and reduce
+ heap fragmentation.
+* `defined?(@ivar)` is optimized with Object Shapes.
+
+### YJIT
+
+* Major performance improvements over Ruby 3.2
+ * Support for splat and rest arguments has been improved.
+ * Registers are allocated for stack operations of the virtual machine.
+ * More calls with optional arguments are compiled. Exception handlers are also compiled.
+ * Unsupported call types and megamorphic call sites no longer exit to the interpreter.
+ * Basic methods like Rails `#blank?` and
+ [specialized `#present?`](https://github.com/rails/rails/pull/49909) are inlined.
+ * `Integer#*`, `Integer#!=`, `String#!=`, `String#getbyte`,
+ `Kernel#block_given?`, `Kernel#is_a?`, `Kernel#instance_of?`, and `Module#===`
+ are specially optimized.
+ * Compilation speed is now slightly faster than Ruby 3.2.
+ * Now more than 3x faster than the interpreter on Optcarrot!
+* Significantly improved memory usage over Ruby 3.2
+ * Metadata for compiled code uses a lot less memory.
+ * `--yjit-call-threshold` is automatically raised from 30 to 120
+ when the application has more than 40,000 ISEQs.
+ * `--yjit-cold-threshold` is added to skip compiling cold ISEQs.
+ * More compact code is generated on Arm64.
+* Code GC is now disabled by default
+ * `--yjit-exec-mem-size` is treated as a hard limit where compilation of new code stops.
+ * No sudden drops in performance due to code GC.
+ Better copy-on-write behavior on servers reforking with
+ [Pitchfork](https://github.com/shopify/pitchfork).
+ * You can still enable code GC if desired with `--yjit-code-gc`
+* Add `RubyVM::YJIT.enable` that can enable YJIT at run-time
+ * You can start YJIT without modifying command-line arguments or environment variables.
+ Rails 7.2 will [enable YJIT by default](https://github.com/rails/rails/pull/49947)
+ using this method.
+ * This can also be used to enable YJIT only once your application is
+ done booting. `--yjit-disable` can be used if you want to use other
+ YJIT options while disabling YJIT at boot.
+* More YJIT stats are available by default
+ * `yjit_alloc_size` and several more metadata-related stats are now available by default.
+ * `ratio_in_yjit` stat produced by `--yjit-stats` is now available in release builds,
+ a special stats or dev build is no longer required to access most stats.
+* Add more profiling capabilities
+ * `--yjit-perf` is added to facilitate profiling with Linux perf.
+ * `--yjit-trace-exits` now supports sampling with `--yjit-trace-exits-sample-rate=N`
+* More thorough testing and multiple bug fixes
+* `--yjit-stats=quiet` is added to avoid printing stats on exit.
+
+### MJIT
+
+* MJIT is removed.
+ * `--disable-jit-support` is removed. Consider using `--disable-yjit --disable-rjit` instead.
+
+### RJIT
+
+* Introduced a pure-Ruby JIT compiler RJIT.
+ * RJIT supports only x86\_64 architecture on Unix platforms.
+ * Unlike MJIT, it doesn't require a C compiler at runtime.
+* RJIT exists only for experimental purposes.
+ * You should keep using YJIT in production.
+
+### M:N Thread scheduler
+
+* M:N Thread scheduler is introduced. [[Feature #19842]]
+ * Background: Ruby 1.8 and before, M:1 thread scheduler (M Ruby threads
+ with 1 native thread. Called as User level threads or Green threads)
+ is used. Ruby 1.9 and later, 1:1 thread scheduler (1 Ruby thread with
+ 1 native thread). M:1 threads takes lower resources compare with 1:1
+ threads because it needs only 1 native threads. However it is difficult
+ to support context switching for all of blocking operation so 1:1
+ threads are employed from Ruby 1.9. M:N thread scheduler uses N native
+ threads for M Ruby threads (N is small number in general). It doesn't
+ need same number of native threads as Ruby threads (similar to the M:1
+ thread scheduler). Also our M:N threads supports blocking operations
+ well same as 1:1 threads. See the ticket for more details.
+ Our M:N thread scheduler refers on the goroutine scheduler in the
+ Go language.
+ * In a ractor, only 1 thread can run in a same time because of
+ implementation. Therefore, applications that use only one Ractor
+ (most applications) M:N thread scheduler works as M:1 thread scheduler
+ with further extension from Ruby 1.8.
+ * M:N thread scheduler can introduce incompatibility for C-extensions,
+ so it is disabled by default on the main Ractors.
+ `RUBY_MN_THREADS=1` environment variable will enable it.
+ On non-main Ractors, M:N thread scheduler is enabled (and can not
+ disable it now).
+ * `N` (the number of native threads) can be specified with `RUBY_MAX_CPU`
+ environment variable. The default is 8.
+ Note that more than `N` native threads are used to support many kind of
+ blocking operations.
+
+[Bug #595]: https://bugs.ruby-lang.org/issues/595
+[Feature #10602]: https://bugs.ruby-lang.org/issues/10602
+[Bug #17146]: https://bugs.ruby-lang.org/issues/17146
+[Feature #18183]: https://bugs.ruby-lang.org/issues/18183
+[Feature #18285]: https://bugs.ruby-lang.org/issues/18285
+[Feature #18498]: https://bugs.ruby-lang.org/issues/18498
+[Feature #18515]: https://bugs.ruby-lang.org/issues/18515
+[Feature #18551]: https://bugs.ruby-lang.org/issues/18551
+[Feature #18885]: https://bugs.ruby-lang.org/issues/18885
+[Feature #18949]: https://bugs.ruby-lang.org/issues/18949
+[Feature #18980]: https://bugs.ruby-lang.org/issues/18980
+[Bug #19012]: https://bugs.ruby-lang.org/issues/19012
+[Feature #19057]: https://bugs.ruby-lang.org/issues/19057
+[Bug #19150]: https://bugs.ruby-lang.org/issues/19150
+[Bug #19293]: https://bugs.ruby-lang.org/issues/19293
+[Feature #19314]: https://bugs.ruby-lang.org/issues/19314
+[Feature #19347]: https://bugs.ruby-lang.org/issues/19347
+[Feature #19351]: https://bugs.ruby-lang.org/issues/19351
+[Feature #19362]: https://bugs.ruby-lang.org/issues/19362
+[Feature #19370]: https://bugs.ruby-lang.org/issues/19370
+[Feature #19521]: https://bugs.ruby-lang.org/issues/19521
+[Feature #19538]: https://bugs.ruby-lang.org/issues/19538
+[Feature #19561]: https://bugs.ruby-lang.org/issues/19561
+[Feature #19571]: https://bugs.ruby-lang.org/issues/19571
+[Feature #19572]: https://bugs.ruby-lang.org/issues/19572
+[Feature #19591]: https://bugs.ruby-lang.org/issues/19591
+[Feature #19630]: https://bugs.ruby-lang.org/issues/19630
+[Feature #19637]: https://bugs.ruby-lang.org/issues/19637
+[Feature #19678]: https://bugs.ruby-lang.org/issues/19678
+[Feature #19714]: https://bugs.ruby-lang.org/issues/19714
+[Feature #19725]: https://bugs.ruby-lang.org/issues/19725
+[Feature #19757]: https://bugs.ruby-lang.org/issues/19757
+[Feature #19776]: https://bugs.ruby-lang.org/issues/19776
+[Feature #19777]: https://bugs.ruby-lang.org/issues/19777
+[Feature #19785]: https://bugs.ruby-lang.org/issues/19785
+[Feature #19790]: https://bugs.ruby-lang.org/issues/19790
+[Feature #19839]: https://bugs.ruby-lang.org/issues/19839
+[Feature #19842]: https://bugs.ruby-lang.org/issues/19842
+[Feature #19843]: https://bugs.ruby-lang.org/issues/19843
+[Bug #19868]: https://bugs.ruby-lang.org/issues/19868
+[Feature #19965]: https://bugs.ruby-lang.org/issues/19965
+[Feature #20005]: https://bugs.ruby-lang.org/issues/20005
+[Feature #20057]: https://bugs.ruby-lang.org/issues/20057
diff --git a/doc/NEWS/NEWS-3.4.0.md b/doc/NEWS/NEWS-3.4.0.md
new file mode 100644
index 0000000000..e9cc3a9569
--- /dev/null
+++ b/doc/NEWS/NEWS-3.4.0.md
@@ -0,0 +1,962 @@
+# NEWS for Ruby 3.4.0
+
+This document is a list of user-visible feature changes
+since the **3.3.0** release, except for bug fixes.
+
+Note that each entry is kept to a minimum, see links for details.
+
+## Language changes
+
+* `it` is added to reference a block parameter. [[Feature #18980]]
+
+* String literals in files without a `frozen_string_literal` comment now emit a deprecation warning
+ when they are mutated.
+ These warnings can be enabled with `-W:deprecated` or by setting `Warning[:deprecated] = true`.
+ To disable this change, you can run Ruby with the `--disable-frozen-string-literal`
+ command line argument. [[Feature #20205]]
+
+ * `String#+@` now duplicates when mutating the string would emit
+ a deprecation warning, offered as a replacement for the
+ `str.dup if str.frozen?` pattern.
+
+* Keyword splatting `nil` when calling methods is now supported.
+ `**nil` is treated similarly to `**{}`, passing no keywords,
+ and not calling any conversion methods. [[Bug #20064]]
+
+* Block passing is no longer allowed in index assignment
+ (e.g. `a[0, &b] = 1`). [[Bug #19918]]
+
+* Keyword arguments are no longer allowed in index assignment
+ (e.g. `a[0, kw: 1] = 2`). [[Bug #20218]]
+
+* The toplevel name `::Ruby` is reserved now, and the definition will be warned
+ when `Warning[:deprecated]`. [[Feature #20884]]
+
+## Core classes updates
+
+Note: We're only listing outstanding class updates.
+
+
+* Array
+
+ * `Array#fetch_values` was added. [[Feature #20702]]
+
+* Exception
+
+ * `Exception#set_backtrace` now accepts arrays of `Thread::Backtrace::Location`.
+ `Kernel#raise`, `Thread#raise` and `Fiber#raise` also accept this new format. [[Feature #13557]]
+
+* Fiber::Scheduler
+
+ * An optional `Fiber::Scheduler#blocking_operation_wait` hook allows blocking operations to be moved out of the
+ event loop in order to reduce latency and improve multi-core processor utilization. [[Feature #20876]]
+
+* GC
+
+ * `GC.config` added to allow setting configuration variables on the Garbage
+ Collector. [[Feature #20443]]
+
+ * GC configuration parameter `rgengc_allow_full_mark` introduced. When `false`
+ GC will only mark young objects. Default is `true`. [[Feature #20443]]
+
+* Hash
+
+ * `Hash.new` now accepts an optional `capacity:` argument, to preallocate the hash with a given capacity.
+ This can improve performance when building large hashes incrementally by saving on reallocation and
+ rehashing of keys. [[Feature #19236]]
+
+* IO::Buffer
+
+ * `IO::Buffer#copy` can release the GVL, allowing other threads to run while copying data. [[Feature #20902]]
+
+* Integer
+
+ * `Integer#**` used to return `Float::INFINITY` when the return value is large, but now returns an `Integer`.
+ If the return value is extremely large, it raises an exception.
+ [[Feature #20811]]
+
+* MatchData
+
+ * `MatchData#bytebegin` and `MatchData#byteend` have been added. [[Feature #20576]]
+
+* Object
+
+ * `Object#singleton_method` now returns methods in modules prepended to or included in the
+ receiver's singleton class. [[Bug #20620]]
+
+ ```rb
+ o = Object.new
+ o.extend(Module.new{def a = 1})
+ o.singleton_method(:a).call #=> 1
+ ```
+
+* Ractor
+
+ * `require` in Ractor is allowed. The requiring process will be run on
+ the main Ractor.
+ `Ractor._require(feature)` is added to run requiring process on the
+ main Ractor.
+ [[Feature #20627]]
+
+ * `Ractor.main?` is added. [[Feature #20627]]
+
+ * `Ractor.[]` and `Ractor.[]=` are added to access the ractor local storage
+ of the current Ractor. [[Feature #20715]]
+
+ * `Ractor.store_if_absent(key){ init }` is added to initialize ractor local
+ variables in thread-safety. [[Feature #20875]]
+
+* Range
+
+ * `Range#size` now raises `TypeError` if the range is not iterable. [[Misc #18984]]
+ * `Range#step` now consistently has a semantics of iterating by using `+` operator
+ for all types, not only numerics. [[Feature #18368]]
+
+ ```ruby
+ (Time.utc(2022, 2, 24)..).step(24*60*60).take(3)
+ #=> [2022-02-24 00:00:00 UTC, 2022-02-25 00:00:00 UTC, 2022-02-26 00:00:00 UTC]
+ ```
+
+* Rational
+
+ * `Rational#**` used to return `Float::INFINITY` or `Float::NAN`
+ when the numerator of the return value is large, but now returns an `Rational`.
+ If it is extremely large, it raises an exception. [[Feature #20811]]
+
+* RubyVM::AbstractSyntaxTree
+
+ * Add `RubyVM::AbstractSyntaxTree::Node#locations` method which returns location objects
+ associated with the AST node. [[Feature #20624]]
+ * Add `RubyVM::AbstractSyntaxTree::Location` class which holds location information. [[Feature #20624]]
+
+
+* String
+
+ * `String#append_as_bytes` was added to more easily and efficiently work with binary buffers and protocols.
+ It directly concatenate the arguments into the string without any encoding validation or conversion.
+ [[Feature #20594]]
+
+* Symbol
+
+ * The string returned by `Symbol#to_s` now emits a deprecation warning when mutated, and will be
+ frozen in a future version of Ruby.
+ These warnings can be enabled with `-W:deprecated` or by setting `Warning[:deprecated] = true`.
+ [[Feature #20350]]
+
+* Time
+
+ * On Windows, now `Time#zone` encodes the system timezone name in UTF-8
+ instead of the active code page, if it contains non-ASCII characters.
+ [[Bug #20929]]
+
+ * `Time#xmlschema`, and its `Time#iso8601` alias have been moved into the core Time
+ class while previously it was an extension provided by the `time` gem. [[Feature #20707]]
+
+* Warning
+
+ * Add `Warning.categories` method which returns a list of possible warning categories.
+ [[Feature #20293]]
+
+## Stdlib updates
+
+We only list stdlib changes that are notable feature changes.
+
+* RubyGems
+
+ * Add `--attestation` option to gem push. It enabled to store signature of build artifact to sigstore.dev.
+
+* Bundler
+
+ * Add a `lockfile_checksums` configuration to include checksums in fresh lockfiles.
+ * Add bundle lock `--add-checksums` to add checksums to an existing lockfile.
+
+* JSON
+
+ * Performance improvements `JSON.parse` about 1.5 times faster than json-2.7.x.
+
+* Tempfile
+
+ * The keyword argument `anonymous: true` is implemented for Tempfile.create.
+ `Tempfile.create(anonymous: true)` removes the created temporary file immediately.
+ So applications don't need to remove the file.
+ [[Feature #20497]]
+
+* win32/sspi.rb
+
+ * This library is now extracted from the Ruby repository to [ruby/net-http-sspi].
+ [[Feature #20775]]
+
+* Socket
+
+ * `Socket::ResolutionError` and `Socket::ResolutionError#error_code` was added.
+ [[Feature #20018]]
+
+* IRB
+
+ * Interactive method completion is now improved with type information by default.
+ [[Feature #20778]]
+
+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 releases.
+
+The following default gem is added.
+
+* win32-registry 0.1.0
+
+The following default gems are updated.
+
+* RubyGems 3.6.2
+* benchmark 0.4.0
+* bundler 2.6.2
+* date 3.4.1
+* delegate 0.4.0
+* did_you_mean 2.0.0
+* digest 3.2.0
+* erb 4.0.4
+* error_highlight 0.7.0
+* etc 1.4.5
+* fcntl 1.2.0
+* fiddle 1.1.6
+* fileutils 1.7.3
+* io-console 0.8.0
+* io-nonblock 0.3.1
+* ipaddr 1.2.7
+* irb 1.14.3
+* json 2.9.1
+* logger 1.6.4
+* net-http 0.6.0
+* open-uri 0.5.0
+* openssl 3.3.0
+* optparse 0.6.0
+* ostruct 0.6.1
+* pathname 0.4.0
+* pp 0.6.2
+* prism 1.2.0
+* pstore 0.1.4
+* psych 5.2.2
+* rdoc 6.10.0
+* reline 0.6.0
+* resolv 0.6.0
+* securerandom 0.4.1
+* set 1.1.1
+* shellwords 0.2.2
+* singleton 0.3.0
+* stringio 3.1.2
+* strscan 3.1.2
+* syntax_suggest 2.0.2
+* tempfile 0.3.1
+* time 0.4.1
+* timeout 0.4.3
+* tmpdir 0.3.1
+* uri 1.0.2
+* win32ole 1.9.1
+* yaml 0.4.0
+* zlib 3.2.1
+
+ * 3.5.3 to [v3.5.4][RubyGems-v3.5.4], [v3.5.5][RubyGems-v3.5.5], [v3.5.6][RubyGems-v3.5.6], [v3.5.7][RubyGems-v3.5.7], [v3.5.8][RubyGems-v3.5.8], [v3.5.9][RubyGems-v3.5.9], [v3.5.10][RubyGems-v3.5.10], [v3.5.11][RubyGems-v3.5.11], [v3.5.12][RubyGems-v3.5.12], [v3.5.13][RubyGems-v3.5.13], [v3.5.14][RubyGems-v3.5.14], [v3.5.15][RubyGems-v3.5.15], [v3.5.16][RubyGems-v3.5.16], [v3.5.17][RubyGems-v3.5.17], [v3.5.18][RubyGems-v3.5.18], [v3.5.19][RubyGems-v3.5.19], [v3.5.20][RubyGems-v3.5.20], [v3.5.21][RubyGems-v3.5.21], [v3.5.22][RubyGems-v3.5.22], [v3.5.23][RubyGems-v3.5.23], [v3.6.0][RubyGems-v3.6.0], [v3.6.1][RubyGems-v3.6.1], [v3.6.2][RubyGems-v3.6.2]
+* [benchmark][benchmark] 0.4.0
+ * 0.3.0 to [v0.4.0][benchmark-v0.4.0]
+* [bundler][bundler] 2.6.2
+ * 2.5.3 to [v2.5.4][bundler-v2.5.4], [v2.5.5][bundler-v2.5.5], [v2.5.6][bundler-v2.5.6], [v2.5.7][bundler-v2.5.7], [v2.5.8][bundler-v2.5.8], [v2.5.9][bundler-v2.5.9], [v2.5.10][bundler-v2.5.10], [v2.5.11][bundler-v2.5.11], [v2.5.12][bundler-v2.5.12], [v2.5.13][bundler-v2.5.13], [v2.5.14][bundler-v2.5.14], [v2.5.15][bundler-v2.5.15], [v2.5.16][bundler-v2.5.16], [v2.5.17][bundler-v2.5.17], [v2.5.18][bundler-v2.5.18], [v2.5.19][bundler-v2.5.19], [v2.5.20][bundler-v2.5.20], [v2.5.21][bundler-v2.5.21], [v2.5.22][bundler-v2.5.22], [v2.5.23][bundler-v2.5.23], [v2.6.0][bundler-v2.6.0], [v2.6.1][bundler-v2.6.1], [v2.6.2][bundler-v2.6.2]
+* [date][date] 3.4.1
+ * 3.3.4 to [v3.4.0][date-v3.4.0], [v3.4.1][date-v3.4.1]
+* [delegate][delegate] 0.4.0
+ * 0.3.1 to [v0.4.0][delegate-v0.4.0]
+* [did_you_mean][did_you_mean] 2.0.0
+ * 1.6.3 to [v2.0.0][did_you_mean-v2.0.0]
+* [digest][digest] 3.2.0
+ * 3.1.1 to [v3.2.0.pre0][digest-v3.2.0.pre0], [v3.2.0][digest-v3.2.0]
+* [erb][erb] 4.0.4
+ * 4.0.3 to [v4.0.4][erb-v4.0.4]
+* [error_highlight][error_highlight] 0.7.0
+ * 0.6.0 to [v0.7.0][error_highlight-v0.7.0]
+* [etc][etc] 1.4.5
+ * 1.4.3 to [v1.4.4][etc-v1.4.4], [v1.4.5][etc-v1.4.5]
+* [fcntl][fcntl] 1.2.0
+ * 1.1.0 to [v1.2.0][fcntl-v1.2.0]
+* [fiddle][fiddle] 1.1.6
+ * 1.1.2 to [v1.1.3][fiddle-v1.1.3], [v1.1.4][fiddle-v1.1.4], [v1.1.5][fiddle-v1.1.5], [v1.1.6][fiddle-v1.1.6]
+* [fileutils][fileutils] 1.7.3
+ * 1.7.2 to [v1.7.3][fileutils-v1.7.3]
+* [io-console][io-console] 0.8.0
+ * 0.7.1 to [v0.7.2][io-console-v0.7.2], [v0.8.0.beta1][io-console-v0.8.0.beta1], [v0.8.0][io-console-v0.8.0]
+* [io-nonblock][io-nonblock] 0.3.1
+ * 0.3.0 to [v0.3.1][io-nonblock-v0.3.1]
+* [ipaddr][ipaddr] 1.2.7
+ * 1.2.6 to [v1.2.7][ipaddr-v1.2.7]
+* [irb][irb] 1.14.3
+ * 1.11.0 to [v1.11.1][irb-v1.11.1], [v1.11.2][irb-v1.11.2], [v1.12.0][irb-v1.12.0], [v1.13.0][irb-v1.13.0], [v1.13.1][irb-v1.13.1], [v1.13.2][irb-v1.13.2], [v1.14.0][irb-v1.14.0], [v1.14.1][irb-v1.14.1], [v1.14.2][irb-v1.14.2], [v1.14.3][irb-v1.14.3]
+* [json][json] 2.9.1
+ * 2.7.1 to [v2.7.2][json-v2.7.2], [v2.7.3.rc1][json-v2.7.3.rc1], [v2.7.3][json-v2.7.3], [v2.7.4][json-v2.7.4], [v2.7.5][json-v2.7.5], [v2.7.6][json-v2.7.6], [v2.8.0][json-v2.8.0], [v2.8.1][json-v2.8.1], [v2.8.2][json-v2.8.2], [v2.9.0][json-v2.9.0], [v2.9.1][json-v2.9.1]
+* [logger][logger] 1.6.4
+ * 1.6.0 to [v1.6.1][logger-v1.6.1], [v1.6.2][logger-v1.6.2], [v1.6.3][logger-v1.6.3], [v1.6.4][logger-v1.6.4]
+* [net-http][net-http] 0.6.0
+ * 0.4.0 to [v0.4.1][net-http-v0.4.1], [v0.5.0][net-http-v0.5.0], [v0.6.0][net-http-v0.6.0]
+* [open-uri][open-uri] 0.5.0
+ * 0.4.1 to [v0.5.0][open-uri-v0.5.0]
+* [optparse][optparse] 0.6.0
+ * 0.4.0 to [v0.5.0][optparse-v0.5.0], [v0.6.0][optparse-v0.6.0]
+* [ostruct][ostruct] 0.6.1
+ * 0.6.0 to [v0.6.1][ostruct-v0.6.1]
+* [pathname][pathname] 0.4.0
+ * 0.3.0 to [v0.4.0][pathname-v0.4.0]
+* [pp][pp] 0.6.2
+ * 0.5.0 to [v0.6.0][pp-v0.6.0], [v0.6.1][pp-v0.6.1], [v0.6.2][pp-v0.6.2]
+* [prism][prism] 1.2.0
+ * 0.19.0 to [v0.20.0][prism-v0.20.0], [v0.21.0][prism-v0.21.0], [v0.22.0][prism-v0.22.0], [v0.23.0][prism-v0.23.0], [v0.24.0][prism-v0.24.0], [v0.25.0][prism-v0.25.0], [v0.26.0][prism-v0.26.0], [v0.27.0][prism-v0.27.0], [v0.28.0][prism-v0.28.0], [v0.29.0][prism-v0.29.0], [v0.30.0][prism-v0.30.0], [v1.0.0][prism-v1.0.0], [v1.1.0][prism-v1.1.0], [v1.2.0][prism-v1.2.0]
+* [pstore][pstore] 0.1.4
+ * 0.1.3 to [v0.1.4][pstore-v0.1.4]
+* [psych][psych] 5.2.2
+ * 5.1.2 to [v5.2.0.beta1][psych-v5.2.0.beta1], [v5.2.0.beta2][psych-v5.2.0.beta2], [v5.2.0.beta3][psych-v5.2.0.beta3], [v5.2.0.beta4][psych-v5.2.0.beta4], [v5.2.0.beta5][psych-v5.2.0.beta5], [v5.2.0.beta6][psych-v5.2.0.beta6], [v5.2.0.beta7][psych-v5.2.0.beta7], [v5.2.0][psych-v5.2.0], [v5.2.1][psych-v5.2.1], [v5.2.2][psych-v5.2.2]
+* [rdoc][rdoc] 6.10.0
+ * 6.6.2 to [v6.7.0][rdoc-v6.7.0], [v6.8.0][rdoc-v6.8.0], [v6.8.1][rdoc-v6.8.1], [v6.9.0][rdoc-v6.9.0], [v6.9.1][rdoc-v6.9.1], [v6.10.0][rdoc-v6.10.0]
+* [reline][reline] 0.6.0
+ * 0.4.1 to [v0.4.2][reline-v0.4.2], [v0.4.3][reline-v0.4.3], [v0.5.0.pre.1][reline-v0.5.0.pre.1], [v0.5.0][reline-v0.5.0], [v0.5.1][reline-v0.5.1], [v0.5.2][reline-v0.5.2], [v0.5.3][reline-v0.5.3], [v0.5.4][reline-v0.5.4], [v0.5.5][reline-v0.5.5], [v0.5.6][reline-v0.5.6], [v0.5.7][reline-v0.5.7], [v0.5.8][reline-v0.5.8], [v0.5.9][reline-v0.5.9], [v0.5.10][reline-v0.5.10], [v0.5.11][reline-v0.5.11], [v0.5.12][reline-v0.5.12], [v0.6.0][reline-v0.6.0]
+* [resolv][resolv] 0.6.0
+ * 0.3.0 to [v0.4.0][resolv-v0.4.0], [v0.5.0][resolv-v0.5.0], [v0.6.0][resolv-v0.6.0]
+* [securerandom][securerandom] 0.4.1
+ * 0.3.1 to [v0.3.2][securerandom-v0.3.2], [v0.4.0][securerandom-v0.4.0], [v0.4.1][securerandom-v0.4.1]
+* [set][set] 1.1.1
+ * 1.1.0 to [v1.1.1][set-v1.1.1]
+* [shellwords][shellwords] 0.2.2
+ * 0.2.0 to [v0.2.1][shellwords-v0.2.1], [v0.2.2][shellwords-v0.2.2]
+* [singleton][singleton] 0.3.0
+ * 0.2.0 to [v0.3.0][singleton-v0.3.0]
+* [stringio][stringio] 3.1.2
+ * 3.1.0 to [v3.1.1][stringio-v3.1.1], [v3.1.2][stringio-v3.1.2]
+* [strscan][strscan] 3.1.2
+ * 3.0.7 to [v3.0.8][strscan-v3.0.8], [v3.0.9][strscan-v3.0.9], [v3.1.0][strscan-v3.1.0], [v3.1.1][strscan-v3.1.1], [v3.1.2][strscan-v3.1.2]
+* [syntax_suggest][syntax_suggest] 2.0.2
+ * 2.0.0 to [v2.0.1][syntax_suggest-v2.0.1], [v2.0.2][syntax_suggest-v2.0.2]
+* [tempfile][tempfile] 0.3.1
+ * 0.2.1 to [v0.3.0][tempfile-v0.3.0], [v0.3.1][tempfile-v0.3.1]
+* [time][time] 0.4.1
+ * 0.3.0 to [v0.4.0][time-v0.4.0], [v0.4.1][time-v0.4.1]
+* [timeout][timeout] 0.4.3
+ * 0.4.1 to [v0.4.2][timeout-v0.4.2], [v0.4.3][timeout-v0.4.3]
+* [tmpdir][tmpdir] 0.3.1
+ * 0.2.0 to [v0.3.0][tmpdir-v0.3.0], [v0.3.1][tmpdir-v0.3.1]
+* [uri][uri] 1.0.2
+ * 0.13.0 to [v0.13.1][uri-v0.13.1], [v1.0.0][uri-v1.0.0], [v1.0.1][uri-v1.0.1], [v1.0.2][uri-v1.0.2]
+* [win32ole][win32ole] 1.9.1
+ * 1.8.10 to [v1.9.0][win32ole-v1.9.0], [v1.9.1][win32ole-v1.9.1]
+* [yaml][yaml] 0.4.0
+ * 0.3.0 to [v0.4.0][yaml-v0.4.0]
+* [zlib][zlib] 3.2.1
+ * 3.1.0 to [v3.1.1][zlib-v3.1.1], [v3.2.0][zlib-v3.2.0], [v3.2.1][zlib-v3.2.1]
+
+The following bundled gem is added.
+
+* [repl_type_completor][repl_type_completor] 0.1.9
+
+The following bundled gems are updated.
+
+* [minitest][minitest] 5.25.4
+ * 5.20.0 to [v5.25.4][minitest-v5.25.4]
+* [power_assert][power_assert] 2.0.5
+ * 2.0.3 to [v2.0.4][power_assert-v2.0.4], [v2.0.5][power_assert-v2.0.5]
+* [rake][rake] 13.2.1
+ * 13.1.0 to [v13.2.0][rake-v13.2.0], [v13.2.1][rake-v13.2.1]
+* [test-unit][test-unit] 3.6.7
+ * 3.6.1 to [3.6.2][test-unit-3.6.2], [3.6.3][test-unit-3.6.3], [3.6.4][test-unit-3.6.4], [3.6.5][test-unit-3.6.5], [3.6.6][test-unit-3.6.6], [3.6.7][test-unit-3.6.7]
+* [rexml][rexml] 3.4.0
+ * 3.2.6 to [v3.2.7][rexml-v3.2.7], [v3.2.8][rexml-v3.2.8], [v3.2.9][rexml-v3.2.9], [v3.3.0][rexml-v3.3.0], [v3.3.1][rexml-v3.3.1], [v3.3.2][rexml-v3.3.2], [v3.3.3][rexml-v3.3.3], [v3.3.4][rexml-v3.3.4], [v3.3.5][rexml-v3.3.5], [v3.3.6][rexml-v3.3.6], [v3.3.7][rexml-v3.3.7], [v3.3.8][rexml-v3.3.8], [v3.3.9][rexml-v3.3.9], [v3.4.0][rexml-v3.4.0]
+* [rss][rss] 0.3.1
+ * 0.3.0 to [0.3.1][rss-0.3.1]
+* [net-ftp][net-ftp] 0.3.8
+ * 0.3.3 to [v0.3.4][net-ftp-v0.3.4], [v0.3.5][net-ftp-v0.3.5], [v0.3.6][net-ftp-v0.3.6], [v0.3.7][net-ftp-v0.3.7], [v0.3.8][net-ftp-v0.3.8]
+* [net-imap][net-imap] 0.5.4
+ * 0.4.9 to [v0.4.9.1][net-imap-v0.4.9.1], [v0.4.10][net-imap-v0.4.10], [v0.4.11][net-imap-v0.4.11], [v0.4.12][net-imap-v0.4.12], [v0.4.13][net-imap-v0.4.13], [v0.4.14][net-imap-v0.4.14], [v0.4.15][net-imap-v0.4.15], [v0.4.16][net-imap-v0.4.16], [v0.4.17][net-imap-v0.4.17], [v0.5.0][net-imap-v0.5.0], [v0.4.18][net-imap-v0.4.18], [v0.5.1][net-imap-v0.5.1], [v0.5.2][net-imap-v0.5.2], [v0.5.3][net-imap-v0.5.3], [v0.5.4][net-imap-v0.5.4]
+* [net-smtp][net-smtp] 0.5.0
+ * 0.4.0 to [v0.4.0.1][net-smtp-v0.4.0.1], [v0.5.0][net-smtp-v0.5.0]
+* [prime][prime] 0.1.3
+ * 0.1.2 to [v0.1.3][prime-v0.1.3]
+* [rbs][rbs] 3.8.0
+ * 3.4.0 to [v3.4.1][rbs-v3.4.1], [v3.4.2][rbs-v3.4.2], [v3.4.3][rbs-v3.4.3], [v3.4.4][rbs-v3.4.4], [v3.5.0.pre.1][rbs-v3.5.0.pre.1], [v3.5.0.pre.2][rbs-v3.5.0.pre.2], [v3.5.0][rbs-v3.5.0], [v3.5.1][rbs-v3.5.1], [v3.5.2][rbs-v3.5.2], [v3.5.3][rbs-v3.5.3], [v3.6.0.dev.1][rbs-v3.6.0.dev.1], [v3.6.0.pre.1][rbs-v3.6.0.pre.1], [v3.6.0.pre.2][rbs-v3.6.0.pre.2], [v3.6.0.pre.3][rbs-v3.6.0.pre.3], [v3.6.0][rbs-v3.6.0], [v3.6.1][rbs-v3.6.1], [v3.7.0.dev.1][rbs-v3.7.0.dev.1], [v3.7.0.pre.1][rbs-v3.7.0.pre.1], [v3.7.0][rbs-v3.7.0], [v3.8.0.pre.1][rbs-v3.8.0.pre.1] [v3.8.0][rbs-v3.8.0]
+* [typeprof][typeprof] 0.30.1
+ * 0.21.9 to [v0.30.1][typeprof-v0.30.1]
+* [debug][debug] 1.10.0
+ * 1.9.1 to [v1.9.2][debug-v1.9.2], [v1.10.0][debug-v1.10.0]
+* [racc][racc] 1.8.1
+ * 1.7.3 to [v1.8.0][racc-v1.8.0], [v1.8.1][racc-v1.8.1]
+
+The following bundled gems are promoted from default gems.
+
+* [mutex_m][mutex_m] 0.3.0
+ * 0.2.0 to [v0.3.0][mutex_m-v0.3.0]
+* [getoptlong][getoptlong] 0.2.1
+* [base64][base64] 0.2.0
+* [bigdecimal][bigdecimal] 3.1.8
+ * 3.1.5 to [v3.1.6][bigdecimal-v3.1.6], [v3.1.7][bigdecimal-v3.1.7], [v3.1.8][bigdecimal-v3.1.8]
+* [observer][observer] 0.1.2
+* [abbrev][abbrev] 0.1.2
+* [resolv-replace][resolv-replace] 0.1.1
+* [rinda][rinda] 0.2.0
+* [drb][drb] 2.2.1
+ * 2.2.0 to [v2.2.1][drb-v2.2.1]
+* [nkf][nkf] 0.2.0
+ * 0.1.3 to [v0.2.0][nkf-v0.2.0]
+* [syslog][syslog] 0.2.0
+ * 0.1.2 to [v0.2.0][syslog-v0.2.0]
+* [csv][csv] 3.3.2
+ * 3.2.8 to [v3.2.9][csv-v3.2.9], [v3.3.0][csv-v3.3.0], [v3.3.1][csv-v3.3.1], [v3.3.2][csv-v3.3.2]
+
+## Supported platforms
+
+## Compatibility issues
+
+* Error messages and backtrace displays have been changed.
+
+ * Use a single quote instead of a backtick as an opening quote. [[Feature #16495]]
+ * Display a class name before a method name (only when the class has a permanent name). [[Feature #19117]]
+ * Extra `rescue`/`ensure` frames are no longer available on the backtrace. [[Feature #20275]]
+ * `Kernel#caller`, `Thread::Backtrace::Location`’s methods, etc. are also changed accordingly.
+
+ Old:
+ ```
+ test.rb:1:in `foo': undefined method `time' for an instance of Integer
+ from test.rb:2:in `<main>'
+ ```
+
+ New:
+ ```
+ test.rb:1:in 'Object#foo': undefined method 'time' for an instance of Integer
+ from test.rb:2:in '<main>'
+ ```
+
+* `Hash#inspect` rendering have been changed. [[Bug #20433]]
+
+ * Symbol keys are displayed using the modern symbol key syntax: `"{user: 1}"`
+ * Other keys now have spaces around `=>`: `'{"user" => 1}'`, while previously they didn't: `'{"user"=>1}'`
+
+* `Kernel#Float()` now accepts a decimal string with decimal part omitted. [[Feature #20705]]
+
+ ```rb
+ Float("1.") #=> 1.0 (previously, an ArgumentError was raised)
+ Float("1.E-1") #=> 0.1 (previously, an ArgumentError was raised)
+ ```
+
+* `String#to_f` now accepts a decimal string with decimal part omitted. [[Feature #20705]]
+ Note that the result changes when an exponent is specified.
+
+ ```rb
+ "1.".to_f #=> 1.0
+ "1.E-1".to_f #=> 0.1 (previously, 1.0 was returned)
+ ```
+
+* `Refinement#refined_class` has been removed. [[Feature #19714]]
+
+## Stdlib compatibility issues
+
+* DidYouMean
+
+ * `DidYouMean::SPELL_CHECKERS[]=` and `DidYouMean::SPELL_CHECKERS.merge!` are removed.
+
+* Net::HTTP
+
+ * Removed the following deprecated constants:
+ * `Net::HTTP::ProxyMod`
+ * `Net::NetPrivate::HTTPRequest`
+ * `Net::HTTPInformationCode`
+ * `Net::HTTPSuccessCode`
+ * `Net::HTTPRedirectionCode`
+ * `Net::HTTPRetriableCode`
+ * `Net::HTTPClientErrorCode`
+ * `Net::HTTPFatalErrorCode`
+ * `Net::HTTPServerErrorCode`
+ * `Net::HTTPResponseReceiver`
+ * `Net::HTTPResponceReceiver`
+
+ These constants were deprecated from 2012.
+
+* Timeout
+
+ * Reject negative values for `Timeout.timeout`. [[Bug #20795]]
+
+* URI
+
+ * Switched default parser to RFC 3986 compliant from RFC 2396 compliant.
+ [[Bug #19266]]
+
+## C API updates
+
+* `rb_newobj` and `rb_newobj_of` (and corresponding macros `RB_NEWOBJ`, `RB_NEWOBJ_OF`, `NEWOBJ`, `NEWOBJ_OF`) have been removed. [[Feature #20265]]
+* Removed deprecated function `rb_gc_force_recycle`. [[Feature #18290]]
+
+## Implementation improvements
+
+* The default parser is now Prism.
+ To use the conventional parser, use the command-line argument `--parser=parse.y`.
+ [[Feature #20564]]
+
+* Happy Eyeballs version 2 (RFC8305), an algorithm that ensures faster and more reliable connections
+ by attempting IPv6 and IPv4 concurrently, is used in `Socket.tcp` and `TCPSocket.new`.
+ To disable it globally, set the environment variable `RUBY_TCP_NO_FAST_FALLBACK=1` or
+ call `Socket.tcp_fast_fallback=false`.
+ Or to disable it on a per-method basis, use the keyword argument `fast_fallback: false`.
+ [[Feature #20108]] [[Feature #20782]]
+
+* Alternative garbage collector (GC) implementations can be loaded dynamically
+ through the modular garbage collector feature. To enable this feature,
+ configure Ruby with `--with-modular-gc` at build time. GC libraries can be
+ loaded at runtime using the environment variable `RUBY_GC_LIBRARY`.
+ [[Feature #20351]]
+
+* Ruby's built-in garbage collector has been split into a separate file at
+ `gc/default/default.c` and interacts with Ruby using an API defined in
+ `gc/gc_impl.h`. The built-in garbage collector can now also be built as a
+ library using `make modular-gc MODULAR_GC=default` and enabled using the
+ environment variable `RUBY_GC_LIBRARY=default`. [[Feature #20470]]
+
+* An experimental GC library is provided based on [MMTk](https://www.mmtk.io/).
+ This GC library can be built using `make modular-gc MODULAR_GC=mmtk` and
+ enabled using the environment variable `RUBY_GC_LIBRARY=mmtk`. This requires
+ the Rust toolchain on the build machine. [[Feature #20860]]
+
+### YJIT
+
+#### New features
+
+* Command-line options
+ * `--yjit-mem-size` introduces a unified memory limit (default 128MiB) to track total YJIT memory usage,
+ providing a more intuitive alternative to the old `--yjit-exec-mem-size` option.
+ * `--yjit-trace-exits=COUNTER` allows tracing of counted exits and fallbacks.
+ * `--yjit-perf=codegen` allows profiling of JIT code based on YJIT's codegen functions.
+ * `--yjit-log` enables a compilation log to track what gets compiled.
+* Ruby API
+ * `RubyVM::YJIT.enable(log: true)` also enables a compilation log.
+ * `RubyVM::YJIT.log` provides access to the tail of the compilation log at run-time.
+* YJIT stats
+ * `RubyVM::YJIT.runtime_stats` now always provides additional statistics on
+ invalidation, inlining, and metadata encoding.
+ * `RubyVM::YJIT.runtime_stats[:iseq_calls]` is added to profile non-inlined Ruby method calls.
+ * `RubyVM::YJIT.runtime_stats[:cfunc_calls]` is truncated to the top 20 entries for better performance.
+
+#### New optimizations
+
+* Compressed context reduces memory needed to store YJIT metadata
+* Allocate registers for local variables and Ruby method arguments
+* When YJIT is enabled, use more Core primitives written in Ruby:
+ * `Array#each`, `Array#select`, `Array#map` rewritten in Ruby for better performance [[Feature #20182]].
+* Ability to inline small/trivial methods such as:
+ * Empty methods
+ * Methods returning a constant
+ * Methods returning `self`
+ * Methods directly returning an argument
+* Specialized codegen for many more runtime methods
+* Optimize `String#getbyte`, `String#setbyte` and other string methods
+* Optimize bitwise operations to speed up low-level bit/byte manipulation
+* Support shareable constants in multi-ractor mode
+* Various other incremental optimizations
+
+## Miscellaneous changes
+
+* Passing a block to a method which doesn't use the passed block will show
+ a warning on verbose mode (`-w`).
+ In connection with this, a new `strict_unused_block` warning category was introduced.
+ Turn them on with `-W:strict_unused_block` or `Warning[:strict_unused_block] = true`.
+ [[Feature #15554]]
+
+* Redefining some core methods that are specially optimized by the interpreter
+ and JIT like `String#freeze` or `Integer#+` now emits a performance class
+ warning (`-W:performance` or `Warning[:performance] = true`).
+ [[Feature #20429]]
+
+[Feature #13557]: https://bugs.ruby-lang.org/issues/13557
+[Feature #15554]: https://bugs.ruby-lang.org/issues/15554
+[Feature #16495]: https://bugs.ruby-lang.org/issues/16495
+[Feature #18290]: https://bugs.ruby-lang.org/issues/18290
+[Feature #18368]: https://bugs.ruby-lang.org/issues/18368
+[Feature #18980]: https://bugs.ruby-lang.org/issues/18980
+[Misc #18984]: https://bugs.ruby-lang.org/issues/18984
+[Feature #19117]: https://bugs.ruby-lang.org/issues/19117
+[Feature #19236]: https://bugs.ruby-lang.org/issues/19236
+[Bug #19266]: https://bugs.ruby-lang.org/issues/19266
+[Feature #19714]: https://bugs.ruby-lang.org/issues/19714
+[Bug #19918]: https://bugs.ruby-lang.org/issues/19918
+[Feature #20018]: https://bugs.ruby-lang.org/issues/20018
+[Bug #20064]: https://bugs.ruby-lang.org/issues/20064
+[Feature #20108]: https://bugs.ruby-lang.org/issues/20108
+[Feature #20182]: https://bugs.ruby-lang.org/issues/20182
+[Feature #20205]: https://bugs.ruby-lang.org/issues/20205
+[Bug #20218]: https://bugs.ruby-lang.org/issues/20218
+[Feature #20265]: https://bugs.ruby-lang.org/issues/20265
+[Feature #20275]: https://bugs.ruby-lang.org/issues/20275
+[Feature #20293]: https://bugs.ruby-lang.org/issues/20293
+[Feature #20350]: https://bugs.ruby-lang.org/issues/20350
+[Feature #20351]: https://bugs.ruby-lang.org/issues/20351
+[Feature #20429]: https://bugs.ruby-lang.org/issues/20429
+[Bug #20433]: https://bugs.ruby-lang.org/issues/20433
+[Feature #20443]: https://bugs.ruby-lang.org/issues/20443
+[Feature #20470]: https://bugs.ruby-lang.org/issues/20470
+[Feature #20497]: https://bugs.ruby-lang.org/issues/20497
+[Feature #20564]: https://bugs.ruby-lang.org/issues/20564
+[Feature #20576]: https://bugs.ruby-lang.org/issues/20576
+[Feature #20594]: https://bugs.ruby-lang.org/issues/20594
+[Bug #20620]: https://bugs.ruby-lang.org/issues/20620
+[Feature #20624]: https://bugs.ruby-lang.org/issues/20624
+[Feature #20627]: https://bugs.ruby-lang.org/issues/20627
+[Feature #20702]: https://bugs.ruby-lang.org/issues/20702
+[Feature #20705]: https://bugs.ruby-lang.org/issues/20705
+[Feature #20707]: https://bugs.ruby-lang.org/issues/20707
+[Feature #20715]: https://bugs.ruby-lang.org/issues/20715
+[Feature #20775]: https://bugs.ruby-lang.org/issues/20775
+[Feature #20778]: https://bugs.ruby-lang.org/issues/20778
+[Feature #20782]: https://bugs.ruby-lang.org/issues/20782
+[Bug #20795]: https://bugs.ruby-lang.org/issues/20795
+[Feature #20811]: https://bugs.ruby-lang.org/issues/20811
+[Feature #20860]: https://bugs.ruby-lang.org/issues/20860
+[Feature #20875]: https://bugs.ruby-lang.org/issues/20875
+[Feature #20876]: https://bugs.ruby-lang.org/issues/20876
+[Feature #20884]: https://bugs.ruby-lang.org/issues/20884
+[Feature #20902]: https://bugs.ruby-lang.org/issues/20902
+[Bug #20929]: https://bugs.ruby-lang.org/issues/20929
+[RubyGems-v3.5.4]: https://github.com/rubygems/rubygems/releases/tag/v3.5.4
+[RubyGems-v3.5.5]: https://github.com/rubygems/rubygems/releases/tag/v3.5.5
+[RubyGems-v3.5.6]: https://github.com/rubygems/rubygems/releases/tag/v3.5.6
+[RubyGems-v3.5.7]: https://github.com/rubygems/rubygems/releases/tag/v3.5.7
+[RubyGems-v3.5.8]: https://github.com/rubygems/rubygems/releases/tag/v3.5.8
+[RubyGems-v3.5.9]: https://github.com/rubygems/rubygems/releases/tag/v3.5.9
+[RubyGems-v3.5.10]: https://github.com/rubygems/rubygems/releases/tag/v3.5.10
+[RubyGems-v3.5.11]: https://github.com/rubygems/rubygems/releases/tag/v3.5.11
+[RubyGems-v3.5.12]: https://github.com/rubygems/rubygems/releases/tag/v3.5.12
+[RubyGems-v3.5.13]: https://github.com/rubygems/rubygems/releases/tag/v3.5.13
+[RubyGems-v3.5.14]: https://github.com/rubygems/rubygems/releases/tag/v3.5.14
+[RubyGems-v3.5.15]: https://github.com/rubygems/rubygems/releases/tag/v3.5.15
+[RubyGems-v3.5.16]: https://github.com/rubygems/rubygems/releases/tag/v3.5.16
+[RubyGems-v3.5.17]: https://github.com/rubygems/rubygems/releases/tag/v3.5.17
+[RubyGems-v3.5.18]: https://github.com/rubygems/rubygems/releases/tag/v3.5.18
+[RubyGems-v3.5.19]: https://github.com/rubygems/rubygems/releases/tag/v3.5.19
+[RubyGems-v3.5.20]: https://github.com/rubygems/rubygems/releases/tag/v3.5.20
+[RubyGems-v3.5.21]: https://github.com/rubygems/rubygems/releases/tag/v3.5.21
+[RubyGems-v3.5.22]: https://github.com/rubygems/rubygems/releases/tag/v3.5.22
+[RubyGems-v3.5.23]: https://github.com/rubygems/rubygems/releases/tag/v3.5.23
+[RubyGems-v3.6.0]: https://github.com/rubygems/rubygems/releases/tag/v3.6.0
+[RubyGems-v3.6.1]: https://github.com/rubygems/rubygems/releases/tag/v3.6.1
+[RubyGems-v3.6.2]: https://github.com/rubygems/rubygems/releases/tag/v3.6.2
+[benchmark-v0.4.0]: https://github.com/ruby/benchmark/releases/tag/v0.4.0
+[bundler-v2.5.4]: https://github.com/rubygems/rubygems/releases/tag/bundler-v2.5.4
+[bundler-v2.5.5]: https://github.com/rubygems/rubygems/releases/tag/bundler-v2.5.5
+[bundler-v2.5.6]: https://github.com/rubygems/rubygems/releases/tag/bundler-v2.5.6
+[bundler-v2.5.7]: https://github.com/rubygems/rubygems/releases/tag/bundler-v2.5.7
+[bundler-v2.5.8]: https://github.com/rubygems/rubygems/releases/tag/bundler-v2.5.8
+[bundler-v2.5.9]: https://github.com/rubygems/rubygems/releases/tag/bundler-v2.5.9
+[bundler-v2.5.10]: https://github.com/rubygems/rubygems/releases/tag/bundler-v2.5.10
+[bundler-v2.5.11]: https://github.com/rubygems/rubygems/releases/tag/bundler-v2.5.11
+[bundler-v2.5.12]: https://github.com/rubygems/rubygems/releases/tag/bundler-v2.5.12
+[bundler-v2.5.13]: https://github.com/rubygems/rubygems/releases/tag/bundler-v2.5.13
+[bundler-v2.5.14]: https://github.com/rubygems/rubygems/releases/tag/bundler-v2.5.14
+[bundler-v2.5.15]: https://github.com/rubygems/rubygems/releases/tag/bundler-v2.5.15
+[bundler-v2.5.16]: https://github.com/rubygems/rubygems/releases/tag/bundler-v2.5.16
+[bundler-v2.5.17]: https://github.com/rubygems/rubygems/releases/tag/bundler-v2.5.17
+[bundler-v2.5.18]: https://github.com/rubygems/rubygems/releases/tag/bundler-v2.5.18
+[bundler-v2.5.19]: https://github.com/rubygems/rubygems/releases/tag/bundler-v2.5.19
+[bundler-v2.5.20]: https://github.com/rubygems/rubygems/releases/tag/bundler-v2.5.20
+[bundler-v2.5.21]: https://github.com/rubygems/rubygems/releases/tag/bundler-v2.5.21
+[bundler-v2.5.22]: https://github.com/rubygems/rubygems/releases/tag/bundler-v2.5.22
+[bundler-v2.5.23]: https://github.com/rubygems/rubygems/releases/tag/bundler-v2.5.23
+[bundler-v2.6.0]: https://github.com/rubygems/rubygems/releases/tag/bundler-v2.6.0
+[bundler-v2.6.1]: https://github.com/rubygems/rubygems/releases/tag/bundler-v2.6.1
+[bundler-v2.6.2]: https://github.com/rubygems/rubygems/releases/tag/bundler-v2.6.2
+[date-v3.4.0]: https://github.com/ruby/date/releases/tag/v3.4.0
+[date-v3.4.1]: https://github.com/ruby/date/releases/tag/v3.4.1
+[delegate-v0.4.0]: https://github.com/ruby/delegate/releases/tag/v0.4.0
+[did_you_mean-v2.0.0]: https://github.com/ruby/did_you_mean/releases/tag/v2.0.0
+[digest-v3.2.0.pre0]: https://github.com/ruby/digest/releases/tag/v3.2.0.pre0
+[digest-v3.2.0]: https://github.com/ruby/digest/releases/tag/v3.2.0
+[erb-v4.0.4]: https://github.com/ruby/erb/releases/tag/v4.0.4
+[etc-v1.4.4]: https://github.com/ruby/etc/releases/tag/v1.4.4
+[etc-v1.4.5]: https://github.com/ruby/etc/releases/tag/v1.4.5
+[fcntl-v1.2.0]: https://github.com/ruby/fcntl/releases/tag/v1.2.0
+[fiddle-v1.1.3]: https://github.com/ruby/fiddle/releases/tag/v1.1.3
+[fiddle-v1.1.4]: https://github.com/ruby/fiddle/releases/tag/v1.1.4
+[fiddle-v1.1.5]: https://github.com/ruby/fiddle/releases/tag/v1.1.5
+[fiddle-v1.1.6]: https://github.com/ruby/fiddle/releases/tag/v1.1.6
+[fileutils-v1.7.3]: https://github.com/ruby/fileutils/releases/tag/v1.7.3
+[io-console-v0.7.2]: https://github.com/ruby/io-console/releases/tag/v0.7.2
+[io-console-v0.8.0.beta1]: https://github.com/ruby/io-console/releases/tag/v0.8.0.beta1
+[io-console-v0.8.0]: https://github.com/ruby/io-console/releases/tag/v0.8.0
+[io-nonblock-v0.3.1]: https://github.com/ruby/io-nonblock/releases/tag/v0.3.1
+[ipaddr-v1.2.7]: https://github.com/ruby/ipaddr/releases/tag/v1.2.7
+[irb-v1.11.1]: https://github.com/ruby/irb/releases/tag/v1.11.1
+[irb-v1.11.2]: https://github.com/ruby/irb/releases/tag/v1.11.2
+[irb-v1.12.0]: https://github.com/ruby/irb/releases/tag/v1.12.0
+[irb-v1.13.0]: https://github.com/ruby/irb/releases/tag/v1.13.0
+[irb-v1.13.1]: https://github.com/ruby/irb/releases/tag/v1.13.1
+[irb-v1.13.2]: https://github.com/ruby/irb/releases/tag/v1.13.2
+[irb-v1.14.0]: https://github.com/ruby/irb/releases/tag/v1.14.0
+[irb-v1.14.1]: https://github.com/ruby/irb/releases/tag/v1.14.1
+[irb-v1.14.2]: https://github.com/ruby/irb/releases/tag/v1.14.2
+[irb-v1.14.3]: https://github.com/ruby/irb/releases/tag/v1.14.3
+[json-v2.7.2]: https://github.com/ruby/json/releases/tag/v2.7.2
+[json-v2.7.3.rc1]: https://github.com/ruby/json/releases/tag/v2.7.3.rc1
+[json-v2.7.3]: https://github.com/ruby/json/releases/tag/v2.7.3
+[json-v2.7.4]: https://github.com/ruby/json/releases/tag/v2.7.4
+[json-v2.7.5]: https://github.com/ruby/json/releases/tag/v2.7.5
+[json-v2.7.6]: https://github.com/ruby/json/releases/tag/v2.7.6
+[json-v2.8.0]: https://github.com/ruby/json/releases/tag/v2.8.0
+[json-v2.8.1]: https://github.com/ruby/json/releases/tag/v2.8.1
+[json-v2.8.2]: https://github.com/ruby/json/releases/tag/v2.8.2
+[json-v2.9.0]: https://github.com/ruby/json/releases/tag/v2.9.0
+[json-v2.9.1]: https://github.com/ruby/json/releases/tag/v2.9.1
+[logger-v1.6.1]: https://github.com/ruby/logger/releases/tag/v1.6.1
+[logger-v1.6.2]: https://github.com/ruby/logger/releases/tag/v1.6.2
+[logger-v1.6.3]: https://github.com/ruby/logger/releases/tag/v1.6.3
+[logger-v1.6.4]: https://github.com/ruby/logger/releases/tag/v1.6.4
+[net-http-v0.4.1]: https://github.com/ruby/net-http/releases/tag/v0.4.1
+[net-http-v0.5.0]: https://github.com/ruby/net-http/releases/tag/v0.5.0
+[net-http-v0.6.0]: https://github.com/ruby/net-http/releases/tag/v0.6.0
+[open-uri-v0.5.0]: https://github.com/ruby/open-uri/releases/tag/v0.5.0
+[optparse-v0.5.0]: https://github.com/ruby/optparse/releases/tag/v0.5.0
+[optparse-v0.6.0]: https://github.com/ruby/optparse/releases/tag/v0.6.0
+[ostruct-v0.6.1]: https://github.com/ruby/ostruct/releases/tag/v0.6.1
+[pathname-v0.4.0]: https://github.com/ruby/pathname/releases/tag/v0.4.0
+[pp-v0.6.0]: https://github.com/ruby/pp/releases/tag/v0.6.0
+[pp-v0.6.1]: https://github.com/ruby/pp/releases/tag/v0.6.1
+[pp-v0.6.2]: https://github.com/ruby/pp/releases/tag/v0.6.2
+[prism-v0.20.0]: https://github.com/ruby/prism/releases/tag/v0.20.0
+[prism-v0.21.0]: https://github.com/ruby/prism/releases/tag/v0.21.0
+[prism-v0.22.0]: https://github.com/ruby/prism/releases/tag/v0.22.0
+[prism-v0.23.0]: https://github.com/ruby/prism/releases/tag/v0.23.0
+[prism-v0.24.0]: https://github.com/ruby/prism/releases/tag/v0.24.0
+[prism-v0.25.0]: https://github.com/ruby/prism/releases/tag/v0.25.0
+[prism-v0.26.0]: https://github.com/ruby/prism/releases/tag/v0.26.0
+[prism-v0.27.0]: https://github.com/ruby/prism/releases/tag/v0.27.0
+[prism-v0.28.0]: https://github.com/ruby/prism/releases/tag/v0.28.0
+[prism-v0.29.0]: https://github.com/ruby/prism/releases/tag/v0.29.0
+[prism-v0.30.0]: https://github.com/ruby/prism/releases/tag/v0.30.0
+[prism-v1.0.0]: https://github.com/ruby/prism/releases/tag/v1.0.0
+[prism-v1.1.0]: https://github.com/ruby/prism/releases/tag/v1.1.0
+[prism-v1.2.0]: https://github.com/ruby/prism/releases/tag/v1.2.0
+[pstore-v0.1.4]: https://github.com/ruby/pstore/releases/tag/v0.1.4
+[psych-v5.2.0.beta1]: https://github.com/ruby/psych/releases/tag/v5.2.0.beta1
+[psych-v5.2.0]: https://github.com/ruby/psych/releases/tag/v5.2.0
+[psych-v5.2.0.beta2]: https://github.com/ruby/psych/releases/tag/v5.2.0.beta2
+[psych-v5.2.0.beta3]: https://github.com/ruby/psych/releases/tag/v5.2.0.beta3
+[psych-v5.2.0.beta4]: https://github.com/ruby/psych/releases/tag/v5.2.0.beta4
+[psych-v5.2.0.beta5]: https://github.com/ruby/psych/releases/tag/v5.2.0.beta5
+[psych-v5.2.0.beta6]: https://github.com/ruby/psych/releases/tag/v5.2.0.beta6
+[psych-v5.2.0.beta7]: https://github.com/ruby/psych/releases/tag/v5.2.0.beta7
+[psych-v5.2.1]: https://github.com/ruby/psych/releases/tag/v5.2.1
+[psych-v5.2.2]: https://github.com/ruby/psych/releases/tag/v5.2.2
+[rdoc-v6.7.0]: https://github.com/ruby/rdoc/releases/tag/v6.7.0
+[rdoc-v6.8.0]: https://github.com/ruby/rdoc/releases/tag/v6.8.0
+[rdoc-v6.8.1]: https://github.com/ruby/rdoc/releases/tag/v6.8.1
+[rdoc-v6.9.0]: https://github.com/ruby/rdoc/releases/tag/v6.9.0
+[rdoc-v6.9.1]: https://github.com/ruby/rdoc/releases/tag/v6.9.1
+[rdoc-v6.10.0]: https://github.com/ruby/rdoc/releases/tag/v6.10.0
+[reline-v0.5.0.pre.1]: https://github.com/ruby/reline/releases/tag/v0.5.0.pre.1
+[reline-v0.4.2]: https://github.com/ruby/reline/releases/tag/v0.4.2
+[reline-v0.4.3]: https://github.com/ruby/reline/releases/tag/v0.4.3
+[reline-v0.5.0]: https://github.com/ruby/reline/releases/tag/v0.5.0
+[reline-v0.5.1]: https://github.com/ruby/reline/releases/tag/v0.5.1
+[reline-v0.5.2]: https://github.com/ruby/reline/releases/tag/v0.5.2
+[reline-v0.5.3]: https://github.com/ruby/reline/releases/tag/v0.5.3
+[reline-v0.5.4]: https://github.com/ruby/reline/releases/tag/v0.5.4
+[reline-v0.5.5]: https://github.com/ruby/reline/releases/tag/v0.5.5
+[reline-v0.5.6]: https://github.com/ruby/reline/releases/tag/v0.5.6
+[reline-v0.5.7]: https://github.com/ruby/reline/releases/tag/v0.5.7
+[reline-v0.5.8]: https://github.com/ruby/reline/releases/tag/v0.5.8
+[reline-v0.5.9]: https://github.com/ruby/reline/releases/tag/v0.5.9
+[reline-v0.5.10]: https://github.com/ruby/reline/releases/tag/v0.5.10
+[reline-v0.5.11]: https://github.com/ruby/reline/releases/tag/v0.5.11
+[reline-v0.5.12]: https://github.com/ruby/reline/releases/tag/v0.5.12
+[reline-v0.6.0]: https://github.com/ruby/reline/releases/tag/v0.6.0
+[resolv-v0.4.0]: https://github.com/ruby/resolv/releases/tag/v0.4.0
+[resolv-v0.5.0]: https://github.com/ruby/resolv/releases/tag/v0.5.0
+[resolv-v0.6.0]: https://github.com/ruby/resolv/releases/tag/v0.6.0
+[securerandom-v0.3.2]: https://github.com/ruby/securerandom/releases/tag/v0.3.2
+[securerandom-v0.4.0]: https://github.com/ruby/securerandom/releases/tag/v0.4.0
+[securerandom-v0.4.1]: https://github.com/ruby/securerandom/releases/tag/v0.4.1
+[set-v1.1.1]: https://github.com/ruby/set/releases/tag/v1.1.1
+[shellwords-v0.2.1]: https://github.com/ruby/shellwords/releases/tag/v0.2.1
+[shellwords-v0.2.2]: https://github.com/ruby/shellwords/releases/tag/v0.2.2
+[singleton-v0.3.0]: https://github.com/ruby/singleton/releases/tag/v0.3.0
+[stringio-v3.1.1]: https://github.com/ruby/stringio/releases/tag/v3.1.1
+[stringio-v3.1.2]: https://github.com/ruby/stringio/releases/tag/v3.1.2
+[strscan-v3.0.8]: https://github.com/ruby/strscan/releases/tag/v3.0.8
+[strscan-v3.0.9]: https://github.com/ruby/strscan/releases/tag/v3.0.9
+[strscan-v3.1.0]: https://github.com/ruby/strscan/releases/tag/v3.1.0
+[strscan-v3.1.1]: https://github.com/ruby/strscan/releases/tag/v3.1.1
+[strscan-v3.1.2]: https://github.com/ruby/strscan/releases/tag/v3.1.2
+[syntax_suggest-v2.0.1]: https://github.com/ruby/syntax_suggest/releases/tag/v2.0.1
+[syntax_suggest-v2.0.2]: https://github.com/ruby/syntax_suggest/releases/tag/v2.0.2
+[tempfile-v0.3.0]: https://github.com/ruby/tempfile/releases/tag/v0.3.0
+[tempfile-v0.3.1]: https://github.com/ruby/tempfile/releases/tag/v0.3.1
+[time-v0.4.0]: https://github.com/ruby/time/releases/tag/v0.4.0
+[time-v0.4.1]: https://github.com/ruby/time/releases/tag/v0.4.1
+[timeout-v0.4.2]: https://github.com/ruby/timeout/releases/tag/v0.4.2
+[timeout-v0.4.3]: https://github.com/ruby/timeout/releases/tag/v0.4.3
+[tmpdir-v0.3.0]: https://github.com/ruby/tmpdir/releases/tag/v0.3.0
+[tmpdir-v0.3.1]: https://github.com/ruby/tmpdir/releases/tag/v0.3.1
+[uri-v0.13.1]: https://github.com/ruby/uri/releases/tag/v0.13.1
+[uri-v1.0.0]: https://github.com/ruby/uri/releases/tag/v1.0.0
+[uri-v1.0.1]: https://github.com/ruby/uri/releases/tag/v1.0.1
+[uri-v1.0.2]: https://github.com/ruby/uri/releases/tag/v1.0.2
+[win32ole-v1.9.0]: https://github.com/ruby/win32ole/releases/tag/v1.9.0
+[win32ole-v1.9.1]: https://github.com/ruby/win32ole/releases/tag/v1.9.1
+[yaml-v0.4.0]: https://github.com/ruby/yaml/releases/tag/v0.4.0
+[zlib-v3.1.1]: https://github.com/ruby/zlib/releases/tag/v3.1.1
+[zlib-v3.2.0]: https://github.com/ruby/zlib/releases/tag/v3.2.0
+[zlib-v3.2.1]: https://github.com/ruby/zlib/releases/tag/v3.2.1
+[minitest-v5.25.4]: https://github.com/seattlerb/minitest/releases/tag/v5.25.4
+[power_assert-v2.0.4]: https://github.com/ruby/power_assert/releases/tag/v2.0.4
+[power_assert-v2.0.5]: https://github.com/ruby/power_assert/releases/tag/v2.0.5
+[rake-v13.2.0]: https://github.com/ruby/rake/releases/tag/v13.2.0
+[rake-v13.2.1]: https://github.com/ruby/rake/releases/tag/v13.2.1
+[test-unit-3.6.2]: https://github.com/test-unit/test-unit/releases/tag/3.6.2
+[test-unit-3.6.3]: https://github.com/test-unit/test-unit/releases/tag/3.6.3
+[test-unit-3.6.4]: https://github.com/test-unit/test-unit/releases/tag/3.6.4
+[test-unit-3.6.5]: https://github.com/test-unit/test-unit/releases/tag/3.6.5
+[test-unit-3.6.6]: https://github.com/test-unit/test-unit/releases/tag/3.6.6
+[test-unit-3.6.7]: https://github.com/test-unit/test-unit/releases/tag/3.6.7
+[rexml-v3.2.7]: https://github.com/ruby/rexml/releases/tag/v3.2.7
+[rexml-v3.2.8]: https://github.com/ruby/rexml/releases/tag/v3.2.8
+[rexml-v3.2.9]: https://github.com/ruby/rexml/releases/tag/v3.2.9
+[rexml-v3.3.0]: https://github.com/ruby/rexml/releases/tag/v3.3.0
+[rexml-v3.3.1]: https://github.com/ruby/rexml/releases/tag/v3.3.1
+[rexml-v3.3.2]: https://github.com/ruby/rexml/releases/tag/v3.3.2
+[rexml-v3.3.3]: https://github.com/ruby/rexml/releases/tag/v3.3.3
+[rexml-v3.3.4]: https://github.com/ruby/rexml/releases/tag/v3.3.4
+[rexml-v3.3.5]: https://github.com/ruby/rexml/releases/tag/v3.3.5
+[rexml-v3.3.6]: https://github.com/ruby/rexml/releases/tag/v3.3.6
+[rexml-v3.3.7]: https://github.com/ruby/rexml/releases/tag/v3.3.7
+[rexml-v3.3.8]: https://github.com/ruby/rexml/releases/tag/v3.3.8
+[rexml-v3.3.9]: https://github.com/ruby/rexml/releases/tag/v3.3.9
+[rexml-v3.4.0]: https://github.com/ruby/rexml/releases/tag/v3.4.0
+[rss-0.3.1]: https://github.com/ruby/rss/releases/tag/0.3.1
+[net-ftp-v0.3.4]: https://github.com/ruby/net-ftp/releases/tag/v0.3.4
+[net-ftp-v0.3.5]: https://github.com/ruby/net-ftp/releases/tag/v0.3.5
+[net-ftp-v0.3.6]: https://github.com/ruby/net-ftp/releases/tag/v0.3.6
+[net-ftp-v0.3.7]: https://github.com/ruby/net-ftp/releases/tag/v0.3.7
+[net-ftp-v0.3.8]: https://github.com/ruby/net-ftp/releases/tag/v0.3.8
+[net-imap-v0.4.9.1]: https://github.com/ruby/net-imap/releases/tag/v0.4.9.1
+[net-imap-v0.4.10]: https://github.com/ruby/net-imap/releases/tag/v0.4.10
+[net-imap-v0.4.11]: https://github.com/ruby/net-imap/releases/tag/v0.4.11
+[net-imap-v0.4.12]: https://github.com/ruby/net-imap/releases/tag/v0.4.12
+[net-imap-v0.4.13]: https://github.com/ruby/net-imap/releases/tag/v0.4.13
+[net-imap-v0.4.14]: https://github.com/ruby/net-imap/releases/tag/v0.4.14
+[net-imap-v0.4.15]: https://github.com/ruby/net-imap/releases/tag/v0.4.15
+[net-imap-v0.4.16]: https://github.com/ruby/net-imap/releases/tag/v0.4.16
+[net-imap-v0.4.17]: https://github.com/ruby/net-imap/releases/tag/v0.4.17
+[net-imap-v0.5.0]: https://github.com/ruby/net-imap/releases/tag/v0.5.0
+[net-imap-v0.4.18]: https://github.com/ruby/net-imap/releases/tag/v0.4.18
+[net-imap-v0.5.1]: https://github.com/ruby/net-imap/releases/tag/v0.5.1
+[net-imap-v0.5.2]: https://github.com/ruby/net-imap/releases/tag/v0.5.2
+[net-imap-v0.5.3]: https://github.com/ruby/net-imap/releases/tag/v0.5.3
+[net-imap-v0.5.4]: https://github.com/ruby/net-imap/releases/tag/v0.5.4
+[net-smtp-v0.4.0.1]: https://github.com/ruby/net-smtp/releases/tag/v0.4.0.1
+[net-smtp-v0.5.0]: https://github.com/ruby/net-smtp/releases/tag/v0.5.0
+[prime-v0.1.3]: https://github.com/ruby/prime/releases/tag/v0.1.3
+[rbs-v3.4.1]: https://github.com/ruby/rbs/releases/tag/v3.4.1
+[rbs-v3.4.2]: https://github.com/ruby/rbs/releases/tag/v3.4.2
+[rbs-v3.4.3]: https://github.com/ruby/rbs/releases/tag/v3.4.3
+[rbs-v3.4.4]: https://github.com/ruby/rbs/releases/tag/v3.4.4
+[rbs-v3.5.0.pre.1]: https://github.com/ruby/rbs/releases/tag/v3.5.0.pre.1
+[rbs-v3.5.0.pre.2]: https://github.com/ruby/rbs/releases/tag/v3.5.0.pre.2
+[rbs-v3.5.0]: https://github.com/ruby/rbs/releases/tag/v3.5.0
+[rbs-v3.5.1]: https://github.com/ruby/rbs/releases/tag/v3.5.1
+[rbs-v3.5.2]: https://github.com/ruby/rbs/releases/tag/v3.5.2
+[rbs-v3.5.3]: https://github.com/ruby/rbs/releases/tag/v3.5.3
+[rbs-v3.6.0.dev.1]: https://github.com/ruby/rbs/releases/tag/v3.6.0.dev.1
+[rbs-v3.6.0.pre.1]: https://github.com/ruby/rbs/releases/tag/v3.6.0.pre.1
+[rbs-v3.6.0.pre.2]: https://github.com/ruby/rbs/releases/tag/v3.6.0.pre.2
+[rbs-v3.6.0.pre.3]: https://github.com/ruby/rbs/releases/tag/v3.6.0.pre.3
+[rbs-v3.6.0]: https://github.com/ruby/rbs/releases/tag/v3.6.0
+[rbs-v3.6.1]: https://github.com/ruby/rbs/releases/tag/v3.6.1
+[rbs-v3.7.0.dev.1]: https://github.com/ruby/rbs/releases/tag/v3.7.0.dev.1
+[rbs-v3.7.0.pre.1]: https://github.com/ruby/rbs/releases/tag/v3.7.0.pre.1
+[rbs-v3.7.0]: https://github.com/ruby/rbs/releases/tag/v3.7.0
+[rbs-v3.8.0.pre.1]: https://github.com/ruby/rbs/releases/tag/v3.8.0.pre.1
+[rbs-v3.8.0]: https://github.com/ruby/rbs/releases/tag/v3.8.0
+[debug-v1.9.2]: https://github.com/ruby/debug/releases/tag/v1.9.2
+[debug-v1.10.0]: https://github.com/ruby/debug/releases/tag/v1.10.0
+[racc-v1.8.0]: https://github.com/ruby/racc/releases/tag/v1.8.0
+[racc-v1.8.1]: https://github.com/ruby/racc/releases/tag/v1.8.1
+[mutex_m-v0.3.0]: https://github.com/ruby/mutex_m/releases/tag/v0.3.0
+[bigdecimal-v3.1.6]: https://github.com/ruby/bigdecimal/releases/tag/v3.1.6
+[bigdecimal-v3.1.7]: https://github.com/ruby/bigdecimal/releases/tag/v3.1.7
+[bigdecimal-v3.1.8]: https://github.com/ruby/bigdecimal/releases/tag/v3.1.8
+[drb-v2.2.1]: https://github.com/ruby/drb/releases/tag/v2.2.1
+[nkf-v0.2.0]: https://github.com/ruby/nkf/releases/tag/v0.2.0
+[syslog-v0.2.0]: https://github.com/ruby/syslog/releases/tag/v0.2.0
+[csv-v3.2.9]: https://github.com/ruby/csv/releases/tag/v3.2.9
+[csv-v3.3.0]: https://github.com/ruby/csv/releases/tag/v3.3.0
+[csv-v3.3.1]: https://github.com/ruby/csv/releases/tag/v3.3.1
+[csv-v3.3.2]: https://github.com/ruby/csv/releases/tag/v3.3.2
+[ruby/net-http-sspi]: https://github.com/ruby/net-http-sspi
+[typeprof-v0.30.1]: https://github.com/ruby/typeprof/releases/tag/v0.30.1
+
+[RubyGems]: https://github.com/rubygems/rubygems
+[benchmark]: https://github.com/ruby/benchmark
+[bundler]: https://github.com/rubygems/rubygems
+[date]: https://github.com/ruby/date
+[delegate]: https://github.com/ruby/delegate
+[did_you_mean]: https://github.com/ruby/did_you_mean
+[digest]: https://github.com/ruby/digest
+[erb]: https://github.com/ruby/erb
+[error_highlight]: https://github.com/ruby/error_highlight
+[etc]: https://github.com/ruby/etc
+[fcntl]: https://github.com/ruby/fcntl
+[fiddle]: https://github.com/ruby/fiddle
+[fileutils]: https://github.com/ruby/fileutils
+[io-console]: https://github.com/ruby/io-console
+[io-nonblock]: https://github.com/ruby/io-nonblock
+[ipaddr]: https://github.com/ruby/ipaddr
+[irb]: https://github.com/ruby/irb
+[json]: https://github.com/ruby/json
+[logger]: https://github.com/ruby/logger
+[net-http]: https://github.com/ruby/net-http
+[open-uri]: https://github.com/ruby/open-uri
+[optparse]: https://github.com/ruby/optparse
+[ostruct]: https://github.com/ruby/ostruct
+[pathname]: https://github.com/ruby/pathname
+[pp]: https://github.com/ruby/pp
+[prism]: https://github.com/ruby/prism
+[pstore]: https://github.com/ruby/pstore
+[psych]: https://github.com/ruby/psych
+[rdoc]: https://github.com/ruby/rdoc
+[reline]: https://github.com/ruby/reline
+[resolv]: https://github.com/ruby/resolv
+[securerandom]: https://github.com/ruby/securerandom
+[set]: https://github.com/ruby/set
+[shellwords]: https://github.com/ruby/shellwords
+[singleton]: https://github.com/ruby/singleton
+[stringio]: https://github.com/ruby/stringio
+[strscan]: https://github.com/ruby/strscan
+[syntax_suggest]: https://github.com/ruby/syntax_suggest
+[tempfile]: https://github.com/ruby/tempfile
+[time]: https://github.com/ruby/time
+[timeout]: https://github.com/ruby/timeout
+[tmpdir]: https://github.com/ruby/tmpdir
+[uri]: https://github.com/ruby/uri
+[win32ole]: https://github.com/ruby/win32ole
+[yaml]: https://github.com/ruby/yaml
+[zlib]: https://github.com/ruby/zlib
+
+[repl_type_completor]: https://github.com/ruby/repl_type_completor
+[minitest]: https://github.com/seattlerb/minitest
+[power_assert]: https://github.com/ruby/power_assert
+[rake]: https://github.com/ruby/rake
+[test-unit]: https://github.com/test-unit/test-unit
+[rexml]: https://github.com/ruby/rexml
+[rss]: https://github.com/ruby/rss
+[net-ftp]: https://github.com/ruby/net-ftp
+[net-imap]: https://github.com/ruby/net-imap
+[net-smtp]: https://github.com/ruby/net-smtp
+[prime]: https://github.com/ruby/prime
+[rbs]: https://github.com/ruby/rbs
+[typeprof]: https://github.com/ruby/typeprof
+[debug]: https://github.com/ruby/debug
+[racc]: https://github.com/ruby/racc
+[mutex_m]: https://github.com/ruby/mutex_m
+[getoptlong]: https://github.com/ruby/getoptlong
+[base64]: https://github.com/ruby/base64
+[bigdecimal]: https://github.com/ruby/bigdecimal
+[observer]: https://github.com/ruby/observer
+[abbrev]: https://github.com/ruby/abbrev
+[resolv-replace]: https://github.com/ruby/resolv-replace
+[rinda]: https://github.com/ruby/rinda
+[drb]: https://github.com/ruby/drb
+[nkf]: https://github.com/ruby/nkf
+[syslog]: https://github.com/ruby/syslog
+[csv]: https://github.com/ruby/csv
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
new file mode 100644
index 0000000000..4ad6118ddd
--- /dev/null
+++ b/doc/_regexp.rdoc
@@ -0,0 +1,1291 @@
+A {regular expression}[https://en.wikipedia.org/wiki/Regular_expression]
+(also called a _regexp_) is a <i>match pattern</i> (also simply called a _pattern_).
+
+A common notation for a regexp uses enclosing slash characters:
+
+ /foo/
+
+A regexp may be applied to a <i>target string</i>;
+The part of the string (if any) that matches the pattern is called a _match_,
+and may be said <i>to match</i>:
+
+ re = /red/
+ re.match?('redirect') # => true # Match at beginning of target.
+ re.match?('bored') # => true # Match at end of target.
+ re.match?('credit') # => true # Match within target.
+ re.match?('foo') # => false # No match.
+
+== \Regexp Uses
+
+A regexp may be used:
+
+- To extract substrings based on a given pattern:
+
+ re = /foo/ # => /foo/
+ re.match('food') # => #<MatchData "foo">
+ re.match('good') # => nil
+
+ See sections {Method match}[rdoc-ref:Regexp@Method+match]
+ and {Operator =~}[rdoc-ref:Regexp@Operator-].
+
+- 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].
+
+- 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:language/regexp/methods.rdoc].
+
+== \Regexp Objects
+
+A regexp object has:
+
+- A source; see {Sources}[rdoc-ref:Regexp@Sources].
+
+- Several modes; see {Modes}[rdoc-ref:Regexp@Modes].
+
+- A timeout; see {Timeouts}[rdoc-ref:Regexp@Timeouts].
+
+- An encoding; see {Encodings}[rdoc-ref:Regexp@Encodings].
+
+== Creating a \Regexp
+
+A regular expression may be created with:
+
+- A regexp literal using slash characters
+ (see {Regexp Literals}[rdoc-ref:syntax/literals.rdoc@Regexp+Literals]):
+
+ # This is a very common usage.
+ /foo/ # => /foo/
+
+- A <tt>%r</tt> regexp literal
+ (see {%r: Regexp Literals}[rdoc-ref:syntax/literals.rdoc@r-regexp+literals]):
+
+ # Same delimiter character at beginning and end;
+ # useful for avoiding escaping characters
+ %r/name\/value pair/ # => /name\/value pair/
+ %r:name/value pair: # => /name\/value pair/
+ %r|name/value pair| # => /name\/value pair/
+
+ # Certain "paired" characters can be delimiters.
+ %r[foo] # => /foo/
+ %r{foo} # => /foo/
+ %r(foo) # => /foo/
+ %r<foo> # => /foo/
+
+- Method Regexp.new.
+
+== Method <tt>match</tt>
+
+Each of the methods Regexp#match, String#match, and Symbol#match
+returns a MatchData object if a match was found, +nil+ otherwise;
+each also sets {global variables}[rdoc-ref:Regexp@Global+Variables]:
+
+ 'food'.match(/foo/) # => #<MatchData "foo">
+ 'food'.match(/bar/) # => nil
+
+== Operator <tt>=~</tt>
+
+Each of the operators Regexp#=~, String#=~, and Symbol#=~
+returns an integer offset if a match was found, +nil+ otherwise;
+each also sets {global variables}[rdoc-ref:Regexp@Global+Variables]:
+
+ /bar/ =~ 'foo bar' # => 4
+ 'foo bar' =~ /bar/ # => 4
+ /baz/ =~ 'foo bar' # => nil
+
+== Method <tt>match?</tt>
+
+Each of the methods Regexp#match?, String#match?, and Symbol#match?
+returns +true+ if a match was found, +false+ otherwise;
+none sets {global variables}[rdoc-ref:Regexp@Global+Variables]:
+
+ 'food'.match?(/foo/) # => true
+ 'food'.match?(/bar/) # => false
+
+== Global Variables
+
+Certain regexp-oriented methods assign values to global variables:
+
+- <tt>#match</tt>: see {Method match}[rdoc-ref:Regexp@Method+match].
+- <tt>#=~</tt>: see {Operator =~}[rdoc-ref:Regexp@Operator-].
+
+The affected global variables are:
+
+- <tt>$~</tt>: Returns a MatchData object, or +nil+.
+- <tt>$&</tt>: Returns the matched part of the string, or +nil+.
+- <tt>$`</tt>: Returns the part of the string to the left of the match, or +nil+.
+- <tt>$'</tt>: Returns the part of the string to the right of the match, or +nil+.
+- <tt>$+</tt>: Returns the last group matched, or +nil+.
+- <tt>$1</tt>, <tt>$2</tt>, etc.: Returns the first, second, etc.,
+ matched group, or +nil+.
+ Note that <tt>$0</tt> is quite different;
+ it returns the name of the currently executing program.
+
+These variables, except for <tt>$~</tt>, are shorthands for methods of
+<tt>$~</tt>. See MatchData@Global+variables+equivalence.
+
+Examples:
+
+ # Matched string, but no matched groups.
+ 'foo bar bar baz'.match('bar')
+ $~ # => #<MatchData "bar">
+ $& # => "bar"
+ $` # => "foo "
+ $' # => " bar baz"
+ $+ # => nil
+ $1 # => nil
+
+ # Matched groups.
+ /s(\w{2}).*(c)/.match('haystack')
+ $~ # => #<MatchData "stac" 1:"ta" 2:"c">
+ $& # => "stac"
+ $` # => "hay"
+ $' # => "k"
+ $+ # => "c"
+ $1 # => "ta"
+ $2 # => "c"
+ $3 # => nil
+
+ # No match.
+ 'foo'.match('bar')
+ $~ # => nil
+ $& # => nil
+ $` # => nil
+ $' # => nil
+ $+ # => nil
+ $1 # => nil
+
+Note that Regexp#match?, String#match?, and Symbol#match?
+do not set global variables.
+
+== Sources
+
+As seen above, the simplest regexp uses a literal expression as its source:
+
+ re = /foo/ # => /foo/
+ re.match('food') # => #<MatchData "foo">
+ re.match('good') # => nil
+
+A rich collection of available _subexpressions_
+gives the regexp great power and flexibility:
+
+- {Special characters}[rdoc-ref:Regexp@Special+Characters]
+- {Source literals}[rdoc-ref:Regexp@Source+Literals]
+- {Character classes}[rdoc-ref:Regexp@Character+Classes]
+- {Shorthand character classes}[rdoc-ref:Regexp@Shorthand+Character+Classes]
+- {Anchors}[rdoc-ref:Regexp@Anchors]
+- {Alternation}[rdoc-ref:Regexp@Alternation]
+- {Quantifiers}[rdoc-ref:Regexp@Quantifiers]
+- {Groups and captures}[rdoc-ref:Regexp@Groups+and+Captures]
+- {Unicode}[rdoc-ref:Regexp@Unicode]
+- {POSIX Bracket Expressions}[rdoc-ref:Regexp@POSIX+Bracket+Expressions]
+- {Comments}[rdoc-ref:Regexp@Comments]
+
+=== Special Characters
+
+\Regexp special characters, called _metacharacters_,
+have special meanings in certain contexts;
+depending on the context, these are sometimes metacharacters:
+
+ . ? - + * ^ \ | $ ( ) [ ] { }
+
+To match a metacharacter literally, backslash-escape it:
+
+ # Matches one or more 'o' characters.
+ /o+/.match('foo') # => #<MatchData "oo">
+ # Would match 'o+'.
+ /o\+/.match('foo') # => nil
+
+To match a backslash literally, backslash-escape it:
+
+ /\./.match('\.') # => #<MatchData ".">
+ /\\./.match('\.') # => #<MatchData "\\.">
+
+Method Regexp.escape returns an escaped string:
+
+ Regexp.escape('.?-+*^\|$()[]{}')
+ # => "\\.\\?\\-\\+\\*\\^\\\\\\|\\$\\(\\)\\[\\]\\{\\}"
+
+=== Source Literals
+
+The source literal largely behaves like a double-quoted string;
+see {Double-Quoted String Literals}[rdoc-ref:syntax/literals.rdoc@Double-Quoted+String+Literals].
+
+In particular, a source literal may contain interpolated expressions:
+
+ s = 'foo' # => "foo"
+ /#{s}/ # => /foo/
+ /#{s.capitalize}/ # => /Foo/
+ /#{2 + 2}/ # => /4/
+
+There are differences between an ordinary string literal and a source literal;
+see {Shorthand Character Classes}[rdoc-ref:Regexp@Shorthand+Character+Classes].
+
+- <tt>\s</tt> in an ordinary string literal is equivalent to a space character;
+ in a source literal, it's shorthand for matching a whitespace character.
+- In an ordinary string literal, these are (needlessly) escaped characters;
+ in a source literal, they are shorthands for various matching characters:
+
+ \w \W \d \D \h \H \S \R
+
+=== Character Classes
+
+A <i>character class</i> is delimited by square brackets;
+it specifies that certain characters match at a given point in the target string:
+
+ # This character class will match any vowel.
+ re = /B[aeiou]rd/
+ re.match('Bird') # => #<MatchData "Bird">
+ re.match('Bard') # => #<MatchData "Bard">
+ re.match('Byrd') # => nil
+
+A character class may contain hyphen characters to specify ranges of characters:
+
+ # These regexps have the same effect.
+ /[abcdef]/.match('foo') # => #<MatchData "f">
+ /[a-f]/.match('foo') # => #<MatchData "f">
+ /[a-cd-f]/.match('foo') # => #<MatchData "f">
+
+When the first character of a character class is a caret (<tt>^</tt>),
+the sense of the class is inverted: it matches any character _except_ those specified.
+
+ /[^a-eg-z]/.match('f') # => #<MatchData "f">
+
+A character class may contain another character class.
+By itself this isn't useful because <tt>[a-z[0-9]]</tt>
+describes the same set as <tt>[a-z0-9]</tt>.
+
+However, character classes also support the <tt>&&</tt> operator,
+which performs set intersection on its arguments.
+The two can be combined as follows:
+
+ /[a-w&&[^c-g]z]/ # ([a-w] AND ([^c-g] OR z))
+
+This is equivalent to:
+
+ /[abh-w]/
+
+=== Shorthand Character Classes
+
+Each of the following metacharacters serves as a shorthand
+for a character class:
+
+- <tt>/./</tt>: Matches any character except a newline:
+
+ /./.match('foo') # => #<MatchData "f">
+ /./.match("\n") # => nil
+
+- <tt>/./m</tt>: Matches any character, including a newline;
+ see {Multiline Mode}[rdoc-ref:Regexp@Multiline+Mode]:
+
+ /./m.match("\n") # => #<MatchData "\n">
+
+- <tt>/\w/</tt>: Matches a word character: equivalent to <tt>[a-zA-Z0-9_]</tt>:
+
+ /\w/.match(' foo') # => #<MatchData "f">
+ /\w/.match(' _') # => #<MatchData "_">
+ /\w/.match(' ') # => nil
+
+- <tt>/\W/</tt>: Matches a non-word character: equivalent to <tt>[^a-zA-Z0-9_]</tt>:
+
+ /\W/.match(' ') # => #<MatchData " ">
+ /\W/.match('_') # => nil
+
+- <tt>/\d/</tt>: Matches a digit character: equivalent to <tt>[0-9]</tt>:
+
+ /\d/.match('THX1138') # => #<MatchData "1">
+ /\d/.match('foo') # => nil
+
+- <tt>/\D/</tt>: Matches a non-digit character: equivalent to <tt>[^0-9]</tt>:
+
+ /\D/.match('123Jump!') # => #<MatchData "J">
+ /\D/.match('123') # => nil
+
+- <tt>/\h/</tt>: Matches a hexdigit character: equivalent to <tt>[0-9a-fA-F]</tt>:
+
+ /\h/.match('xyz fedcba9876543210') # => #<MatchData "f">
+ /\h/.match('xyz') # => nil
+
+- <tt>/\H/</tt>: Matches a non-hexdigit character: equivalent to <tt>[^0-9a-fA-F]</tt>:
+
+ /\H/.match('fedcba9876543210xyz') # => #<MatchData "x">
+ /\H/.match('fedcba9876543210') # => nil
+
+- <tt>/\s/</tt>: Matches a whitespace character: equivalent to <tt>/[ \t\r\n\f\v]/</tt>:
+
+ /\s/.match('foo bar') # => #<MatchData " ">
+ /\s/.match('foo') # => nil
+
+- <tt>/\S/</tt>: Matches a non-whitespace character: equivalent to <tt>/[^ \t\r\n\f\v]/</tt>:
+
+ /\S/.match(" \t\r\n\f\v foo") # => #<MatchData "f">
+ /\S/.match(" \t\r\n\f\v") # => nil
+
+- <tt>/\R/</tt>: Matches a linebreak, platform-independently:
+
+ /\R/.match("\r") # => #<MatchData "\r"> # Carriage return (CR)
+ /\R/.match("\n") # => #<MatchData "\n"> # Newline (LF)
+ /\R/.match("\f") # => #<MatchData "\f"> # Formfeed (FF)
+ /\R/.match("\v") # => #<MatchData "\v"> # Vertical tab (VT)
+ /\R/.match("\r\n") # => #<MatchData "\r\n"> # CRLF
+ /\R/.match("\u0085") # => #<MatchData "\u0085"> # Next line (NEL)
+ /\R/.match("\u2028") # => #<MatchData "\u2028"> # Line separator (LSEP)
+ /\R/.match("\u2029") # => #<MatchData "\u2029"> # Paragraph separator (PSEP)
+
+=== Anchors
+
+An anchor is a metasequence that matches a zero-width position between
+characters in the target string.
+
+For a subexpression with no anchor,
+matching may begin anywhere in the target string:
+
+ /real/.match('surrealist') # => #<MatchData "real">
+
+For a subexpression with an anchor,
+matching must begin at the matched anchor.
+
+==== Boundary Anchors
+
+Each of these anchors matches a boundary:
+
+- <tt>^</tt>: Matches the beginning of a line:
+
+ /^bar/.match("foo\nbar") # => #<MatchData "bar">
+ /^ar/.match("foo\nbar") # => nil
+
+- <tt>$</tt>: Matches the end of a line:
+
+ /bar$/.match("foo\nbar") # => #<MatchData "bar">
+ /ba$/.match("foo\nbar") # => nil
+
+- <tt>\A</tt>: Matches the beginning of the string:
+
+ /\Afoo/.match('foo bar') # => #<MatchData "foo">
+ /\Afoo/.match(' foo bar') # => nil
+
+- <tt>\Z</tt>: Matches the end of the string;
+ if string ends with a single newline,
+ it matches just before the ending newline:
+
+ /foo\Z/.match('bar foo') # => #<MatchData "foo">
+ /foo\Z/.match('foo bar') # => nil
+ /foo\Z/.match("bar foo\n") # => #<MatchData "foo">
+ /foo\Z/.match("bar foo\n\n") # => nil
+
+- <tt>\z</tt>: Matches the end of the string:
+
+ /foo\z/.match('bar foo') # => #<MatchData "foo">
+ /foo\z/.match('foo bar') # => nil
+ /foo\z/.match("bar foo\n") # => nil
+
+- <tt>\b</tt>: Matches word boundary when not inside brackets;
+ matches backspace (<tt>"0x08"</tt>) when inside brackets:
+
+ /foo\b/.match('foo bar') # => #<MatchData "foo">
+ /foo\b/.match('foobar') # => nil
+
+- <tt>\B</tt>: Matches non-word boundary:
+
+ /foo\B/.match('foobar') # => #<MatchData "foo">
+ /foo\B/.match('foo bar') # => nil
+
+- <tt>\G</tt>: Matches first matching position:
+
+ In methods like String#gsub and String#scan, it changes on each iteration.
+ It initially matches the beginning of subject, and in each following iteration it matches where the last match finished.
+
+ " a b c".gsub(/ /, '_') # => "____a_b_c"
+ " a b c".gsub(/\G /, '_') # => "____a b c"
+
+ In methods like Regexp#match and String#match
+ that take an optional offset, it matches where the search begins.
+
+ "hello, world".match(/,/, 3) # => #<MatchData ",">
+ "hello, world".match(/\G,/, 3) # => nil
+
+==== Lookaround Anchors
+
+Lookahead anchors:
+
+- <tt>(?=pat)</tt>: Positive lookahead assertion:
+ ensures that the following characters match _pat_,
+ but doesn't include those characters in the matched substring.
+
+- <tt>(?!pat)</tt>: Negative lookahead assertion:
+ ensures that the following characters <i>do not</i> match _pat_,
+ but doesn't include those characters in the matched substring.
+
+Lookbehind anchors:
+
+- <tt>(?<=pat)</tt>: Positive lookbehind assertion:
+ ensures that the preceding characters match _pat_, but
+ doesn't include those characters in the matched substring.
+
+- <tt>(?<!pat)</tt>: Negative lookbehind assertion:
+ ensures that the preceding characters do not match
+ _pat_, but doesn't include those characters in the matched substring.
+
+The pattern below uses positive lookahead and positive lookbehind to match
+text appearing in <tt><b></tt>...<tt></b></tt> tags
+without including the tags in the match:
+
+ /(?<=<b>)\w+(?=<\/b>)/.match("Fortune favors the <b>bold</b>.")
+ # => #<MatchData "bold">
+
+The pattern in lookbehind must be fixed-width.
+But top-level alternatives can be of various lengths.
+ex. (?<=a|bc) is OK. (?<=aaa(?:b|cd)) is not allowed.
+
+==== Match-Reset Anchor
+
+- <tt>\K</tt>: Match reset:
+ the matched content preceding <tt>\K</tt> in the regexp is excluded from the result.
+ For example, the following two regexps are almost equivalent:
+
+ /ab\Kc/.match('abc') # => #<MatchData "c">
+ /(?<=ab)c/.match('abc') # => #<MatchData "c">
+
+ These match same string and <tt>$&</tt> equals <tt>'c'</tt>,
+ while the matched position is different.
+
+ As are the following two regexps:
+
+ /(a)\K(b)\Kc/
+ /(?<=(?<=(a))(b))c/
+
+=== Alternation
+
+The vertical bar metacharacter (<tt>|</tt>) may be used within parentheses
+to express alternation:
+two or more subexpressions any of which may match the target string.
+
+Two alternatives:
+
+ re = /(a|b)/
+ re.match('foo') # => nil
+ re.match('bar') # => #<MatchData "b" 1:"b">
+
+Four alternatives:
+
+ re = /(a|b|c|d)/
+ re.match('shazam') # => #<MatchData "a" 1:"a">
+ re.match('cold') # => #<MatchData "c" 1:"c">
+
+Each alternative is a subexpression, and may be composed of other subexpressions:
+
+ re = /([a-c]|[x-z])/
+ re.match('bar') # => #<MatchData "b" 1:"b">
+ re.match('ooz') # => #<MatchData "z" 1:"z">
+
+Method Regexp.union provides a convenient way to construct
+a regexp with alternatives.
+
+=== Quantifiers
+
+A simple regexp matches one character:
+
+ /\w/.match('Hello') # => #<MatchData "H">
+
+An added _quantifier_ specifies how many matches are required or allowed:
+
+- <tt>*</tt> - Matches zero or more times:
+
+ /\w*/.match('')
+ # => #<MatchData "">
+ /\w*/.match('x')
+ # => #<MatchData "x">
+ /\w*/.match('xyz')
+ # => #<MatchData "xyz">
+
+- <tt>+</tt> - Matches one or more times:
+
+ /\w+/.match('') # => nil
+ /\w+/.match('x') # => #<MatchData "x">
+ /\w+/.match('xyz') # => #<MatchData "xyz">
+
+- <tt>?</tt> - Matches zero or one times:
+
+ /\w?/.match('') # => #<MatchData "">
+ /\w?/.match('x') # => #<MatchData "x">
+ /\w?/.match('xyz') # => #<MatchData "x">
+
+- <tt>{</tt>_n_<tt>}</tt> - Matches exactly _n_ times:
+
+ /\w{2}/.match('') # => nil
+ /\w{2}/.match('x') # => nil
+ /\w{2}/.match('xyz') # => #<MatchData "xy">
+
+- <tt>{</tt>_min_<tt>,}</tt> - Matches _min_ or more times:
+
+ /\w{2,}/.match('') # => nil
+ /\w{2,}/.match('x') # => nil
+ /\w{2,}/.match('xy') # => #<MatchData "xy">
+ /\w{2,}/.match('xyz') # => #<MatchData "xyz">
+
+- <tt>{,</tt>_max_<tt>}</tt> - Matches _max_ or fewer times:
+
+ /\w{,2}/.match('') # => #<MatchData "">
+ /\w{,2}/.match('x') # => #<MatchData "x">
+ /\w{,2}/.match('xyz') # => #<MatchData "xy">
+
+- <tt>{</tt>_min_<tt>,</tt>_max_<tt>}</tt> -
+ Matches at least _min_ times and at most _max_ times:
+
+ /\w{1,2}/.match('') # => nil
+ /\w{1,2}/.match('x') # => #<MatchData "x">
+ /\w{1,2}/.match('xyz') # => #<MatchData "xy">
+
+==== Greedy, Lazy, or Possessive Matching
+
+Quantifier matching may be greedy, lazy, or possessive:
+
+- In _greedy_ matching, as many occurrences as possible are matched
+ while still allowing the overall match to succeed.
+ Greedy quantifiers: <tt>*</tt>, <tt>+</tt>, <tt>?</tt>,
+ <tt>{min, max}</tt> and its variants.
+- In _lazy_ matching, the minimum number of occurrences are matched.
+ Lazy quantifiers: <tt>*?</tt>, <tt>+?</tt>, <tt>??</tt>,
+ <tt>{min, max}?</tt> and its variants.
+- In _possessive_ matching, once a match is found, there is no backtracking;
+ that match is retained, even if it jeopardises the overall match.
+ Possessive quantifiers: <tt>*+</tt>, <tt>++</tt>, <tt>?+</tt>.
+ Note that <tt>{min, max}</tt> and its variants do _not_ support possessive matching.
+
+More:
+
+- About greedy and lazy matching, see
+ {Choosing Minimal or Maximal Repetition}[https://www.oreilly.com/library/view/regular-expressions-cookbook/9780596802837/ch02s13.html].
+- About possessive matching, see
+ {Eliminate Needless Backtracking}[https://www.oreilly.com/library/view/regular-expressions-cookbook/9780596802837/ch02s14.html].
+
+=== Groups and Captures
+
+A simple regexp has (at most) one match:
+
+ re = /\d\d\d\d-\d\d-\d\d/
+ re.match('1943-02-04') # => #<MatchData "1943-02-04">
+ re.match('1943-02-04').size # => 1
+ re.match('foo') # => nil
+
+Adding one or more pairs of parentheses, <tt>(subexpression)</tt>,
+defines _groups_, which may result in multiple matched substrings,
+called _captures_:
+
+ re = /(\d\d\d\d)-(\d\d)-(\d\d)/
+ re.match('1943-02-04') # => #<MatchData "1943-02-04" 1:"1943" 2:"02" 3:"04">
+ re.match('1943-02-04').size # => 4
+
+The first capture is the entire matched string;
+the other captures are the matched substrings from the groups.
+
+A group may have a {quantifier}[rdoc-ref:Regexp@Quantifiers]:
+
+ re = /July 4(th)?/
+ re.match('July 4') # => #<MatchData "July 4" 1:nil>
+ re.match('July 4th') # => #<MatchData "July 4th" 1:"th">
+
+ re = /(foo)*/
+ re.match('') # => #<MatchData "" 1:nil>
+ re.match('foo') # => #<MatchData "foo" 1:"foo">
+ re.match('foofoo') # => #<MatchData "foofoo" 1:"foo">
+
+ re = /(foo)+/
+ re.match('') # => nil
+ re.match('foo') # => #<MatchData "foo" 1:"foo">
+ re.match('foofoo') # => #<MatchData "foofoo" 1:"foo">
+
+The returned \MatchData object gives access to the matched substrings:
+
+ re = /(\d\d\d\d)-(\d\d)-(\d\d)/
+ md = re.match('1943-02-04')
+ # => #<MatchData "1943-02-04" 1:"1943" 2:"02" 3:"04">
+ md[0] # => "1943-02-04"
+ md[1] # => "1943"
+ md[2] # => "02"
+ md[3] # => "04"
+
+==== Non-Capturing Groups
+
+A group may be made non-capturing;
+it is still a group (and, for example, can have a quantifier),
+but its matching substring is not included among the captures.
+
+A non-capturing group begins with <tt>?:</tt> (inside the parentheses):
+
+ # Don't capture the year.
+ re = /(?:\d\d\d\d)-(\d\d)-(\d\d)/
+ md = re.match('1943-02-04') # => #<MatchData "1943-02-04" 1:"02" 2:"04">
+
+==== Backreferences
+
+A group match may also be referenced within the regexp itself;
+such a reference is called a +backreference+:
+
+ /[csh](..) [csh]\1 in/.match('The cat sat in the hat')
+ # => #<MatchData "cat sat in" 1:"at">
+
+This table shows how each subexpression in the regexp above
+matches a substring in the target string:
+
+ | Subexpression in Regexp | Matching Substring in Target String |
+ |---------------------------|-------------------------------------|
+ | First '[csh]' | Character 'c' |
+ | '(..)' | First substring 'at' |
+ | First space ' ' | First space character ' ' |
+ | Second '[csh]' | Character 's' |
+ | '\1' (backreference 'at') | Second substring 'at' |
+ | ' in' | Substring ' in' |
+
+A regexp may contain any number of groups:
+
+- For a large number of groups:
+
+ - The ordinary <tt>\\n</tt> notation applies only for _n_ in range (1..9).
+ - The <tt>MatchData[n]</tt> notation applies for any non-negative _n_.
+
+- <tt>\0</tt> is a special backreference, referring to the entire matched string;
+ it may not be used within the regexp itself,
+ but may be used outside it (for example, in a substitution method call):
+
+ 'The cat sat in the hat'.gsub(/[csh]at/, '\0s')
+ # => "The cats sats in the hats"
+
+==== Named Captures
+
+As seen above, a capture can be referred to by its number.
+A capture can also have a name,
+prefixed as <tt>?<name></tt> or <tt>?'name'</tt>,
+and the name (symbolized) may be used as an index in <tt>MatchData[]</tt>:
+
+ md = /\$(?<dollars>\d+)\.(?'cents'\d+)/.match("$3.67")
+ # => #<MatchData "$3.67" dollars:"3" cents:"67">
+ md[:dollars] # => "3"
+ md[:cents] # => "67"
+ # The capture numbers are still valid.
+ md[2] # => "67"
+
+When a regexp contains a named capture, there are no unnamed captures:
+
+ /\$(?<dollars>\d+)\.(\d+)/.match("$3.67")
+ # => #<MatchData "$3.67" dollars:"3">
+
+A named group may be backreferenced as <tt>\k<name></tt>:
+
+ /(?<vowel>[aeiou]).\k<vowel>.\k<vowel>/.match('ototomy')
+ # => #<MatchData "ototo" vowel:"o">
+
+When (and only when) a regexp contains named capture groups
+and appears before the <tt>=~</tt> operator,
+the captured substrings are assigned to local variables with corresponding names:
+
+ /\$(?<dollars>\d+)\.(?<cents>\d+)/ =~ '$3.67'
+ dollars # => "3"
+ cents # => "67"
+
+Method Regexp#named_captures returns a hash of the capture names and substrings;
+method Regexp#names returns an array of the capture names.
+
+==== Atomic Grouping
+
+A group may be made _atomic_ with <tt>(?></tt>_subexpression_<tt>)</tt>.
+
+This causes the subexpression to be matched
+independently of the rest of the expression,
+so that the matched substring becomes fixed for the remainder of the match,
+unless the entire subexpression must be abandoned and subsequently revisited.
+
+In this way _subexpression_ is treated as a non-divisible whole.
+Atomic grouping is typically used to optimise patterns
+to prevent needless backtracking .
+
+Example (without atomic grouping):
+
+ /".*"/.match('"Quote"') # => #<MatchData "\"Quote\"">
+
+Analysis:
+
+1. The leading subexpression <tt>"</tt> in the pattern matches the first character
+ <tt>"</tt> in the target string.
+2. The next subexpression <tt>.*</tt> matches the next substring <tt>Quote"</tt>
+ (including the trailing double-quote).
+3. Now there is nothing left in the target string to match
+ the trailing subexpression <tt>"</tt> in the pattern;
+ this would cause the overall match to fail.
+4. The matched substring is backtracked by one position: <tt>Quote</tt>.
+5. The final subexpression <tt>"</tt> now matches the final substring <tt>"</tt>,
+ and the overall match succeeds.
+
+If subexpression <tt>.*</tt> is grouped atomically,
+the backtracking is disabled, and the overall match fails:
+
+ /"(?>.*)"/.match('"Quote"') # => nil
+
+Atomic grouping can affect performance;
+see {Atomic Group}[https://www.regular-expressions.info/atomic.html].
+
+==== Subexpression Calls
+
+As seen above, a backreference number (<tt>\\n</tt>) or name (<tt>\k<name></tt>)
+gives access to a captured _substring_;
+the corresponding regexp _subexpression_ may also be accessed,
+via the number n (<tt>\\gn</tt>) or name (<tt>\g<name></tt>):
+
+ /\A(?<paren>\(\g<paren>*\))*\z/.match('(())')
+ # ^1
+ # ^2
+ # ^3
+ # ^4
+ # ^5
+ # ^6
+ # ^7
+ # ^8
+ # ^9
+ # ^10
+
+The pattern:
+
+1. Matches at the beginning of the string, i.e. before the first character.
+2. Enters a named group +paren+.
+3. Matches the first character in the string, <tt>'('</tt>.
+4. Calls the +paren+ group again, i.e. recurses back to the second step.
+5. Re-enters the +paren+ group.
+6. Matches the second character in the string, <tt>'('</tt>.
+7. Attempts to call +paren+ a third time,
+ but fails because doing so would prevent an overall successful match.
+8. Matches the third character in the string, <tt>')'</tt>;
+ marks the end of the second recursive call
+9. Matches the fourth character in the string, <tt>')'</tt>.
+10. Matches the end of the string.
+
+See {Subexpression calls}[https://learnbyexample.github.io/Ruby_Regexp/groupings-and-backreferences.html#subexpression-calls].
+
+==== Conditionals
+
+The conditional construct takes the form <tt>(?(cond)yes|no)</tt>, where:
+
+- _cond_ may be a capture number or name.
+- The match to be applied is _yes_ if _cond_ is captured;
+ otherwise the match to be applied is _no_.
+- If not needed, <tt>|no</tt> may be omitted.
+
+Examples:
+
+ re = /\A(foo)?(?(1)(T)|(F))\z/
+ re.match('fooT') # => #<MatchData "fooT" 1:"foo" 2:"T" 3:nil>
+ re.match('F') # => #<MatchData "F" 1:nil 2:nil 3:"F">
+ re.match('fooF') # => nil
+ re.match('T') # => nil
+
+ re = /\A(?<xyzzy>foo)?(?(<xyzzy>)(T)|(F))\z/
+ re.match('fooT') # => #<MatchData "fooT" xyzzy:"foo">
+ re.match('F') # => #<MatchData "F" xyzzy:nil>
+ re.match('fooF') # => nil
+ re.match('T') # => nil
+
+
+==== Absence Operator
+
+The absence operator is a special group that matches anything which does _not_ match the contained subexpressions.
+
+ /(?~real)/.match('surrealist') # => #<MatchData "surrea">
+ /(?~real)ist/.match('surrealist') # => #<MatchData "ealist">
+ /sur(?~real)ist/.match('surrealist') # => nil
+
+=== Unicode
+
+==== Unicode Properties
+
+The <tt>/\p{property_name}/</tt> construct (with lowercase +p+)
+matches characters using a Unicode property name,
+much like a character class;
+property +Alpha+ specifies alphabetic characters:
+
+ /\p{Alpha}/.match('a') # => #<MatchData "a">
+ /\p{Alpha}/.match('1') # => nil
+
+A property can be inverted
+by prefixing the name with a caret character (<tt>^</tt>):
+
+ /\p{^Alpha}/.match('1') # => #<MatchData "1">
+ /\p{^Alpha}/.match('a') # => nil
+
+Or by using <tt>\P</tt> (uppercase +P+):
+
+ /\P{Alpha}/.match('1') # => #<MatchData "1">
+ /\P{Alpha}/.match('a') # => nil
+
+See {Unicode Properties}[rdoc-ref:language/regexp/unicode_properties.rdoc]
+for regexps based on the numerous properties.
+
+Some commonly-used properties correspond to POSIX bracket expressions:
+
+- <tt>/\p{Alnum}/</tt>: Alphabetic and numeric character
+- <tt>/\p{Alpha}/</tt>: Alphabetic character
+- <tt>/\p{Blank}/</tt>: Space or tab
+- <tt>/\p{Cntrl}/</tt>: Control character
+- <tt>/\p{Digit}/</tt>: Digit
+ characters, and similar)
+- <tt>/\p{Lower}/</tt>: Lowercase alphabetical character
+- <tt>/\p{Print}/</tt>: Like <tt>\p{Graph}</tt>, but includes the space character
+- <tt>/\p{Punct}/</tt>: Punctuation character
+- <tt>/\p{Space}/</tt>: Whitespace character (<tt>[:blank:]</tt>, newline,
+ carriage return, etc.)
+- <tt>/\p{Upper}/</tt>: Uppercase alphabetical
+- <tt>/\p{XDigit}/</tt>: Digit allowed in a hexadecimal number (i.e., 0-9a-fA-F)
+
+These are also commonly used:
+
+- <tt>/\p{Emoji}/</tt>: Unicode emoji.
+- <tt>/\p{Graph}/</tt>: Characters excluding <tt>/\p{Cntrl}/</tt> and <tt>/\p{Space}/</tt>.
+ Note that invisible characters under the Unicode
+ {"Format"}[https://www.compart.com/en/unicode/category/Cf] category are included.
+- <tt>/\p{Word}/</tt>: A member in one of these Unicode character
+ categories (see below) or having one of these Unicode properties:
+
+ - Unicode categories:
+ - +Mark+ (+M+).
+ - <tt>Decimal Number</tt> (+Nd+)
+ - <tt>Connector Punctuation</tt> (+Pc+).
+
+ - Unicode properties:
+ - +Alpha+
+ - <tt>Join_Control</tt>
+
+- <tt>/\p{ASCII}/</tt>: A character in the ASCII character set.
+- <tt>/\p{Any}/</tt>: Any Unicode character (including unassigned characters).
+- <tt>/\p{Assigned}/</tt>: An assigned character.
+
+==== Unicode Character Categories
+
+A Unicode character category name:
+
+- May be either its full name or its abbreviated name.
+- Is case-insensitive.
+- Treats a space, a hyphen, and an underscore as equivalent.
+
+Examples:
+
+ /\p{lu}/ # => /\p{lu}/
+ /\p{LU}/ # => /\p{LU}/
+ /\p{Uppercase Letter}/ # => /\p{Uppercase Letter}/
+ /\p{Uppercase_Letter}/ # => /\p{Uppercase_Letter}/
+ /\p{UPPERCASE-LETTER}/ # => /\p{UPPERCASE-LETTER}/
+
+Below are the Unicode character category abbreviations and names.
+Enumerations of characters in each category are at the links.
+
+Letters:
+
+- +L+, +Letter+: +LC+, +Lm+, or +Lo+.
+- +LC+, +Cased_Letter+: +Ll+, +Lt+, or +Lu+.
+- {Lu, Lowercase_Letter}[https://www.compart.com/en/unicode/category/Ll].
+- {Lu, Modifier_Letter}[https://www.compart.com/en/unicode/category/Lm].
+- {Lu, Other_Letter}[https://www.compart.com/en/unicode/category/Lo].
+- {Lu, Titlecase_Letter}[https://www.compart.com/en/unicode/category/Lt].
+- {Lu, Uppercase_Letter}[https://www.compart.com/en/unicode/category/Lu].
+
+Marks:
+
+- +M+, +Mark+: +Mc+, +Me+, or +Mn+.
+- {Mc, Spacing_Mark}[https://www.compart.com/en/unicode/category/Mc].
+- {Me, Enclosing_Mark}[https://www.compart.com/en/unicode/category/Me].
+- {Mn, Nonapacing_Mark}[https://www.compart.com/en/unicode/category/Mn].
+
+Numbers:
+
+- +N+, +Number+: +Nd+, +Nl+, or +No+.
+- {Nd, Decimal_Number}[https://www.compart.com/en/unicode/category/Nd].
+- {Nl, Letter_Number}[https://www.compart.com/en/unicode/category/Nl].
+- {No, Other_Number}[https://www.compart.com/en/unicode/category/No].
+
+Punctuation:
+
+- +P+, +Punctuation+: +Pc+, +Pd+, +Pe+, +Pf+, +Pi+, +Po+, or +Ps+.
+- {Pc, Connector_Punctuation}[https://www.compart.com/en/unicode/category/Pc].
+- {Pd, Dash_Punctuation}[https://www.compart.com/en/unicode/category/Pd].
+- {Pe, Close_Punctuation}[https://www.compart.com/en/unicode/category/Pe].
+- {Pf, Final_Punctuation}[https://www.compart.com/en/unicode/category/Pf].
+- {Pi, Initial_Punctuation}[https://www.compart.com/en/unicode/category/Pi].
+- {Po, Other_Punctuation}[https://www.compart.com/en/unicode/category/Po].
+- {Ps, Open_Punctuation}[https://www.compart.com/en/unicode/category/Ps].
+
+- +S+, +Symbol+: +Sc+, +Sk+, +Sm+, or +So+.
+- {Sc, Currency_Symbol}[https://www.compart.com/en/unicode/category/Sc].
+- {Sk, Modifier_Symbol}[https://www.compart.com/en/unicode/category/Sk].
+- {Sm, Math_Symbol}[https://www.compart.com/en/unicode/category/Sm].
+- {So, Other_Symbol}[https://www.compart.com/en/unicode/category/So].
+
+- +Z+, +Separator+: +Zl+, +Zp+, or +Zs+.
+- {Zl, Line_Separator}[https://www.compart.com/en/unicode/category/Zl].
+- {Zp, Paragraph_Separator}[https://www.compart.com/en/unicode/category/Zp].
+- {Zs, Space_Separator}[https://www.compart.com/en/unicode/category/Zs].
+
+- +C+, +Other+: +Cc+, +Cf+, +Cn+, +Co+, or +Cs+.
+- {Cc, Control}[https://www.compart.com/en/unicode/category/Cc].
+- {Cf, Format}[https://www.compart.com/en/unicode/category/Cf].
+- {Cn, Unassigned}[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].
+
+==== Unicode Scripts and Blocks
+
+Among the Unicode properties are:
+
+- {Unicode scripts}[https://en.wikipedia.org/wiki/Script_(Unicode)];
+ see {supported scripts}[https://www.unicode.org/standard/supported.html].
+- {Unicode blocks}[https://en.wikipedia.org/wiki/Unicode_block];
+ see {supported blocks}[http://www.unicode.org/Public/UNIDATA/Blocks.txt].
+
+=== POSIX Bracket Expressions
+
+A POSIX <i>bracket expression</i> is also similar to a character class.
+These expressions provide a portable alternative to the above,
+with the added benefit of encompassing non-ASCII characters:
+
+- <tt>/\d/</tt> matches only ASCII decimal digits +0+ through +9+.
+- <tt>/[[:digit:]]/</tt> matches any character in the Unicode
+ <tt>Decimal Number</tt> (+Nd+) category;
+ see below.
+
+The POSIX bracket expressions:
+
+- <tt>/[[:digit:]]/</tt>: Matches a {Unicode digit}[https://www.compart.com/en/unicode/category/Nd]:
+
+ /[[:digit:]]/.match('9') # => #<MatchData "9">
+ /[[:digit:]]/.match("\u1fbf9") # => #<MatchData "9">
+
+- <tt>/[[:xdigit:]]/</tt>: Matches a digit allowed in a hexadecimal number;
+ equivalent to <tt>[0-9a-fA-F]</tt>.
+
+- <tt>/[[:upper:]]/</tt>: Matches a {Unicode uppercase letter}[https://www.compart.com/en/unicode/category/Lu]:
+
+ /[[:upper:]]/.match('A') # => #<MatchData "A">
+ /[[:upper:]]/.match("\u00c6") # => #<MatchData "Æ">
+
+- <tt>/[[:lower:]]/</tt>: Matches a {Unicode lowercase letter}[https://www.compart.com/en/unicode/category/Ll]:
+
+ /[[:lower:]]/.match('a') # => #<MatchData "a">
+ /[[:lower:]]/.match("\u01fd") # => #<MatchData "ǽ">
+
+- <tt>/[[:alpha:]]/</tt>: Matches <tt>/[[:upper:]]/</tt> or <tt>/[[:lower:]]/</tt>.
+
+- <tt>/[[:alnum:]]/</tt>: Matches <tt>/[[:alpha:]]/</tt> or <tt>/[[:digit:]]/</tt>.
+
+- <tt>/[[:space:]]/</tt>: Matches {Unicode space character}[https://www.compart.com/en/unicode/category/Zs]:
+
+ /[[:space:]]/.match(' ') # => #<MatchData " ">
+ /[[:space:]]/.match("\u2005") # => #<MatchData " ">
+
+- <tt>/[[:blank:]]/</tt>: Matches <tt>/[[:space:]]/</tt> or tab character:
+
+ /[[:blank:]]/.match(' ') # => #<MatchData " ">
+ /[[:blank:]]/.match("\u2005") # => #<MatchData " ">
+ /[[:blank:]]/.match("\t") # => #<MatchData "\t">
+
+- <tt>/[[:cntrl:]]/</tt>: Matches {Unicode control character}[https://www.compart.com/en/unicode/category/Cc]:
+
+ /[[:cntrl:]]/.match("\u0000") # => #<MatchData "\u0000">
+ /[[:cntrl:]]/.match("\u009f") # => #<MatchData "\u009F">
+
+- <tt>/[[:graph:]]/</tt>: Matches any character
+ except <tt>/[[:space:]]/</tt> or <tt>/[[:cntrl:]]/</tt>.
+
+- <tt>/[[:print:]]/</tt>: Matches <tt>/[[:graph:]]/</tt> or space character.
+
+- <tt>/[[:punct:]]/</tt>: Matches any (Unicode punctuation character}[https://www.compart.com/en/unicode/category/Po]:
+
+Ruby also supports these (non-POSIX) bracket expressions:
+
+- <tt>/[[:ascii:]]/</tt>: Matches a character in the ASCII character set.
+- <tt>/[[:word:]]/</tt>: Matches a character in one of these Unicode character
+ categories or having one of these Unicode properties:
+
+ - Unicode categories:
+ - +Mark+ (+M+).
+ - <tt>Decimal Number</tt> (+Nd+)
+ - <tt>Connector Punctuation</tt> (+Pc+).
+
+ - Unicode properties:
+ - +Alpha+
+ - <tt>Join_Control</tt>
+
+=== Comments
+
+A comment may be included in a regexp pattern
+using the <tt>(?#</tt>_comment_<tt>)</tt> construct,
+where _comment_ is a substring that is to be ignored.
+arbitrary text ignored by the regexp engine:
+
+ /foo(?#Ignore me)bar/.match('foobar') # => #<MatchData "foobar">
+
+The comment may not include an unescaped terminator character.
+
+See also {Extended Mode}[rdoc-ref:Regexp@Extended+Mode].
+
+== Modes
+
+Each of these modifiers sets a mode for the regexp:
+
+- +i+: <tt>/pattern/i</tt> sets
+ {Case-Insensitive Mode}[rdoc-ref:Regexp@Case-Insensitive+Mode].
+- +m+: <tt>/pattern/m</tt> sets
+ {Multiline Mode}[rdoc-ref:Regexp@Multiline+Mode].
+- +x+: <tt>/pattern/x</tt> sets
+ {Extended Mode}[rdoc-ref:Regexp@Extended+Mode].
+- +o+: <tt>/pattern/o</tt> sets
+ {Interpolation Mode}[rdoc-ref:Regexp@Interpolation+Mode].
+
+Any, all, or none of these may be applied.
+
+Modifiers +i+, +m+, and +x+ may be applied to subexpressions:
+
+- <tt>(?modifier)</tt> turns the mode "on" for ensuing subexpressions
+- <tt>(?-modifier)</tt> turns the mode "off" for ensuing subexpressions
+- <tt>(?modifier:subexp)</tt> turns the mode "on" for _subexp_ within the group
+- <tt>(?-modifier:subexp)</tt> turns the mode "off" for _subexp_ within the group
+
+Example:
+
+ re = /(?i)te(?-i)st/
+ re.match('test') # => #<MatchData "test">
+ re.match('TEst') # => #<MatchData "TEst">
+ re.match('TEST') # => nil
+ re.match('teST') # => nil
+
+ re = /t(?i:e)st/
+ re.match('test') # => #<MatchData "test">
+ re.match('tEst') # => #<MatchData "tEst">
+ re.match('tEST') # => nil
+
+Method Regexp#options returns an integer whose value showing
+the settings for case-insensitivity mode, multiline mode, and extended mode.
+
+=== Case-Insensitive Mode
+
+By default, a regexp is case-sensitive:
+
+ /foo/.match('FOO') # => nil
+
+Modifier +i+ enables case-insensitive mode:
+
+ /foo/i.match('FOO')
+ # => #<MatchData "FOO">
+
+Method Regexp#casefold? returns whether the mode is case-insensitive.
+
+=== Multiline Mode
+
+The multiline-mode in Ruby is what is commonly called a "dot-all mode":
+
+- Without the +m+ modifier, the subexpression <tt>.</tt> does not match newlines:
+
+ /a.c/.match("a\nc") # => nil
+
+- With the modifier, it does match:
+
+ /a.c/m.match("a\nc") # => #<MatchData "a\nc">
+
+Unlike other languages, the modifier +m+ does not affect the anchors <tt>^</tt> and <tt>$</tt>.
+These anchors always match at line-boundaries in Ruby.
+
+=== Extended Mode
+
+Modifier +x+ enables extended mode, which means that:
+
+- Literal white space in the pattern is to be ignored.
+- Character <tt>#</tt> marks the remainder of its containing line as a comment,
+ which is also to be ignored for matching purposes.
+
+In extended mode, whitespace and comments may be used
+to form a self-documented regexp.
+
+Regexp not in extended mode (matches some Roman numerals):
+
+ pattern = '^M{0,3}(CM|CD|D?C{0,3})(XC|XL|L?X{0,3})(IX|IV|V?I{0,3})$'
+ re = /#{pattern}/
+ re.match('MCMXLIII') # => #<MatchData "MCMXLIII" 1:"CM" 2:"XL" 3:"III">
+
+Regexp in extended mode:
+
+ pattern = <<-EOT
+ ^ # beginning of string
+ M{0,3} # thousands - 0 to 3 Ms
+ (CM|CD|D?C{0,3}) # hundreds - 900 (CM), 400 (CD), 0-300 (0 to 3 Cs),
+ # or 500-800 (D, followed by 0 to 3 Cs)
+ (XC|XL|L?X{0,3}) # tens - 90 (XC), 40 (XL), 0-30 (0 to 3 Xs),
+ # or 50-80 (L, followed by 0 to 3 Xs)
+ (IX|IV|V?I{0,3}) # ones - 9 (IX), 4 (IV), 0-3 (0 to 3 Is),
+ # or 5-8 (V, followed by 0 to 3 Is)
+ $ # end of string
+ EOT
+ re = /#{pattern}/x
+ re.match('MCMXLIII') # => #<MatchData "MCMXLIII" 1:"CM" 2:"XL" 3:"III">
+
+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
+is encountered,
+the generated Regexp object is saved and used for all future evaluations
+of that literal regexp.
+Without modifier +o+, the generated Regexp is not saved,
+so each evaluation of the literal regexp generates a new Regexp object.
+
+Without modifier +o+:
+
+ def letters; sleep 5; /[A-Z][a-z]/; end
+ words = %w[abc def xyz]
+ start = Time.now
+ words.each {|word| word.match(/\A[#{letters}]+\z/) }
+ Time.now - start # => 15.0174892
+
+With modifier +o+:
+
+ start = Time.now
+ words.each {|word| word.match(/\A[#{letters}]+\z/o) }
+ Time.now - start # => 5.0010866
+
+Note that if the literal regexp does not have interpolations,
+the +o+ behavior is the default.
+
+== Encodings
+
+By default, a regexp with only US-ASCII characters has US-ASCII encoding:
+
+ re = /foo/
+ re.source.encoding # => #<Encoding:US-ASCII>
+ re.encoding # => #<Encoding:US-ASCII>
+
+A regular expression containing non-US-ASCII characters
+is assumed to use the source encoding.
+This can be overridden with one of the following modifiers.
+
+- <tt>/pat/n</tt>: US-ASCII if only containing US-ASCII characters,
+ otherwise ASCII-8BIT:
+
+ /foo/n.encoding # => #<Encoding:US-ASCII>
+ /foo\xff/n.encoding # => #<Encoding:ASCII-8BIT>
+ /foo\x7f/n.encoding # => #<Encoding:US-ASCII>
+
+- <tt>/pat/u</tt>: UTF-8
+
+ /foo/u.encoding # => #<Encoding:UTF-8>
+
+- <tt>/pat/e</tt>: EUC-JP
+
+ /foo/e.encoding # => #<Encoding:EUC-JP>
+
+- <tt>/pat/s</tt>: Windows-31J
+
+ /foo/s.encoding # => #<Encoding:Windows-31J>
+
+A regexp can be matched against a target string when either:
+
+- They have the same encoding.
+- The regexp's encoding is a fixed encoding and the string
+ contains only ASCII characters.
+ Method Regexp#fixed_encoding? returns whether the regexp
+ has a <i>fixed</i> encoding.
+
+If a match between incompatible encodings is attempted an
+<tt>Encoding::CompatibilityError</tt> exception is raised.
+
+Example:
+
+ re = eval("# encoding: ISO-8859-1\n/foo\\xff?/")
+ re.encoding # => #<Encoding:ISO-8859-1>
+ re =~ "foo".encode("UTF-8") # => 0
+ re =~ "foo\u0100" # Raises Encoding::CompatibilityError
+
+The encoding may be explicitly fixed by including Regexp::FIXEDENCODING
+in the second argument for Regexp.new:
+
+ # Regexp with encoding ISO-8859-1.
+ re = Regexp.new("a".force_encoding('iso-8859-1'), Regexp::FIXEDENCODING)
+ re.encoding # => #<Encoding:ISO-8859-1>
+ # Target string with encoding UTF-8.
+ s = "a\u3042"
+ s.encoding # => #<Encoding:UTF-8>
+ re.match(s) # Raises Encoding::CompatibilityError.
+
+== Timeouts
+
+When either a regexp source or a target string comes from untrusted input,
+malicious values could become a denial-of-service attack;
+to prevent such an attack, it is wise to set a timeout.
+
+\Regexp has two timeout values:
+
+- A class default timeout, used for a regexp whose instance timeout is +nil+;
+ this default is initially +nil+, and may be set by method Regexp.timeout=:
+
+ Regexp.timeout # => nil
+ Regexp.timeout = 3.0
+ Regexp.timeout # => 3.0
+
+- An instance timeout, which defaults to +nil+ and may be set in Regexp.new:
+
+ re = Regexp.new('foo', timeout: 5.0)
+ re.timeout # => 5.0
+
+When regexp.timeout is +nil+, the timeout "falls through" to Regexp.timeout;
+when regexp.timeout is non-+nil+, that value controls timing out:
+
+ | regexp.timeout Value | Regexp.timeout Value | Result |
+ |----------------------|----------------------|-----------------------------|
+ | nil | nil | Never times out. |
+ | nil | Float | Times out in Float seconds. |
+ | Float | Any | Times out in Float seconds. |
+
+== Optimization
+
+For certain values of the pattern and target string,
+matching time can grow polynomially or exponentially in relation to the input size;
+the potential vulnerability arising from this is the {regular expression denial-of-service}[https://en.wikipedia.org/wiki/ReDoS] (ReDoS) attack.
+
+\Regexp matching can apply an optimization to prevent ReDoS attacks.
+When the optimization is applied, matching time increases linearly (not polynomially or exponentially)
+in relation to the input size, and a ReDoS attack is not possible.
+
+This optimization is applied if the pattern meets these criteria:
+
+- No backreferences.
+- No subexpression calls.
+- No nested lookaround anchors or atomic groups.
+- No nested quantifiers with counting (i.e. no nested <tt>{n}</tt>,
+ <tt>{min,}</tt>, <tt>{,max}</tt>, or <tt>{min,max}</tt> style quantifiers)
+
+You can use method Regexp.linear_time? to determine whether a pattern meets these criteria:
+
+ Regexp.linear_time?(/a*/) # => true
+ Regexp.linear_time?('a*') # => true
+ Regexp.linear_time?(/(a*)\1/) # => false
+
+However, an untrusted source may not be safe even if the method returns +true+,
+because the optimization uses memoization (which may invoke large memory consumption).
+
+== References
+
+Read:
+
+- <i>Mastering Regular Expressions</i>
+ by Jeffrey E.F. Friedl.
+- <i>Regular Expressions Cookbook</i>
+ by Jan Goyvaerts & Steven Levithan.
+
+Explore, test:
+
+- {Rubular}[https://rubular.com/]: interactive online editor.
diff --git a/doc/_timezones.rdoc b/doc/_timezones.rdoc
new file mode 100644
index 0000000000..945654c163
--- /dev/null
+++ b/doc/_timezones.rdoc
@@ -0,0 +1,163 @@
+== Timezone Specifiers
+
+Certain +Time+ methods accept arguments that specify timezones:
+
+- Time.at: keyword argument +in:+.
+- Time.new: positional argument +zone+ or keyword argument +in:+.
+- Time.now: keyword argument +in:+.
+- Time#getlocal: positional argument +zone+.
+- Time#localtime: positional argument +zone+.
+
+The value given with any of these must be one of the following
+(each detailed below):
+
+- {Hours/minutes offset}[rdoc-ref:Time@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].
+- {Timezone name}[rdoc-ref:Time@Timezone+Names].
+
+=== Hours/Minutes Offsets
+
+The zone value may be a string offset from UTC
+in the form <tt>'+HH:MM'</tt> or <tt>'-HH:MM'</tt>,
+where:
+
+- +HH+ is the 2-digit hour in the range <tt>0..23</tt>.
+- +MM+ is the 2-digit minute in the range <tt>0..59</tt>.
+
+Examples:
+
+ t = Time.utc(2000, 1, 1, 20, 15, 1) # => 2000-01-01 20:15:01 UTC
+ Time.at(t, in: '-23:59') # => 1999-12-31 20:16:01 -2359
+ Time.at(t, in: '+23:59') # => 2000-01-02 20:14:01 +2359
+
+=== Single-Letter Offsets
+
+The zone value may be a letter in the range <tt>'A'..'I'</tt>
+or <tt>'K'..'Z'</tt>;
+see {List of military time zones}[https://en.wikipedia.org/wiki/List_of_military_time_zones]:
+
+ t = Time.utc(2000, 1, 1, 20, 15, 1) # => 2000-01-01 20:15:01 UTC
+ Time.at(t, in: 'A') # => 2000-01-01 21:15:01 +0100
+ Time.at(t, in: 'I') # => 2000-01-02 05:15:01 +0900
+ Time.at(t, in: 'K') # => 2000-01-02 06:15:01 +1000
+ Time.at(t, in: 'Y') # => 2000-01-01 08:15:01 -1200
+ Time.at(t, in: 'Z') # => 2000-01-01 20:15:01 UTC
+
+=== \Integer Offsets
+
+The zone value may be an integer number of seconds
+in the range <tt>-86399..86399</tt>:
+
+ t = Time.utc(2000, 1, 1, 20, 15, 1) # => 2000-01-01 20:15:01 UTC
+ Time.at(t, in: -86399) # => 1999-12-31 20:15:02 -235959
+ Time.at(t, in: 86399) # => 2000-01-02 20:15:00 +235959
+
+=== Timezone Objects
+
+The zone value may be an object responding to certain timezone methods, an
+instance of {Timezone}[https://github.com/panthomakos/timezone] and
+{TZInfo}[https://tzinfo.github.io] for example.
+
+The timezone methods are:
+
+- +local_to_utc+:
+
+ Called when Time.new is invoked with +tz+ as the value of positional
+ argument +zone+ or keyword argument +in:+.
+
+ Argument:: a {Time-like object}[rdoc-ref:Time@Time-Like+Objects].
+ Returns:: a {Time-like object}[rdoc-ref:Time@Time-Like+Objects] in the UTC timezone.
+
+- +utc_to_local+:
+
+ Called when Time.at or Time.now is invoked with +tz+ as the value for
+ keyword argument +in:+, and when Time#getlocal or Time#localtime is called
+ with +tz+ as the value for positional argument +zone+.
+
+ The UTC offset will be calculated as the difference between the
+ original time and the returned object as an +Integer+.
+ If the object is in fixed offset, its +utc_offset+ is also counted.
+
+ Argument:: a {Time-like object}[rdoc-ref:Time@Time-Like+Objects].
+ Returns:: a {Time-like object}[rdoc-ref:Time@Time-Like+Objects] in the local timezone.
+
+A custom timezone class may have these instance methods,
+which will be called if defined:
+
+- +abbr+:
+
+ Called when Time#strftime is invoked with a format involving <tt>%Z</tt>.
+
+ Argument:: a {Time-like object}[rdoc-ref:Time@Time-Like+Objects].
+ Returns:: a string abbreviation for the timezone name.
+
+- +dst?+:
+
+ Called when Time.at or Time.now is invoked with +tz+ as the value for
+ keyword argument +in:+, and when Time#getlocal or Time#localtime is
+ called with +tz+ as the value for positional argument +zone+.
+
+ Argument:: a {Time-like object}[rdoc-ref:Time@Time-Like+Objects].
+ Returns:: whether the time is daylight saving time.
+
+- +name+:
+
+ Called when <tt>Marshal.dump(t)</tt> is invoked
+
+ Argument:: none.
+ Returns:: the string name of the timezone.
+
+==== +Time+-Like Objects
+
+A +Time+-like object is a container object capable of interfacing with
+timezone libraries for timezone conversion.
+
+The argument to the timezone conversion methods above will have attributes
+similar to Time, except that timezone related attributes are meaningless.
+
+The objects returned by +local_to_utc+ and +utc_to_local+ methods of the
+timezone object may be of the same class as their arguments, of arbitrary
+object classes, or of class Integer.
+
+For a returned class other than +Integer+, the class must have the
+following methods:
+
+- +year+
+- +mon+
+- +mday+
+- +hour+
+- +min+
+- +sec+
+- +isdst+
+- +to_i+
+
+For a returned +Integer+, its components, decomposed in UTC, are
+interpreted as times in the specified timezone.
+
+=== Timezone Names
+
+If the class (the receiver of class methods, or the class of the receiver
+of instance methods) has +find_timezone+ singleton method, this method is
+called to achieve the corresponding timezone object from a timezone name.
+
+For example, using {Timezone}[https://github.com/panthomakos/timezone]:
+ class TimeWithTimezone < Time
+ require 'timezone'
+ def self.find_timezone(z) = Timezone[z]
+ end
+
+ TimeWithTimezone.now(in: "America/New_York") #=> 2023-12-25 00:00:00 -0500
+ TimeWithTimezone.new("2023-12-25 America/New_York") #=> 2023-12-25 00:00:00 -0500
+
+Or, using {TZInfo}[https://tzinfo.github.io]:
+ class TimeWithTZInfo < Time
+ require 'tzinfo'
+ def self.find_timezone(z) = TZInfo::Timezone.get(z)
+ end
+
+ TimeWithTZInfo.now(in: "America/New_York") #=> 2023-12-25 00:00:00 -0500
+ TimeWithTZInfo.new("2023-12-25 America/New_York") #=> 2023-12-25 00:00:00 -0500
+
+You can define this method per subclasses, or on the toplevel Time class.
diff --git a/doc/command_injection.rdoc b/doc/command_injection.rdoc
deleted file mode 100644
index af09be23f0..0000000000
--- a/doc/command_injection.rdoc
+++ /dev/null
@@ -1,29 +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.system
-- {\`command` (backtick method)}[rdoc-ref:Kernel#`]
- (also called by the expression <tt>%x[command]</tt>).
-- IO.popen(command).
-- IO.read(command).
-- IO.write(command).
-- IO.binread(command).
-- IO.binwrite(command).
-- IO.readlines(command).
-- IO.foreach(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/contributing.md b/doc/contributing.md
deleted file mode 100644
index a6c63de9b2..0000000000
--- a/doc/contributing.md
+++ /dev/null
@@ -1,12 +0,0 @@
-# Contributing to Ruby
-
-This guide outlines ways to get started with contributing to Ruby:
-
-* [Reporting issues](contributing/reporting_issues.md): How to report issues, how to request features, and how backporting works
-* [Building Ruby](contributing/building_ruby.md): How to build Ruby on your local machine for development
-* [Testing Ruby](contributing/testing_ruby.md): How to test Ruby on your local machine once you've built it
-* [Making changes to Ruby](contributing/making_changes_to_ruby.md): How to submit pull requests
- to change Ruby's documentation, code, test suite, or standard libraries
-* [Making changes to Ruby standard libraries](contributing/making_changes_to_stdlibs.md): How to build, test, and contribute to Ruby standard libraries
-* [Making changes to Ruby documentation](contributing/documentation_guide.md): How to make changes to Ruby documentation
-* [Benchmarking Ruby](https://github.com/ruby/ruby/tree/master/benchmark#make-benchmark): How to benchmark Ruby
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 8098b72927..a283a2f3db 100644
--- a/doc/contributing/building_ruby.md
+++ b/doc/contributing/building_ruby.md
@@ -8,98 +8,183 @@
For RubyGems, you will also need:
- * OpenSSL 1.1.x or 3.0.x / LibreSSL
- * libyaml 0.1.7 or later
- * zlib
+ * [OpenSSL] 1.1.x or 3.0.x / [LibreSSL]
+ * [libyaml] 0.1.7 or later
+ * [zlib]
If you want to build from the git repository, you will also need:
- * autoconf - 2.67 or later
- * bison - 3.0 or later
- * gperf - 3.1 or later
+ * [autoconf] - 2.67 or later
+ * [gperf] - 3.1 or later
* Usually unneeded; only if you edit some source files using gperf
- * ruby - 2.5 or later
- * We can upgrade this version to system ruby version of the latest Ubuntu LTS.
+ * ruby - 3.1 or later
+ * We can upgrade this version to system ruby version of the latest
+ Ubuntu LTS.
+ * git - 2.32 or later
+ * 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:
- * readline/editline (libedit, to build readline)
- * libffi (to build fiddle)
- * gmp (if you with to accelerate Bignum operations)
- * libexecinfo (FreeBSD)
- * rustc - 1.58.0 or later (if you wish to build [YJIT](/doc/yjit/yjit.md))
+ * [libffi] (to build fiddle)
+ * [gmp] (if you wish to accelerate Bignum operations)
+ * [rustc] - 1.58.0 or later, if you wish to build
+ [YJIT](rdoc-ref:RubyVM::YJIT).
- If you installed the libraries needed for extensions (openssl, readline, libyaml, zlib) into other than the OS default place,
- typically using Homebrew on macOS, add `--with-EXTLIB-dir` options to `CONFIGURE_ARGS` environment variable.
+ If you want to link the libraries (e.g., gmp) installed into other than
+ the OS default place, typically using Homebrew on macOS, pass the
+ `--with-opt-dir` (or `--with-gmp-dir` for gmp) option to `configure`.
- ``` shell
+ ```sh
+ configure --with-opt-dir=$(brew --prefix gmp):$(brew --prefix jemalloc)
+ ```
+
+ As for the libraries needed for particular extensions only and not for
+ Ruby (openssl, readline, libyaml, zlib), you can add `--with-EXTLIB-dir`
+ options to the command line or to `CONFIGURE_ARGS` environment variable.
+ The command line options will be embedded in `rbconfig.rb`, while the
+ latter environment variable is not embedded and is only used when
+ building the extension libraries.
+
+ ```sh
export CONFIGURE_ARGS=""
for ext in openssl readline libyaml zlib; do
CONFIGURE_ARGS="${CONFIGURE_ARGS} --with-$ext-dir=$(brew --prefix $ext)"
done
```
+[OpenSSL]: https://www.openssl.org
+[LibreSSL]: https://www.libressl.org
+[libyaml]: https://github.com/yaml/libyaml/
+[zlib]: https://www.zlib.net
+[autoconf]: https://www.gnu.org/software/autoconf/
+[gperf]: https://www.gnu.org/software/gperf/
+[libffi]: https://sourceware.org/libffi/
+[gmp]: https://gmplib.org
+[rustc]: https://www.rust-lang.org
+
## Quick start guide
1. Download ruby source code:
+ Select one of the below.
+
1. Build from the tarball:
- Download the latest tarball from [ruby-lang.org](https://www.ruby-lang.org/en/downloads/) and
- extract it. Example for Ruby 3.0.2:
+ Download the latest tarball from [Download Ruby] page and extract
+ it. Example for Ruby 3.0.2:
- ``` shell
- tar -xzf ruby-3.0.2.tar.gz
- cd ruby-3.0.2
- ```
+ ```sh
+ tar -xzf ruby-3.0.2.tar.gz
+ cd ruby-3.0.2
+ ```
2. Build from the git repository:
- Checkout the CRuby source code:
+ Checkout the CRuby source code:
- ``` shell
- git clone https://github.com/ruby/ruby.git
- ```
+ ```sh
+ git clone https://github.com/ruby/ruby.git
+ cd ruby
+ ```
- Generate the configure file:
+ Run the GNU Autoconf script (which generates the `configure` script):
- ``` shell
- ./autogen.sh
- ```
+ ```sh
+ ./autogen.sh
+ ```
-2. Create a `build` directory separate from the source directory:
+2. Create a `build` directory inside the repository directory:
- ``` shell
+ ```sh
mkdir build && cd build
```
- While it's not necessary to build in a separate directory, it's good practice to do so.
+ While it's not necessary to build in a dedicated directory like this, it's good
+ practice to do so.
-3. We'll install Ruby in `~/.rubies/ruby-master`, so create the directory:
+3. We'll eventually install our new Ruby in `~/.rubies/ruby-master`, so we'll create that directory:
- ``` shell
+ ```sh
mkdir ~/.rubies
```
-4. Run configure:
+4. Run the `configure` script (which generates the `Makefile`):
- ``` shell
+ ```sh
../configure --prefix="${HOME}/.rubies/ruby-master"
```
- - If you are frequently building Ruby, add the `--disable-install-doc` flag to not build documentation which will speed up the build process.
+ - Also `-C` (or `--config-cache`) would reduce time to configure from the
+ next time.
5. Build Ruby:
- ``` shell
- make install
+ ```sh
+ make
```
6. [Run tests](testing_ruby.md) to confirm your build succeeded.
+7. Install our newly-compiled Ruby into `~/.rubies/ruby-master`:
+
+ ```sh
+ make install
+ ```
+
+ - If you need to run `make install` with `sudo` and want to avoid document
+ generation with different permissions, you can use `make SUDO=sudo
+ install`.
+
+8. You can then try your new Ruby out, for example:
+
+ ```sh
+ ~/.rubies/ruby-master/bin/ruby -e "puts 'Hello, World!'"
+ ```
+
+By the end, your repo will look like this:
+
+```text
+ruby
+├── autogen.sh # Pre-existing Autoconf script, used in step 1
+├── configure # Generated in step 1, which generates the `Makefile` in step 4
+├── build # Created in step 2 and populated in step 4
+│ ├── GNUmakefile # Generated by `../configure`
+│ ├── Makefile # Generated by `../configure`
+│ ├── object.o # Compiled object file, built by `make`
+│ └── ... other compiled `.o` object files
+│
+│ # Other interesting files:
+├── include
+│ └── ruby.h # The main public header
+├── internal
+│ ├── object.h
+│ └── ... other header files used by the `.c` files in the repo root.
+├── lib
+│ └── # Default gems, like `bundler`, `erb`, `set`, `yaml`, etc.
+├── spec
+│ └── # A mirror of the Ruby specification from github.com/ruby/spec
+├── test
+│ ├── ruby
+│ └── ...
+├── object.c
+└── ... other `.c` files
+```
+
+[Download Ruby]: https://www.ruby-lang.org/en/downloads/
+
### Unexplainable Build Errors
-If you are having unexplainable build errors, after saving all your work, try running `git clean -xfd` in the source root to remove all git ignored local files. If you are working from a source directory that's been updated several times, you may have temporary build artifacts from previous releases which can cause build failures.
+If you are having unexplainable build errors, after saving all your work, try
+running `git clean -xfd` in the source root to remove all git ignored local
+files. If you are working from a source directory that's been updated several
+times, you may have temporary build artifacts from previous releases which can
+cause build failures.
+
+## Building on Windows
+
+The documentation for building on Windows can be found in [the separated
+file](../distribution/windows.md).
## More details
@@ -108,18 +193,21 @@ about Ruby's build to help out.
### Running make scripts in parallel
-In GNU make and BSD make implementations, to run a specific make script in parallel, pass the flag `-j<number of processes>`. For instance,
-to run tests on 8 processes, use:
+In GNU make[^caution-gmake-3] and BSD make implementations, to run a specific make script in
+parallel, pass the flag `-j<number of processes>`. For instance, to run tests
+on 8 processes, use:
-``` shell
+```sh
make test-all -j8
```
We can also set `MAKEFLAGS` to run _all_ `make` commands in parallel.
-Having the right `--jobs` flag will ensure all processors are utilized when building software projects. To do this effectively, you can set `MAKEFLAGS` in your shell configuration/profile:
+Having the right `--jobs` flag will ensure all processors are utilized when
+building software projects. To do this effectively, you can set `MAKEFLAGS` in
+your shell configuration/profile:
-``` shell
+```sh
# On macOS with Fish shell:
export MAKEFLAGS="--jobs "(sysctl -n hw.ncpu)
@@ -133,20 +221,25 @@ export MAKEFLAGS="--jobs "(nproc)
export MAKEFLAGS="--jobs $(nproc)"
```
+[^caution-gmake-3]: **CAUTION**: GNU make 3 is missing some features for parallel execution, we
+recommend to upgrade to GNU make 4 or later.
+
### Miniruby vs Ruby
-Miniruby is a version of Ruby which has no external dependencies and lacks certain features.
-It can be useful in Ruby development because it allows for faster build times. Miniruby is
-built before Ruby. A functional Miniruby is required to build Ruby. To build Miniruby:
+Miniruby is a version of Ruby which has no external dependencies and lacks
+certain features. It can be useful in Ruby development because it allows for
+faster build times. Miniruby is built before Ruby. A functional Miniruby is
+required to build Ruby. To build Miniruby:
-``` shell
+```sh
make miniruby
```
## Debugging
-You can use either lldb or gdb for debugging. Before debugging, you need to create a `test.rb`
-with the Ruby script you'd like to run. You can use the following make targets:
+You can use either lldb or gdb for debugging. Before debugging, you need to
+create a `test.rb` with the Ruby script you'd like to run. You can use the
+following make targets:
* `make run`: Runs `test.rb` using Miniruby
* `make lldb`: Runs `test.rb` using Miniruby in lldb
@@ -155,25 +248,92 @@ with the Ruby script you'd like to run. You can use the following make targets:
* `make lldb-ruby`: Runs `test.rb` using Ruby in lldb
* `make gdb-ruby`: Runs `test.rb` using Ruby in gdb
+For VS Code users, you can set up editor-based debugging experience by running:
+
+```shell
+cp -r misc/.vscode .vscode
+```
+
+This will add launch configurations for debugging Ruby itself by running `test.rb` with `lldb`.
+
+**Note**: if you build Ruby under the `./build` folder, you'll need to update `.vscode/launch.json`'s program entry accordingly to: `"${workspaceFolder}/build/ruby"`
+
+### Compiling for Debugging
+
+You can compile Ruby with the `RUBY_DEBUG` macro to enable debugging on some
+features. One example is debugging object shapes in Ruby with
+`RubyVM::Shape.of(object)`.
+
+Additionally Ruby can be compiled to support the `RUBY_DEBUG` environment
+variable to enable debugging on some features. An example is using
+`RUBY_DEBUG=gc_stress` to debug GC-related issues.
+
+There is also support for the `RUBY_DEBUG_LOG` environment variable to log a
+lot of information about what the VM is doing, via the `USE_RUBY_DEBUG_LOG`
+macro.
+
+You should also configure Ruby without optimization and other flags that may
+interfere with debugging by changing the optimization flags.
+
+Bringing it all together:
+
+```sh
+./configure cppflags="-DRUBY_DEBUG=1 -DUSE_RUBY_DEBUG_LOG=1" --enable-debug-env optflags="-O0 -fno-omit-frame-pointer"
+```
+
### Building with Address Sanitizer
-Using the address sanitizer is a great way to detect memory issues.
+Using the address sanitizer (ASAN) is a great way to detect memory issues. It
+can detect memory safety issues in Ruby itself, and also in any C extensions
+compiled with and loaded into a Ruby compiled with ASAN.
-``` shell
+```sh
./autogen.sh
mkdir build && cd build
-export ASAN_OPTIONS="halt_on_error=0:use_sigaltstack=0:detect_leaks=0"
-../configure cppflags="-fsanitize=address -fno-omit-frame-pointer" optflags=-O0 LDFLAGS="-fsanitize=address -fno-omit-frame-pointer"
+../configure CC=clang-18 cflags="-fsanitize=address -fno-omit-frame-pointer -DUSE_MN_THREADS=0" # and any other options you might like
make
```
-On Linux it is important to specify `-O0` when debugging. This is especially true for ASAN which sometimes works incorrectly at higher optimisation levels.
+The compiled Ruby will now automatically crash with a report and a backtrace
+if ASAN detects a memory safety issue. To run Ruby's test suite under ASAN,
+issue the following command. Note that this will take quite a long time (over
+two hours on my laptop); the `RUBY_TEST_TIMEOUT_SCALE` and
+`SYNTAX_SUGEST_TIMEOUT` variables are required to make sure tests don't
+spuriously fail with timeouts when in fact they're just slow.
+
+```sh
+RUBY_TEST_TIMEOUT_SCALE=5 SYNTAX_SUGGEST_TIMEOUT=600 make check
+```
+
+Please note, however, the following caveats!
+
+* Due to [Bug #20243], Clang generates code for threadlocal variables which
+ doesn't work with M:N threading. Thus, it's necessary to disable M:N
+ threading support at build time for now (with the `-DUSE_MN_THREADS=0`
+ configure argument).
+* ASAN will only work when using Clang version 18 or later - it requires
+ [llvm/llvm-project#75290] related to multithreaded `fork`.
+* ASAN has only been tested so far with Clang on Linux. It may or may not work
+ with other compilers or on other platforms - please file an issue on
+ [Ruby Issue Tracking System] if you run into problems with such configurations
+ (or, to report that they actually work properly!)
+* In particular, although I have not yet tried it, I have reason to believe
+ ASAN will _not_ work properly on macOS yet - the fix for the multithreaded
+ fork issue was actually reverted for macOS (see [llvm/llvm-project#75659]).
+ Please open an issue on [Ruby Issue Tracking System] if this is a problem for
+ you.
+
+[Revision 9d0a5148]: https://bugs.ruby-lang.org/projects/ruby-master/repository/git/revisions/9d0a5148ae062a0481a4a18fbeb9cfd01dc10428
+[Bug #20243]: https://bugs.ruby-lang.org/issues/20243
+[llvm/llvm-project#75290]: https://github.com/llvm/llvm-project/pull/75290
+[llvm/llvm-project#75659]: https://github.com/llvm/llvm-project/pull/75659#issuecomment-1861584777
+[Ruby Issue Tracking System]: https://bugs.ruby-lang.org
## How to measure coverage of C and Ruby code
You need to be able to use gcc (gcov) and lcov visualizer.
-``` shell
+```sh
./autogen.sh
./configure --enable-gcov
make
@@ -184,11 +344,12 @@ make lcov
open lcov-out/index.html
```
-If you need only C code coverage, you can remove `COVERAGE=true` from the above process.
-You can also use `gcov` command directly to get per-file coverage.
+If you need only C code coverage, you can remove `COVERAGE=true` from the
+above process. You can also use `gcov` command directly to get per-file
+coverage.
-If you need only Ruby code coverage, you can remove `--enable-gcov`.
-Note that `test-coverage.dat` accumulates all runs of `make test-all`.
-Make sure that you remove the file if you want to measure one test run.
+If you need only Ruby code coverage, you can remove `--enable-gcov`. Note
+that `test-coverage.dat` accumulates all runs of `make test-all`. Make sure
+that you remove the file if you want to measure one test run.
You can see the coverage result of CI: https://rubyci.org/coverage
diff --git a/doc/contributing/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/contributing.md b/doc/contributing/contributing.md
new file mode 100644
index 0000000000..a2ed00ab90
--- /dev/null
+++ b/doc/contributing/contributing.md
@@ -0,0 +1,35 @@
+# Contributing to Ruby
+
+## Ruby Issues
+
+To report an issue in the Ruby core:
+
+* [Report issues](reporting_issues.md).
+
+## Ruby Core
+
+To contribute to the Ruby core functionality,
+you'll need initially to:
+
+* [Build Ruby](building_ruby.md) on your system.
+* [Test Ruby](testing_ruby.md), to make sure the build is correct.
+
+Then:
+
+* [Make changes to Ruby](making_changes_to_ruby.md).
+
+And possibly:
+
+* [Benchmark Ruby](https://github.com/ruby/ruby/tree/master/benchmark#make-benchmark).
+
+## Ruby Documentation
+
+To contribute to the Ruby core documentation, see:
+
+* [Making changes to the Ruby documentation](documentation_guide.md).
+
+## Ruby Standard Library
+
+To contribute to the Ruby Standard Library, see:
+
+* [Making changes to the Ruby Standard Library](making_changes_to_stdlibs.md).
diff --git a/doc/contributing/documentation_guide.md b/doc/contributing/documentation_guide.md
index 907d935de9..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](rdoc-ref:RDoc::Markup).
+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,9 +20,18 @@ build directory:
make html
```
-Then you can preview your changes by opening
-`{build folder}/.ext/html/index.html` file in your browser.
+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.
## Goal
@@ -41,16 +50,14 @@ 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 [headers](rdoc-ref:RDoc::Markup@Headers).
-- Refer to authoritative and relevant sources using
- [links](rdoc-ref:RDoc::Markup@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](rdoc-ref:RDoc::Markup@Simple+Lists).
+ - Excessive comma-separated phrases; consider a [list][lists].
- Idioms and culture-specific references.
- - Overuse of headers.
+ - Overuse of headings.
- Using US-ASCII-incompatible characters in C source files;
see [Characters](#label-Characters) below.
@@ -59,7 +66,7 @@ Use your judgment about what the user needs to know.
Use only US-ASCII-compatible characters in a C source file.
(If you use other characters, the Ruby CI will gently let you know.)
-If want to put ASCII-incompatible characters into the documentation
+If you want to put ASCII-incompatible characters into the documentation
for a C-coded class, module, or method, there are workarounds
involving new files `doc/*.rdoc`:
@@ -72,7 +79,7 @@ involving new files `doc/*.rdoc`:
class Foo; end
```
-- Similarly, for module `Bar` (defined in file `bar.c`,
+- Similarly, for module `Bar` (defined in file `bar.c`),
create file `doc/bar.rdoc`, declare `module Bar; end`,
and place the module documentation above that declaration:
@@ -92,7 +99,7 @@ involving new files `doc/*.rdoc`:
Example:
- ```
+ ```c
/*
* call-seq:
* each_byte {|byte| ... } -> self
@@ -103,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](rdoc-ref:RDoc::Markup@RDoc+Markup+Reference).
+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.
@@ -124,17 +131,22 @@ a.shuffle! #=> [2, 3, 1]
a #=> [2, 3, 1]
```
-### Headers
+### Headings
+
+Organize a long discussion for a class or module with [headings].
-Organize a long discussion with [headers](rdoc-ref:RDoc::Markup@Headers).
+Do not use formal headings in the documentation for a method or constant.
+
+In the rare case where heading-like structures are needed
+within the documentation for a method or constant,
+use [bold text] as pseudo-headings.
### Blank Lines
A blank line begins a new paragraph.
-A [code block](rdoc-ref:RDoc::Markup@Paragraphs+and+Verbatim)
-or [list](rdoc-ref:RDoc::Markup@Simple+Lists)
-should be preceded by and followed by a blank line.
+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
@@ -150,19 +162,170 @@ For a method name in text:
or a hash mark for an instance method:
<tt>Foo.bar</tt>, <tt>Foo#baz</tt>.
+### Embedded Code and Commands
+
+Code or commands embedded in running text (i.e., not in a code block)
+should marked up as
+[monofont].
+
+Code that is a simple string should include the quote marks.
+
### Auto-Linking
-In general, \RDoc's auto-linking should not be suppressed.
-For example, we should write `Array`, not `\Array`.
+Most often, the name of a class, module, or method
+is auto-linked:
+
+```rdoc
+- Float.
+- Enumerable.
+- File.new
+- File#read.
+```
+
+renders as:
+
+> - Float.
+> - Enumerable.
+> - File.new
+> - File#read.
+
+In general, RDoc's auto-linking should not be suppressed.
+For example, we should write just plain _Float_ (which is auto-linked):
+
+```rdoc
+Returns a Float.
+```
+
+which renders as:
+
+> Returns a Float.
+
+However, _do_ suppress auto-linking when the word in question
+does not refer to a Ruby entity (e.g., some uses of _Class_ or _English_):
+
+```rdoc
+Class variables can be tricky.
+```
+
+renders as:
+
+> Class variables can be tricky.
+
+Also, _do_ suppress auto-linking when the word in question
+refers to the current document
+(e.g., _Float_ in the documentation for class Float).
+
+In this case you may consider forcing the name to
+[monofont],
+which suppresses auto-linking, and also emphasizes that the word is a class name:
+
+```rdoc
+A +Float+ object represents ....
+```
+
+renders as:
+
+> A `Float` object represents ....
+
+For a _very_ few, _very_ often-discussed classes,
+you might consider avoiding the capitalized class name altogether.
+For example, for some mentions of arrays,
+you might write simply the lowercase _array_.
+
+Instead of:
+
+```rdoc
+For an empty Array, ....
+```
+
+which renders as:
+
+> For an empty Array, ....
+
+you might write:
+
+```rdoc
+For an empty array, ....
+```
+
+which renders as:
+
+> For an empty array, ....
+
+This more casual usage avoids both auto-linking and distracting font changes,
+and is unlikely to cause confusion.
+
+This principle may be usefully applied, in particular, for:
+
+- An array.
+- An integer.
+- A hash.
+- A string.
+
+However, it should be applied _only_ when referring to an _instance_ of the class,
+and _never_ when referring to the class itself.
+
+### Explicit Links
-We might consider whether to suppress when:
+When writing an explicit link, follow these guidelines.
-- The word in question does not refer to a Ruby entity
- (e.g., some uses of _Class_ or _English_).
-- The reference is to the current class document
- (e.g., _Array_ in the documentation for class `Array`).
-- The same reference is repeated many times
- (e.g., _RDoc_ on this page).
+#### `rdoc-ref` Scheme
+
+Use the `rdoc-ref` scheme for:
+
+- A link in core documentation to other core documentation.
+- A link in core documentation to documentation in a standard library package.
+- A link in a standard library package to other documentation in that same
+ standard library package.
+
+See section "`rdoc-ref` Scheme" in [links].
+
+#### URL-Based Link
+
+Use a full URL-based link for:
+
+- A link in standard library documentation to documentation in the core.
+- A link in standard library documentation to documentation in a different
+ standard library package.
+
+Doing so ensures that the link will be valid even when the package documentation
+is built independently (separately from the core documentation).
+
+The link should lead to a target in https://docs.ruby-lang.org/en/master/.
+
+Also use a full URL-based link for a link to an off-site document.
+
+#### 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`).
### HTML Tags
@@ -175,16 +338,30 @@ may not render them properly.
In particular, avoid building tables with HTML tags
(<tt><table></tt>, etc.).
-Alternatives are:
+Alternatives:
+
+- A [verbatim text block][verbatim text blocks],
+ using spaces and punctuation to format the text;
+ note that [text markup][text markup] will not be honored:
-- The GFM (GitHub Flavored Markdown) table extension,
- which is enabled by default. See
- {GFM tables extension}[https://github.github.com/gfm/#tables-extension-].
+ - Example {source}[https://github.com/ruby/ruby/blob/34d802f32f00df1ac0220b62f72605827c16bad8/file.c#L6570-L6596].
+ - Corresponding {output}[rdoc-ref:File@ReadWrite+Mode].
-- A {verbatim text block}[rdoc-ref:RDoc::MarkupReference@Verbatim+Text+Blocks],
- using spaces and punctuation to format the text.
- Note that {text markup}[rdoc-ref:RDoc::MarkupReference@Text+Markup]
- will not be honored.
+- (Markdown format only): A {Github Flavored Markdown (GFM) table}[https://github.github.com/gfm/#tables-extension-],
+ using special formatting for the text:
+
+ - Example {source}[https://github.com/ruby/ruby/blob/34d802f32f00df1ac0220b62f72605827c16bad8/doc/contributing/glossary.md?plain=1].
+ - Corresponding {output}[https://docs.ruby-lang.org/en/master/contributing/glossary_md.html].
+
+### 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
@@ -214,19 +391,21 @@ Guidelines:
- The section title is `What's Here`.
- Consider listing the parent class and any included modules; consider
- [links](rdoc-ref:RDoc::Markup@Links)
- to their "What's Here" sections if those exist.
-- List methods as a bullet list:
+ [links] to their "What's Here" sections if those exist.
+- All methods mentioned in the left-pane table of contents
+ should be listed (including any methods extended from another class).
+- Attributes (which are not included in the TOC) may also be listed.
+- Display methods as items in one or more bullet lists:
- Begin each item with the method name, followed by a colon
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](rdoc-ref:RDoc::Markup@Links).
+ [link][links].
-- If there are numerous entries, consider grouping them into subsections with headers.
+- If there are numerous entries, consider grouping them into subsections with headings.
- If there are more than a few such subsections,
consider adding a table of contents just below the main section title.
@@ -238,6 +417,7 @@ The general structure of the method documentation should be:
- Calling sequence (for methods written in C).
- Synopsis (short description).
+- In-brief examples (optional)
- Details and examples.
- Argument description (if necessary).
- Corner cases and exceptions.
@@ -245,21 +425,21 @@ 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:`](rdoc-ref:RDoc::Markup@Method+arguments).
+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:
-```
+```rdoc
class_name.method_name(method_args) {|block_args| ... } -> return_type
```
Example:
-```
+```rdoc
* call-seq:
* Hash.new(default_value = nil) -> new_hash
* Hash.new {|hash, key| ... } -> new_hash
@@ -268,23 +448,32 @@ Example:
For an instance method, use the form
(omitting any prefix, just as RDoc does for a Ruby-coded method):
-```
+```rdoc
method_name(method_args) {|block_args| ... } -> return_type
```
+
For example, in Array, use:
-```
+```rdoc
* call-seq:
* count -> integer
* count(obj) -> integer
* count {|element| ... } -> integer
```
-```
-* call-seq:
+```rdoc
+* call-seq:
* <=> other -> -1, 0, 1, or nil
```
+For a binary-operator style method (e.g., Array#&),
+cite `self` in the call-seq (not, e.g., `array` or `receiver`):
+
+```rdoc
+* call-seq:
+* self & other_array -> new_array
+```
+
Arguments:
- If the method does not accept arguments, omit the parentheses.
@@ -296,15 +485,17 @@ Arguments:
or an explicit argument, use a `call-seq` with optional arguments.
For example, use:
- ```
- respond_to?(symbol, include_all = false) -> true or false
+ ```rdoc
+ * call-seq:
+ * respond_to?(symbol, include_all = false) -> true or false
```
- If the behavior is different with an omitted or an explicit argument,
use a `call-seq` with separate lines.
For example, in Enumerable, use:
- ```
+ ```rdoc
+ * call-seq:
* max -> element
* max(n) -> array
```
@@ -314,15 +505,23 @@ Block:
- If the method does not accept a block, omit the block.
- If the method accepts a block, the `call-seq` should have `{|args| ... }`,
not `{|args| block }` or `{|args| code }`.
+- If the method accepts a block, but returns an Enumerator when the block is omitted,
+ the `call-seq` should show both forms:
+
+ ```rdoc
+ * call-seq:
+ * array.select {|element| ... } -> new_array
+ * array.select -> new_enumerator
+ ```
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 an only if the object is not +self+;
+ prefix `new_` if and only if the object is not `self`;
example: `new_array`.
Aliases:
@@ -342,14 +541,22 @@ an entire paragraph.
For `Array#count`, the synopsis is:
-```
-Returns a count of specified elements.
-```
+> Returns a count of specified elements.
This is great as it is short and descriptive. Avoid documenting
too much in the synopsis, stick to the most important information
for the benefit of the reader.
+### In-Brief Examples
+
+For a method whose documentation is lengthy,
+consider adding an "in-brief" passage,
+showing examples that summarize the method's uses.
+
+The passage may answer some users' questions
+(without their having to read long documentation);
+see Array#[] and Array#[]=.
+
### Details and Examples
Most non-trivial methods benefit from examples, as well as details
@@ -372,6 +579,15 @@ do not add an example if it provides the same information given
in the synopsis or details. The purpose of examples is not to prove
what the details are stating.
+Many methods that can take an optional block call the block if it is given,
+but return a new Enumerator if the block is not given;
+in that case, do not provide an example,
+but do state the fact (with the auto-linking uppercase Enumerator):
+
+```rdoc
+* With no block given, returns a new Enumerator.
+```
+
### Argument Description (if necessary)
For methods that require arguments, if not obvious and not explicitly
@@ -388,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](rdoc-ref:RDoc::Markup@Labeled+Lists).
+[labeled list][lists].
### Corner Cases and Exceptions
@@ -409,7 +625,7 @@ mention `Hash#fetch` as a related method, and `Hash#merge` might mention
`Hash#merge!` as a related method.
- Consider which methods may be related
- to the current method, and if you think the reader would benefit it,
+ to the current method, and if you think the reader would benefit from it,
at the end of the method documentation, add a line starting with
"Related: " (e.g. "Related: #fetch.").
- Don't list more than three related methods.
@@ -418,7 +634,7 @@ mention `Hash#fetch` as a related method, and `Hash#merge` might mention
- Consider adding:
- A phrase suggesting how the related method is similar to,
- or different from,the current method.
+ or different from, the current method.
See an example at Time#getutc.
- Example code that illustrates the similarities and differences.
See examples at Time#ctime, Time#inspect, Time#to_s.
@@ -428,3 +644,16 @@ mention `Hash#fetch` as a related method, and `Hash#merge` might mention
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.
+
+[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 952601f813..3ec9796147 100644
--- a/doc/contributing/glossary.md
+++ b/doc/contributing/glossary.md
@@ -4,13 +4,17 @@ Just a list of acronyms I've run across in the Ruby source code and their meanin
| Term | Definition |
| --- | -----------|
-| `bop` | Basic Operator. Relates to methods like `Integer` plus and minus which can be optimized as long as they haven't been redefined.
+| `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`. |
-| `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 hierachy referenced by `rb_cref_struct * next`. The Class reference is lexically scoped. |
-| CRuby | Implementation of Ruby written in C |
+| `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 | 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` |
@@ -24,16 +28,20 @@ Just a list of acronyms I've run across in the Ruby source code and their meanin
| `insns` | Instructions. Usually an array of YARV instructions. |
| `ivar` | Instance Variable. Refers to a Ruby instance variable like `@foo` |
| `imemo` | Internal Memo. A tagged struct whose memory is managed by Ruby's GC, but contains internal information and isn't meant to be exposed to Ruby programs. Contains various information depending on the type. See the `imemo_type` enum for different types. |
+| `IVC` | Instance Variable Cache. Cache specifically for instance variable access |
| JIT | Just In Time compiler |
| `lep` | Local Environment Pointer. An `ep` which is tagged `VM_ENV_FLAG_LOCAL`. Usually this is the `ep` of a method (rather than a block, whose `ep` isn't "local") |
| `local` | Local. Refers to a local variable. |
-| `me` | Method Entry. Refers to an `rb_method_entry_t` struct, the internal representation of a Ruby method.
+| `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 ef3811ea12..2ceb2e6075 100644
--- a/doc/contributing/making_changes_to_stdlibs.md
+++ b/doc/contributing/making_changes_to_stdlibs.md
@@ -4,17 +4,17 @@ 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
-You can find the list of maintainers [here](https://docs.ruby-lang.org/en/master/maintainers_rdoc.html#label-Maintainers).
+You can find the list of maintainers [here](https://docs.ruby-lang.org/en/master/maintainers_md.html#label-Maintainers).
## Build
First, install its dependencies using:
-```
+```shell
bundle install
```
@@ -22,7 +22,7 @@ bundle install
If the library has a `/ext` directory, it has C files that you need to compile with:
-```
+```shell
bundle exec rake compile
```
@@ -32,18 +32,18 @@ All standard libraries use [test-unit](https://github.com/test-unit/test-unit) a
To run all tests:
-```
+```shell
bundle exec rake test
```
To run a single test file:
-```
+```shell
bundle exec rake test TEST="test/test_foo.rb"
```
To run a single test case:
-```
-bundle exec rake test TEST="test/test_foo.rb" TESTOPS="--name=/test_mytest/"
+```shell
+bundle exec rake test TEST="test/test_foo.rb" TESTOPTS="--name=/test_mytest/"
```
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/reporting_issues.md b/doc/contributing/reporting_issues.md
index 25516ffc6b..a1a2295712 100644
--- a/doc/contributing/reporting_issues.md
+++ b/doc/contributing/reporting_issues.md
@@ -52,19 +52,30 @@ your feature it could help persuade Ruby core.
Here is a template you can use for a feature proposal:
-```
-[Abstract]
- Briefly summarize your feature
-[Background]
- Describe current behavior
-[Proposal]
- Describe your feature in detail
-[Use cases]
- Give specific example uses of your feature
-[Discussion]
- Describe why this feature is necessary and better than using existing features
-[See also]
- Link to other related resources (such as implementations in other languages)
+```markdown
+# Abstract
+
+Briefly summarize your feature
+
+# Background
+
+Describe current behavior
+
+# Proposal
+
+Describe your feature in detail
+
+# Use cases
+
+Give specific example uses of your feature
+
+# Discussion
+
+Describe why this feature is necessary and better than using existing features
+
+# See also
+
+Link to other related resources (such as implementations in other languages)
```
## Backport requests
diff --git a/doc/contributing/testing_ruby.md b/doc/contributing/testing_ruby.md
index 6247686efc..4c7ce7f6a8 100644
--- a/doc/contributing/testing_ruby.md
+++ b/doc/contributing/testing_ruby.md
@@ -1,5 +1,9 @@
# Testing Ruby
+All the commands below assume that you're running them from the `build/` directory made during [Building Ruby](building_ruby.md).
+
+Most commands below should work with [GNU make](https://www.gnu.org/software/make/) (the default on Linux and macOS), [BSD make](https://man.freebsd.org/cgi/man.cgi?make(1)) and [NMAKE](https://learn.microsoft.com/en-us/cpp/build/reference/nmake-reference), except where indicated otherwise.
+
## Test suites
There are several test suites in the Ruby codebase:
@@ -8,131 +12,144 @@ We can run any of the make scripts [in parallel](building_ruby.md#label-Running+
1. [bootstraptest/](https://github.com/ruby/ruby/tree/master/bootstraptest)
- This is a small test suite that runs on Miniruby (see [building Ruby](building_ruby.md#label-Miniruby+vs+Ruby)). We can run it with:
+ This is a small test suite that runs on [Miniruby](building_ruby.md#label-Miniruby+vs+Ruby). We can run it with:
- ```
+ ```sh
make btest
```
- To run it with logs, we can use:
+ To run individual bootstrap tests, we can either specify a list of filenames or use the `--sets` flag in the variable `BTESTS`:
- ```
- make btest OPTS=-v
+ ```sh
+ make btest BTESTS="../bootstraptest/test_string.rb ../bootstraptest/test_class.rb"
+ make btest BTESTS="--sets=string,class"
```
- To run individual bootstrap tests, we can either specify a list of filenames or use the `--sets` flag in the variable `BTESTS`:
+ To run these tests with verbose logging, we can add `-v` to the `OPTS`:
- ```
- make btest BTESTS="bootstraptest/test_fork.rb bootstraptest/tes_gc.rb"
- make btest BTESTS="--sets=fork,gc"
+ ```sh
+ make btest OPTS="--sets=string,class -v"
```
If we want to run the bootstrap test suite on Ruby (not Miniruby), we can use:
- ```
+ ```sh
make test
```
- To run it with logs, we can use:
+ To run these tests with verbose logging, we can add `-v` to the `OPTS`:
- ```
+ ```sh
make test OPTS=-v
```
- To run a file or directory with GNU make, we can use:
+ (GNU make only) To run a specific file, we can use:
+ ```sh
+ make ../test/ruby/test_string.rb
```
- make test/ruby/test_foo.rb
- make test/ruby/test_foo.rb TESTOPTS="-n /test_bar/"
+
+ You can use the `-n` test option to run a specific test with a regex:
+
+ ```sh
+ make ../test/ruby/test_string.rb TESTOPTS="-n /test_.*_to_s/"
```
2. [test/](https://github.com/ruby/ruby/tree/master/test)
This is a more comprehensive test suite that runs on Ruby. We can run it with:
- ```
+ ```sh
make test-all
```
- We can run a specific test directory in this suite using the `TESTS` option, for example:
+ We can run a specific test file or directory in this suite using the `TESTS` option, for example:
- ```
- make test-all TESTS=test/rubygems
- ```
-
- We can run a specific test file in this suite by also using the `TESTS` option, for example:
-
- ```
- make test-all TESTS=test/ruby/test_array.rb
+ ```sh
+ make test-all TESTS="../test/ruby/"
+ make test-all TESTS="../test/ruby/test_string.rb"
```
We can run a specific test in this suite using the `TESTS` option, specifying
first the file name, and then the test name, prefixed with `--name`. For example:
- ```
- make test-all TESTS="../test/ruby/test_alias.rb --name=/test_alias_with_zsuper_method/"
+ ```sh
+ make test-all TESTS="../test/ruby/test_string.rb --name=TestString#test_to_s"
```
- To run these specs with logs, we can use:
+ To run these tests with verbose logging, we can add `-v` to `TESTS`:
- ```
+ ```sh
make test-all TESTS=-v
```
- If we would like to run both the `test/` and `bootstraptest/` test suites, we can run
+ We can display the help of the `TESTS` option:
+ ```sh
+ make test-all TESTS=--help
```
+
+ We can run all the tests in `test/`, `bootstraptest/` and `spec/` (the `spec/` is explained in a later section) all together with:
+
+ ```sh
make check
```
3. [spec/ruby](https://github.com/ruby/ruby/tree/master/spec/ruby)
- This is a test suite that exists in [the Ruby spec repository](https://github.com/ruby/spec) and is mirrored into the `spec/ruby` directory in the Ruby repository. It tests the behavior of the Ruby programming language. We can run this using:
+ This is a test suite defined in [the Ruby spec repository](https://github.com/ruby/spec), and is periodically mirrored into the `spec/ruby` directory of this repository. It tests the behavior of the Ruby programming language. We can run this using:
- ```
+ ```sh
make test-spec
```
- To run a specific directory, we can use `MSPECOPT` to specify the directory:
+ We can run a specific test file or directory in this suite using the `SPECOPTS` option, for example:
- ```
- make test-spec MSPECOPT=spec/ruby/core/array
- ```
-
- To run a specific file, we can also use `MSPECOPT` to specify the file:
-
- ```
- make test-spec MSPECOPT=spec/ruby/core/array/any_spec.rb
+ ```sh
+ make test-spec SPECOPTS="../spec/ruby/core/string/"
+ make test-spec SPECOPTS="../spec/ruby/core/string/to_s_spec.rb"
```
To run a specific test, we can use the `--example` flag to match against the test name:
- ```
- make test-spec MSPECOPT="../spec/ruby/core/array/any_spec.rb --example='is false if the array is empty'"
+ ```sh
+ make test-spec SPECOPTS="../spec/ruby/core/string/to_s_spec.rb --example='returns self when self.class == String'"
```
- To run these specs with logs, we can use:
+ To run these specs with verbose logging, we can add `-v` to the `SPECOPTS`:
- ```
- make test-spec MSPECOPT=-Vfs
+ ```sh
+ make test-spec SPECOPTS="../spec/ruby/core/string/to_s_spec.rb -Vfs"
```
- To run a ruby-spec file or directory with GNU make, we can use
+ (GNU make only) To run a ruby-spec file or directory, we can use
- ```
- make spec/ruby/core/foo/bar_spec.rb
+ ```sh
+ make ../spec/ruby/core/string/to_s_spec.rb
```
4. [spec/bundler](https://github.com/ruby/ruby/tree/master/spec/bundler)
- The bundler test suite exists in [the RubyGems repository](https://github.com/rubygems/rubygems/tree/master/bundler/spec) and is mirrored into the `spec/bundler` directory in the Ruby repository. We can run this using:
+ The bundler test suite is defined in [the RubyGems repository](https://github.com/rubygems/rubygems/tree/master/bundler/spec), and is periodically mirrored into the `spec/ruby` directory of this repository. We can run this using:
- ```
+ ```sh
make test-bundler
```
To run a specific bundler spec file, we can use `BUNDLER_SPECS` as follows:
+ ```sh
+ make test-bundler BUNDLER_SPECS=commands/exec_spec.rb
```
- $ make test-bundler BUNDLER_SPECS=commands/exec_spec.rb
- ```
+
+## Troubleshooting
+
+### Running test suites on s390x CPU Architecture
+
+If we see failing tests related to the zlib library on s390x CPU architecture, we can run the test suites with `DFLTCC=0` to pass:
+
+```sh
+DFLTCC=0 make check
+```
+
+The failures can happen with the zlib library applying the patch [madler/zlib#410](https://github.com/madler/zlib/pull/410) to enable the deflate algorithm producing a different compressed byte stream. We manage this issue at [[ruby-core:114942][Bug #19909]](https://bugs.ruby-lang.org/issues/19909).
diff --git a/doc/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 05769b5773..0000000000
--- a/doc/csv/options/common/col_sep.rdoc
+++ /dev/null
@@ -1,63 +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)
-
-Raises an exception if the given value is not String-convertible:
- col_sep = BasicObject.new
- # Raises NoMethodError (undefined method `to_s' for #<BasicObject:>)
- CSV.generate(line, col_sep: col_sep)
- # Raises NoMethodError (undefined method `to_s' for #<BasicObject:>)
- CSV.parse(str, col_sep: col_sep)
diff --git a/doc/csv/options/common/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 872d9d1f3f..0000000000
--- a/doc/csv/options/common/row_sep.rdoc
+++ /dev/null
@@ -1,100 +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.
-
----
-
-Raises an exception if the given value is not String-convertible:
- row_sep = BasicObject.new
- # Raises NoMethodError (undefined method `to_s' for #<BasicObject:>)
- CSV.generate(ary, row_sep: row_sep)
- # Raises NoMethodError (undefined method `to_s' for #<BasicObject:>)
- CSV.parse(str, row_sep: row_sep)
diff --git a/doc/csv/options/generating/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 6e5fae5fda..0000000000
--- a/doc/csv/options/generating/write_converters.rdoc
+++ /dev/null
@@ -1,33 +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]
-
----
-
-Raises an exception if the converter returns a value that is neither +nil+
-nor \String-convertible:
- bad_converter = proc {|field| BasicObject.new }
- # Raises NoMethodError (undefined method `is_a?' for #<BasicObject:>)
- CSV.generate_line(['a', 'b', 'c'], write_converters: bad_converter) \ No newline at end of file
diff --git a/doc/csv/options/generating/write_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 f9faa9d438..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 b8b9b00c98..0000000000
--- a/doc/csv/options/parsing/liberal_parsing.rdoc
+++ /dev/null
@@ -1,19 +0,0 @@
-====== Option +liberal_parsing+
-
-Specifies the boolean value that determines whether
-CSV will attempt to parse input not conformant with RFC 4180,
-such as double quotes in unquoted fields.
-
-Default value:
- CSV::DEFAULT_OPTIONS.fetch(:liberal_parsing) # => false
-
-For examples in this section:
- 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"]
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 470649d09a..0000000000
--- a/doc/csv/recipes/filtering.rdoc
+++ /dev/null
@@ -1,156 +0,0 @@
-== Recipes for Filtering \CSV
-
-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 3ef6df99b4..0000000000
--- a/doc/csv/recipes/generating.rdoc
+++ /dev/null
@@ -1,244 +0,0 @@
-== Recipes for Generating \CSV
-
-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 coverters
-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://tools.ietf.org/html/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 7ac96a934b..0000000000
--- a/doc/csv/recipes/parsing.rdoc
+++ /dev/null
@@ -1,543 +0,0 @@
-== Recipes for Parsing \CSV
-
-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://tools.ietf.org/html/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 # => [["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 9e4eaa1da4..0000000000
--- a/doc/csv/recipes/recipes.rdoc
+++ /dev/null
@@ -1,6 +0,0 @@
-== Recipes for \CSV
-
-See:
-- {Recipes for Parsing CSV}[./parsing_rdoc.html]
-- {Recipes for Generating CSV}[./generating_rdoc.html]
-- {Recipes for Filtering CSV}[./filtering_rdoc.html]
diff --git a/doc/distribution.md b/doc/distribution/distribution.md
index bc89a7500a..e0e4ad354b 100644
--- a/doc/distribution.md
+++ b/doc/distribution/distribution.md
@@ -8,7 +8,7 @@ This document outlines the expected way to distribute Ruby, with a specific focu
The tarball for official releases is created by the release manager. The release manager uploads the tarball to the [Ruby website](https://www.ruby-lang.org/en/downloads/).
-Downstream distributors should use the official release tarballs as part of their build process. This ensures that the tarball is created in a consistent way, and that the tarball is crytographically verified.
+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
@@ -19,7 +19,8 @@ See the Snapshots section of the [Ruby website](https://www.ruby-lang.org/en/dow
This can be useful if the nightly tarball does not have all changes yet.
At Ruby source tree cloned using git:
-```sh-session
+
+```console
$ ./autogen.sh
$ ./configure -C
$ make
@@ -30,7 +31,7 @@ This will create several tarball in the `tmp` directory. The tarball will be nam
## Building the Tarball
-See [Building Ruby](contributing/building_ruby.md).
+See [Building Ruby](../contributing/building_ruby.md).
## Updating the Ruby Standard Library
diff --git a/doc/windows.md b/doc/distribution/windows.md
index d0f447350e..26a727d7ad 100644
--- a/doc/windows.md
+++ b/doc/distribution/windows.md
@@ -2,9 +2,9 @@
Ruby supports a few native build platforms for Windows.
-* mswin: Build using Microsoft Visual C++ compiler
+* 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 vcruntime.dll
+* mingw-ucrt: Build using compiler for Mingw with Windows Universal CRT
## Building Ruby using Mingw with UCRT
@@ -16,41 +16,52 @@ editor.
Ruby core development can be done either in Windows `cmd` like:
-```
+```batch
+ridk install
ridk enable ucrt64
-pacman -S --needed bison %MINGW_PACKAGE_PREFIX%-openssl %MINGW_PACKAGE_PREFIX%-libyaml %MINGW_PACKAGE_PREFIX%-readline
+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
-cd c:\
-mkdir work
-cd work
-git clone https://github.com/ruby/ruby
+sh ./src/autogen.sh
-cd c:\work\ruby
-sh autogen.sh
-sh configure -C --disable-install-doc
+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 bison $MINGW_PACKAGE_PREFIX-openssl $MINGW_PACKAGE_PREFIX-libyaml $MINGW_PACKAGE_PREFIX-readline
+pacman -S --needed $MINGW_PACKAGE_PREFIX-openssl $MINGW_PACKAGE_PREFIX-libyaml $MINGW_PACKAGE_PREFIX-libffi
+
+mkdir /c/work/ruby
+cd /c/work/ruby
-cd /c/
-mkdir work
-cd work
-git clone https://github.com/ruby/ruby
-cd ruby
+git clone https://github.com/ruby/ruby src
-./autogen.sh
-./configure -C --disable-install-doc
+./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/
@@ -59,40 +70,79 @@ make
### Requirement
-1. Windows 7 or later.
+1. Windows 10/Windows Server 2016 or later.
-2. Visual C++ 12.0 (2013) or later.
+2. Visual C++ 14.0 (2015) or later.
**Note** if you want to build x64 version, use native compiler for
x64.
-3. Please set environment variable `INCLUDE`, `LIB`, `PATH`
- to run required commands properly from the command line.
+ 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
+ * `nmake`
+ * `cl`
+ * `ml`
+ * `lib`
+ * `dumpbin`
4. If you want to build from GIT source, following commands are required.
- * bison
- * patch
- * sed
- * ruby 2.0 or later
+ * `git`
+ * `ruby` 3.1 or later
You can use [scoop](https://scoop.sh/) to install them like:
- ```
- scoop install git ruby winflexbison sed patch
+ ```batch
+ scoop install git ruby
```
-5. You need to install required libraries using [vcpkg](https://vcpkg.io/) like:
+ 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
```
- vcpkg --triplet x64-windows install openssl libffi libyaml zlib
+
+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
@@ -103,30 +153,37 @@ make
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`
+ For example, run `configure --target=i686-mswin32`.
You can also specify the install directory.
- For example, run `configure --prefix=<install_directory>`
+ For example, run `configure --prefix=<install_directory>`.
Default of the install directory is `/usr` .
- The default _PLATFORM_ is `i386-mswin32_`_MSRTVERSION_ on 32-bit
- platforms, or `x64-mswin64_`_MSRTVERSION_ on x64 platforms.
- _MSRTVERSION_ is the 2- or 3-digits version of the Microsoft
- Runtime Library.
-2. Change _RUBY_INSTALL_NAME_ and _RUBY_SO_NAME_ in `Makefile`
- if you want to change the name of the executable files.
- And add _RUBYW_INSTALL_NAME_ to change the name of the
- executable without console window if also you want.
+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 `configure --with-opt-dir=C:\vcpkg\installed\x64-windows`
+ 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 check`
+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 install`
+7. Run `nmake check`
+
+8. Run `nmake install`
### Build examples
@@ -138,7 +195,7 @@ make
install directory: C:\usr\local
```
- ```
+ ```batch
C:
cd \ruby
win32\configure --prefix=/usr/local
@@ -155,7 +212,7 @@ make
install directory: C:\usr\local
```
- ```
+ ```batch
C:
cd \ruby
mkdir mswin32
@@ -174,7 +231,7 @@ make
install directory: C:\usr\local
```
- ```
+ ```batch
D:
cd D:\build\ruby
C:\src\ruby\win32\configure --prefix=/usr/local
@@ -191,7 +248,7 @@ make
install directory: C:\usr\local
```
- ```
+ ```batch
C:
cd \ruby
win32\configure --prefix=/usr/local --target=x64-mswin64
@@ -210,12 +267,25 @@ 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
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/extension.ja.rdoc b/doc/extension.ja.rdoc
index bde907c916..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) ::
@@ -780,9 +782,14 @@ RUBY_TYPED_WB_PROTECTED ::
メソッドの実装に適切にライトバリアを挿入する責任があります.
さもなくばRubyは実行時にクラッシュする可能性があります.
- ライトバリアについてはdoc/extension.ja.rdocのAppendix D
- "世代別GC"も参照してください.
+ ライトバリアについては{世代別
+ GC}[rdoc-ref:@Appendix+D.+-E4-B8-96-E4-BB-A3-E5-88-A5GC]
+ も参照してください.
+このマクロは例外を発生させる可能性があることに注意してくださ
+い. ラップされる sval が,解放する必要があるリソース (割り
+当てられたメモリ,外部ライブラリからのハンドルなど) を保持し
+ている場合は,rb_protect を使用する必要があります.
Cの構造体の割当と対応するオブジェクトの生成を同時に行うマク
ロとして以下のものが提供されています.
@@ -1731,7 +1738,7 @@ have_func(func, header) ::
ックする.funcが標準ではリンクされないライブラリ内のもので
ある時には先にhave_libraryでそのライブラリをチェックしてお
く事.チェックに成功すると,プリプロセッサマクロ
- `HAVE_{FUNC}` を定義し,trueを返す.
+ <tt>HAVE_{FUNC}</tt> を定義し,trueを返す.
have_var(var, header) ::
@@ -1739,44 +1746,44 @@ have_var(var, header) ::
クする.varが標準ではリンクされないライブラリ内のものであ
る時には先にhave_libraryでそのライブラリをチェックしておく
事.チェックに成功すると,プリプロセッサマクロ
- `HAVE_{VAR}` を定義し,trueを返す.
+ <tt>HAVE_{VAR}</tt> を定義し,trueを返す.
have_header(header) ::
ヘッダファイルの存在をチェックする.チェックに成功すると,
- プリプロセッサマクロ `HAVE_{HEADER_H}` を定義し,trueを返す.
+ プリプロセッサマクロ <tt>HAVE_{HEADER_H}</tt> を定義し,trueを返す.
(スラッシュやドットはアンダースコアに置換される)
find_header(header, path...) ::
ヘッダファイルheaderの存在を -Ipath を追加しながらチェック
する.チェックに成功すると,プリプロセッサマクロ
- `HAVE_{HEADER_H}` を定義し,trueを返す.
+ <tt>HAVE_{HEADER_H}</tt> を定義し,trueを返す.
(スラッシュやドットはアンダースコアに置換される)
have_struct_member(type, member[, header[, opt]]) ::
ヘッダファイルheaderをインクルードして型typeが定義され,
なおかつメンバmemberが存在するかをチェックする.チェックに
- 成功すると,プリプロセッサマクロ `HAVE_{TYPE}_{MEMBER}` を
+ 成功すると,プリプロセッサマクロ <tt>HAVE_{TYPE}_{MEMBER}</tt> を
定義し,trueを返す.
have_type(type, header, opt) ::
ヘッダファイルheaderをインクルードして型typeが存在するかを
チェックする.チェックに成功すると,プリプロセッサマクロ
- `HAVE_TYPE_{TYPE}` を定義し,trueを返す.
+ <tt>HAVE_TYPE_{TYPE}</tt> を定義し,trueを返す.
check_sizeof(type, header) ::
ヘッダファイルheaderをインクルードして型typeのchar単位サイ
ズを調べる.チェックに成功すると,プリプロセッサマクロ
- `SIZEOF_{TYPE}` を定義し,そのサイズを返す.定義されていな
+ <tt>SIZEOF_{TYPE}</tt> を定義し,そのサイズを返す.定義されていな
いときはnilを返す.
-append_cppflags(array-of-flags[, opt])
-append_cflags(array-of-flags[, opt])
-append_ldflags(array-of-flags[, opt])
+append_cppflags(array-of-flags[, opt]) ::
+append_cflags(array-of-flags[, opt]) ::
+append_ldflags(array-of-flags[, opt]) ::
各flagが使用可能であれば,それぞれ$CPPFLAGS, $CFLAGS,
$LDFLAGSに追加する.コンパイラのフラグには移植性がないので,
@@ -1850,8 +1857,9 @@ RGenGCは,過去の拡張ライブラリに(ほぼ)互換性を保つよ
スするようなコードは書かないようにして下さい.代わりに,rb_ary_aref(),
rb_ary_store() などの,適切な API 関数を利用するようにして下さい.
-そのほか,対応についての詳細は extension.rdoc の「Appendix D. Generational
-GC」を参照して下さい.
+そのほか,対応についての詳細は {Appendix D. Generational
+GC}[rdoc-ref:extension.rdoc@Appendix+D.+Generational+GC]を参
+照して下さい.
== Appendix E. Ractor サポート
@@ -1860,10 +1868,12 @@ Ruby 3.0 から、Ruby プログラムを並列に実行するための仕組み
なります。サポートしていないライブラリは、メイン Ractor 以外で実行すると
エラーになります(Ractor::UnsafeError)。
-Ractor をサポートするための詳細は、extension.rdoc の「Appendix F. Ractor
-support」を参照してください。
-
+Ractor をサポートするための詳細は、{Appendix F. Ractor
+support}[rdoc-ref:extension.rdoc@Appendix+F.+Ractor+support]
+を参照してください。
-:enddoc: Local variables:
-:enddoc: fill-column: 60
-:enddoc: end:
+--
+Local variables:
+fill-column: 60
+end:
+++
diff --git a/doc/extension.rdoc b/doc/extension.rdoc
index c0360ae625..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) ::
@@ -747,18 +749,68 @@ RUBY_TYPED_WB_PROTECTED ::
barriers in all implementations of methods of that object as
appropriate. Otherwise Ruby might crash while running.
- More about write barriers can be found in "Generational GC" in
- Appendix D.
+ More about write barriers can be found in {Generational
+ GC}[rdoc-ref:@Appendix+D.+Generational+GC].
RUBY_TYPED_FROZEN_SHAREABLE ::
- This flag indicates that the object is shareable object
- if the object is frozen. See Appendix F more details.
+ This flag indicates that the object is shareable object if the object
+ is frozen. See {Ractor support}[rdoc-ref:@Appendix+F.+Ractor+support]
+ more details.
If this flag is not set, the object can not become a shareable
object by Ractor.make_shareable() method.
-You can allocate and wrap the structure in one step.
+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.
+
+You can allocate and wrap the structure in one step, in more
+preferable manner.
TypedData_Make_Struct(klass, type, data_type, sval)
@@ -767,10 +819,71 @@ the structure, which is also allocated. This macro works like:
(sval = ZALLOC(type), TypedData_Wrap_Struct(klass, data_type, sval))
+However, you should use this macro instead of "allocation then wrap"
+like the above code if it is simply allocated, because the latter can
+raise a NoMemoryError and sval will be memory leaked in that case.
+
Arguments klass and data_type work like their counterparts in
TypedData_Wrap_Struct(). A pointer to the allocated structure will
be assigned to sval, which should be a pointer of the type specified.
+==== Declaratively marking/compacting struct references
+
+In the case where your struct refers to Ruby objects that are simple values,
+not wrapped in conditional logic or complex data structures an alternative
+approach to marking and reference updating is provided, by declaring offset
+references to the VALUES in your struct.
+
+Doing this allows the Ruby GC to support marking these references and GC
+compaction without the need to define the +dmark+ and +dcompact+ callbacks.
+
+You must define a static list of VALUE pointers to the offsets within your
+struct where the references are located, and set the "data" member to point to
+this reference list. The reference list must end with +RUBY_END_REFS+.
+
+Some Macros have been provided to make edge referencing easier:
+
+* <code>RUBY_TYPED_DECL_MARKING</code> =A flag that can be set on the +ruby_data_type_t+ to indicate that references are being declared as edges.
+
+* <code>RUBY_REFERENCES(ref_list_name)</code> - Define _ref_list_name_ as a list of references
+
+* <code>RUBY_REF_END</code> - The end mark of the references list.
+
+* <code>RUBY_REF_EDGE(struct, member)</code> - Declare _member_ as a VALUE edge from _struct_. Use this after +RUBY_REFERENCES_START+
+
+* +RUBY_REFS_LIST_PTR+ - Coerce the reference list into a format that can be
+ accepted by the existing +dmark+ interface.
+
+The example below is from Dir (defined in +dir.c+)
+
+ // The struct being wrapped. Notice this contains 3 members of which the second
+ // is a VALUE reference to another ruby object.
+ struct dir_data {
+ DIR *dir;
+ const VALUE path;
+ rb_encoding *enc;
+ }
+
+ // Define a reference list `dir_refs` containing a single entry to `path`.
+ // Needs terminating with RUBY_REF_END
+ RUBY_REFERENCES(dir_refs) = {
+ RUBY_REF_EDGE(dir_data, path),
+ RUBY_REF_END
+ };
+
+ // Override the "dmark" field with the defined reference list now that we
+ // no longer need a marking callback and add RUBY_TYPED_DECL_MARKING to the
+ // flags field
+ static const rb_data_type_t dir_data_type = {
+ "dir",
+ {RUBY_REFS_LIST_PTR(dir_refs), dir_free, dir_memsize,},
+ 0, NULL, RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_DECL_MARKING
+ };
+
+Declaring simple references declaratively in this manner allows the GC to both
+mark, and move the underlying object, and automatically update the reference to
+it during compaction.
+
==== Ruby object to C struct
To retrieve the C pointer from the T_DATA object, use the macro
@@ -1980,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
@@ -2152,70 +2265,155 @@ Ractor safety around C extensions has the following properties:
To make a "Ractor-safe" C extension, we need to check the following points:
-(1) Do not share unshareable objects between ractors
+1. Do not share unshareable objects between ractors
+
+ For example, C's global variable can lead sharing an unshareable objects
+ between ractors.
-For example, C's global variable can lead sharing an unshareable objects
-between ractors.
+ VALUE g_var;
+ VALUE set(VALUE self, VALUE v){ return g_var = v; }
+ VALUE get(VALUE self){ return g_var; }
- VALUE g_var;
- VALUE set(VALUE self, VALUE v){ return g_var = v; }
- VALUE get(VALUE self){ return g_var; }
+ set() and get() pair can share an unshareable objects using g_var, and
+ it is Ractor-unsafe.
-set() and get() pair can share an unshareable objects using g_var, and
-it is Ractor-unsafe.
+ Not only using global variables directly, some indirect data structure
+ such as global st_table can share the objects, so please take care.
-Not only using global variables directly, some indirect data structure
-such as global st_table can share the objects, so please take care.
+ Note that class and module objects are shareable objects, so you can
+ keep the code "cFoo = rb_define_class(...)" with C's global variables.
-Note that class and module objects are shareable objects, so you can
-keep the code "cFoo = rb_define_class(...)" with C's global variables.
+2. Check the thread-safety of the extension
-(2) Check the thread-safety of the extension
+ An extension should be thread-safe. For example, the following code is
+ not thread-safe:
-An extension should be thread-safe. For example, the following code is
-not thread-safe:
+ bool g_called = false;
+ VALUE call(VALUE self) {
+ if (g_called) rb_raise("recursive call is not allowed.");
+ g_called = true;
+ VALUE ret = do_something();
+ g_called = false;
+ return ret;
+ }
- bool g_called = false;
- VALUE call(VALUE self) {
- if (g_called) rb_raise("recursive call is not allowed.");
- g_called = true;
- VALUE ret = do_something();
- g_called = false;
- return ret;
+ because g_called global variable should be synchronized by other
+ ractor's threads. To avoid such data-race, some synchronization should
+ be used. Check include/ruby/thread_native.h and include/ruby/atomic.h.
+
+ With Ractors, all objects given as method parameters and the receiver (self)
+ are guaranteed to be from the current Ractor or to be shareable. As a
+ consequence, it is easier to make code ractor-safe than to make code generally
+ thread-safe. For example, we don't need to lock an array object to access the
+ element of it.
+
+3. Check the thread-safety of any used library
+
+ If the extension relies on an external library, such as a function foo() from
+ a library libfoo, the function libfoo foo() should be thread safe.
+
+4. Make an object shareable
+
+ This is not required to make an extension Ractor-safe.
+
+ If an extension provides special objects defined by rb_data_type_t,
+ consider these objects can become shareable or not.
+
+ RUBY_TYPED_FROZEN_SHAREABLE flag indicates that these objects can be
+ shareable objects if the object is frozen. This means that if the object
+ is frozen, the mutation of wrapped data is not allowed.
+
+5. Others
+
+ There are possibly other points or requirements which must be considered in the
+ making of a Ractor-safe extension. This document will be extended as they are
+ discovered.
+
+== 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);
}
-because g_called global variable should be synchronized by other
-ractor's threads. To avoid such data-race, some synchronization should
-be used. Check include/ruby/thread_native.h and include/ruby/atomic.h.
+ 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;
+ }
-With Ractors, all objects given as method parameters and the receiver (self)
-are guaranteed to be from the current Ractor or to be shareable. As a
-consequence, it is easier to make code ractor-safe than to make code generally
-thread-safe. For example, we don't need to lock an array object to access the
-element of it.
+ 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,
+ };
-(3) Check the thread-safety of any used library
+ static VALUE
+ my_data_alloc(VALUE klass)
+ {
+ struct my_data *data;
+ VALUE obj = TypedData_Make_Struct(klass, struct my_data, &my_type, data);
-If the extension relies on an external library, such as a function foo() from
-a library libfoo, the function libfoo foo() should be thread safe.
+ // 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);
-(4) Make an object shareable
+ return obj
+ }
-This is not required to make an extension Ractor-safe.
+ 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);
-If an extension provides special objects defined by rb_data_type_t,
-consider these objects can become shareable or not.
+ // `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)
+ }
-RUBY_TYPED_FROZEN_SHAREABLE flag indicates that these objects can be
-shareable objects if the object is frozen. This means that if the object
-is frozen, the mutation of wrapped data is not allowed.
+ static VALUE
+ my_data_read(VALUE self)
+ {
+ struct my_data *data;
+ TypedData_Get_Struct(obj, struct my_data, &my_type, data);
-(5) Others
+ // `self` is received from `rb_define_method` so `RB_GC_GUARD` isn't necessary.
+ return rb_str_new(data->buffer, data->buffer_capa)
+ }
-There are possibly other points or requirements which must be considered in the
-making of a Ractor-safe extension. This document will be extended as they are
-discovered.
+ 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);
+ }
-:enddoc: Local variables:
-:enddoc: fill-column: 70
-:enddoc: end:
+--
+Local variables:
+fill-column: 70
+end:
+++
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..fca02f1d83
--- /dev/null
+++ b/doc/file/filename_matching.md
@@ -0,0 +1,471 @@
+# 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
+
+Pathname('xyzzy').fnmatch('xyzzy') # => true
+Pathname('one_two_three').fnmatch('one_two_three') # => true
+Pathname('123').fnmatch('123') # => true
+Pathname('Form 27B/6').fnmatch('Form 27B/6') # => true
+
+# Must be exact.
+pattern = 'abcde'
+path = 'abc'
+File.fnmatch(pattern, path) # => false
+Pathname(path).fnmatch(pattern) # => false
+```
+
+By default, the matching is case-sensitive:
+
+```ruby
+pattern = 'abc'
+path = 'ABC'
+File.fnmatch(pattern, path) # => false
+Pathname(path).fnmatch(pattern) # => 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:
+
+```ruby
+pattern = 'R{ub,foo}y'
+path = 'Ruby'
+File.fnmatch(pattern, path) # => false
+Pathname(path).fnmatch(pattern) # => false
+```
+
+It may be enabled by flag [`File::FNM_EXTGLOB`](#constant-filefnmextglob).
+
+By default, the Windows short name pattern is disabled:
+
+```ruby
+pattern ='PROGRAM~1'
+path = 'Program Files'
+File.fnmatch(pattern, path) # => false
+Pathname(path).fnmatch(pattern) # => 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
+pattern = '*'
+File.fnmatch(pattern, 'foo') # => true
+File.fnmatch(pattern, '') # => true
+File.fnmatch(pattern, 'foo') # => true
+
+Pathname('foo').fnmatch(pattern) # => true
+Pathname('').fnmatch(pattern) # => true
+Pathname('*').fnmatch(pattern) # => true
+```
+
+The pattern may be escaped:
+
+```ruby
+pattern = '\*'
+File.fnmatch(pattern, 'foo') # => false
+Pathname('foo').fnmatch(pattern) # => false
+```
+
+By default, the asterisk pattern does not match a leading period (as in a dot-file):
+
+```ruby
+pattern = '*'
+path = '.document'
+File.fnmatch(pattern, path) # => false
+Pathname(path).fnmatch(pattern) # => false
+```
+
+That matching may be enabled by flag [`File::FNM_DOTMATCH`](#constant-filefnmdotmatch).
+
+By default, the asterisk pattern matches across file separators:
+
+```ruby
+pattern = '*.rb'
+path = 'lib/test.rb'
+File.fnmatch(pattern, path) # => true
+Pathname(path).fnmatch(pattern) # => true
+```
+
+That matching may be disabled by flag [`File::FNM_PATHNAME`](#constant-filefnmpathname).
+
+### Single Character (`'?'`)
+
+The question-mark pattern (`'?'`) matches any single character:
+
+```ruby
+pattern = '?'
+File.fnmatch(pattern, 'f') # => true
+File.fnmatch(pattern, '') # => false
+File.fnmatch(pattern, 'foo') # => false
+
+Pathname('f').fnmatch(pattern) # => true
+Pathname('').fnmatch(pattern) # => false
+Pathname('foo').fnmatch(pattern) # => false
+
+pattern = 'foo-?.txt'
+path = 'foo-1.txt'
+File.fnmatch(pattern, path) # => true
+Pathname(path).fnmatch(pattern) # => true
+```
+
+The pattern may be escaped:
+
+```ruby
+pattern = '\?'
+path = 'f'
+File.fnmatch(pattern, path) # => false
+Pathname(path).fnmatch(pattern) # => false
+```
+
+By default, pattern `'?'` matches the file separator:
+
+```ruby
+pattern = 'foo?bar'
+path = 'foo/bar'
+File.fnmatch(pattern, path) # => true
+Pathname(path).fnmatch(pattern) # => 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
+pattern = '[ruby]'
+File.fnmatch(pattern, 'r') # => true
+File.fnmatch(pattern, 'u') # => true
+File.fnmatch(pattern, 'y') # => true
+
+Pathname('r').fnmatch(pattern) # => true
+Pathname('u').fnmatch(pattern) # => true
+Pathname('y').fnmatch(pattern) # => true
+
+# Matches a single character.
+pattern = '[ruby]'
+path = 'ruby'
+File.fnmatch(pattern, path) # => false
+Pathname(path).fnmatch(pattern) # => false
+```
+
+The pattern may be escaped:
+
+```ruby
+pattern = '\[ruby]'
+path = 'r'
+File.fnmatch(pattern, path) # => false
+Pathname(path).fnmatch(pattern) # => false
+```
+
+The character set may be negated:
+
+```ruby
+pattern = '[^ruby]'
+File.fnmatch(pattern, 'r') # => false
+File.fnmatch(pattern, 'u') # => false
+
+Pathname('r').fnmatch(pattern) # => false
+Pathname('u').fnmatch(pattern) # => 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
+pattern = '[a-c]'
+File.fnmatch(pattern, 'b') # => true
+File.fnmatch(pattern, 'd') # => false
+File.fnmatch(pattern, 'abc') # => false
+
+Pathname('b').fnmatch(pattern) # => true
+Pathname('d').fnmatch(pattern) # => false
+Pathname('abc').fnmatch(pattern) # => false
+```
+
+The pattern may be escaped:
+
+```ruby
+pattern = '\[a-c]'
+path = 'b'
+File.fnmatch(pattern, path) # => false
+Pathname(path).fnmatch(pattern) # => false
+
+```
+
+Multiple ranges are allowed:
+
+```ruby
+pattern = 'R[t-v][a-c]y'
+path = 'Ruby'
+File.fnmatch(pattern, path) # => true
+Pathname(path).fnmatch(pattern) # => true
+```
+
+The range may be negated:
+
+```ruby
+pattern = '[^a-c]'
+path = 'b'
+File.fnmatch(pattern, path) # => false
+Pathname(path).fnmatch(pattern) # => false
+```
+
+### Escape (`'\'`)
+
+The backslash character (`'\'`) may be used to escape any of the characters
+that filename matching treats as special:
+
+```ruby
+path = 'b'
+File.fnmatch('[a-c]', path) # => true
+File.fnmatch('\[a-c]', path) # => false
+File.fnmatch('[a-c\]', path) # => false
+File.fnmatch('[a\-c]', path) # => false
+
+Pathname(path).fnmatch('[a-c]') # => true
+Pathname(path).fnmatch('\[a-c]') # => false
+Pathname(path).fnmatch('[a-c\]') # => false
+Pathname(path).fnmatch('[a\-c]') # => false
+
+File.fnmatch('{a,b}', path, File::FNM_EXTGLOB) # => true
+File.fnmatch('\{a,b}', path, File::FNM_EXTGLOB) # => false
+File.fnmatch('{a\,b}', path, File::FNM_EXTGLOB) # => false
+File.fnmatch('{a,b\}', path, File::FNM_EXTGLOB) # => false
+
+Pathname(path).fnmatch('{a,b}', File::FNM_EXTGLOB) # => true
+Pathname(path).fnmatch('\{a,b}', File::FNM_EXTGLOB) # => false
+Pathname(path).fnmatch('{a,b\}', File::FNM_EXTGLOB) # => false
+Pathname(path).fnmatch('{a\,b}', File::FNM_EXTGLOB) # => false
+
+```
+
+Use a double-backslash to represent an ordinary backslash:
+
+```ruby
+pattern = '\\\\'
+path = '\\'
+File.fnmatch(pattern, path) # => true
+Pathname(path).fnmatch(pattern) # => 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/forwardable.rd.ja b/doc/forwardable.rd.ja
deleted file mode 100644
index 171724b2e5..0000000000
--- a/doc/forwardable.rd.ja
+++ /dev/null
@@ -1,80 +0,0 @@
- -- forwatable.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.rdoc b/doc/globals.rdoc
deleted file mode 100644
index 1d7cda69f9..0000000000
--- a/doc/globals.rdoc
+++ /dev/null
@@ -1,69 +0,0 @@
-# -*- mode: rdoc; coding: utf-8; fill-column: 74; -*-
-
-== Pre-defined global variables
-
-$!:: The Exception object set by Kernel#raise.
-$@:: The same as <code>$!.backtrace</code>.
-$~:: The information about the last match in the current scope (thread-local and frame-local).
-$&:: The string matched by the last successful match.
-$`:: The string to the left of the last successful match.
-$':: The string to the right of the last successful match.
-$+:: The highest group matched by the last successful match.
-$1:: The Nth group of the last successful match. May be > 1.
-$=:: This variable is no longer effective. Deprecated.
-$/:: The input record separator, newline by default. Aliased to $-0.
-$\:: The output record separator for Kernel#print and IO#write. Default is +nil+.
-$,:: The output field separator for Kernel#print and Array#join. Non-nil $, will be deprecated.
-$;:: The default separator for String#split. Non-nil $; will be deprecated. Aliased to $-F.
-$.:: The current input line number of the last file that was read.
-$<:: The same as ARGF.
-$>:: The default output stream for Kernel#print and Kernel#printf. $stdout by default.
-$_:: The last input line of string by gets or readline.
-$0:: Contains the name of the script being executed. May be assignable.
-$*:: The same as ARGV.
-$$:: The process number of the Ruby running this script. Same as Process.pid.
-$?:: The status of the last executed child process (thread-local).
-$LOAD_PATH:: Load path for searching Ruby scripts and extension libraries used
- by Kernel#load and Kernel#require. Aliased to $: and $-I.
- Has a singleton method <code>$LOAD_PATH.resolve_feature_path(feature)</code>
- that returns [+:rb+ or +:so+, path], which resolves the feature to
- the path the original Kernel#require method would load.
-$LOADED_FEATURES:: The array contains the module names loaded by require.
- Aliased to $".
-$DEBUG:: The debug flag, which is set by the <tt>-d</tt> switch. Enabling debug
- output prints each exception raised to $stderr (but not its
- backtrace). Setting this to a true value enables debug output as
- if <tt>-d</tt> were given on the command line. Setting this to a false
- value disables debug output. Aliased to $-d.
-$FILENAME:: Current input filename from ARGF. Same as ARGF.filename.
-$stderr:: The current standard error output.
-$stdin:: The current standard input.
-$stdout:: The current standard output.
-$VERBOSE:: The verbose flag, which is set by the <tt>-w</tt> or <tt>-v</tt> switch.
- Setting this to a true value enables warnings as if <tt>-w</tt> or <tt>-v</tt> were given
- on the command line. Setting this to +nil+ disables warnings,
- including from Kernel#warn. Aliased to $-v and $-w.
-$-a:: True if option <tt>-a</tt> is set. Read-only variable.
-$-i:: In in-place-edit mode, this variable holds the extension, otherwise +nil+.
-$-l:: True if option <tt>-l</tt> is set. Read-only variable.
-$-p:: True if option <tt>-p</tt> is set. Read-only variable.
-
-== Pre-defined global constants
-
-STDIN:: The standard input. The default value for $stdin.
-STDOUT:: The standard output. The default value for $stdout.
-STDERR:: The standard error output. The default value for $stderr.
-ENV:: The hash contains current environment variables.
-ARGF:: The virtual concatenation of the files given on command line (or from $stdin if no files were given).
-ARGV:: An Array of command line arguments given for the script.
-DATA:: The file object of the script, pointing just after <code>__END__</code>.
-TOPLEVEL_BINDING:: The Binding of the top level scope.
-RUBY_VERSION:: The Ruby language version.
-RUBY_RELEASE_DATE:: The release date string.
-RUBY_PLATFORM:: The platform identifier.
-RUBY_PATCHLEVEL:: The patchlevel for this Ruby. If this is a development build of Ruby the patchlevel will be -1.
-RUBY_REVISION:: The GIT commit hash for this Ruby.
-RUBY_COPYRIGHT:: The copyright string for Ruby.
-RUBY_ENGINE:: The name of the Ruby implementation.
-RUBY_ENGINE_VERSION:: The version of the Ruby implementation.
-RUBY_DESCRIPTION:: The same as <tt>ruby --version</tt>, a String describing various aspects of the Ruby implementation.
diff --git a/doc/index.md b/doc/index.md
new file mode 100644
index 0000000000..596825a19c
--- /dev/null
+++ b/doc/index.md
@@ -0,0 +1,65 @@
+# Ruby Documentation
+
+Welcome to the official Ruby programming language documentation.
+
+## Getting Started
+
+New to Ruby? Start with our [Getting Started Guide](https://www.ruby-lang.org/en/documentation/quickstart/).
+
+## Core Classes and Modules
+
+Explore the essential classes and modules:
+
+- [String](String.html) - Text manipulation and string utilities.
+- [Symbol](Symbol.html) - Named identifiers inside the Ruby interpreter.
+- [Array](Array.html) - Ordered collections of objects.
+- [Hash](Hash.html) - Key-value pairs for efficient data retrieval.
+- [Integer](Integer.html) - \Integer number class.
+- [Float](Float.html) - Floating-point number class.
+- [Enumerable](Enumerable.html) - Collection traversal and searching.
+- [File](File.html) - \File operations and handling.
+- [IO](IO.html) - Input/output functionality.
+- [Time](Time.html) - \Time representation.
+- [Regexp](Regexp.html) - Regular expressions for pattern matching.
+- [Range](Range.html) - Representing a range of values.
+- [Exception](Exception.html) - Base class for all exceptions.
+- [Thread](Thread.html) - Multithreading and concurrency.
+
+## Language Reference
+
+Deep dive into Ruby's syntax and features:
+
+- [Ruby Syntax](rdoc-ref:syntax.rdoc)
+- [Exceptions](rdoc-ref:exceptions.md)
+- [Implicit Conversions](rdoc-ref:implicit_conversion.rdoc)
+
+## Standard Libraries
+
+There are some standard libraries included in Ruby that are also commonly used, such as:
+
+- [Date](Date.html) - \Date representation.
+- [JSON](JSON.html) - \JSON encoding and decoding.
+- [ERB](ERB.html) - Embedded Ruby for templating.
+- [Net::HTTP](Net/HTTP.html) - HTTP client library.
+
+Use the following links to access the comprehensive set of libraries included with Ruby:
+
+- [Standard Library Documentation](rdoc-ref:standard_library.md)
+- [Maintainers](rdoc-ref:maintainers.md)
+
+## Contribute to Ruby
+
+Get involved with the Ruby community:
+
+- [Contribution Guide](rdoc-ref:contributing/contributing.md)
+- [Documentation Guide](rdoc-ref:contributing/documentation_guide.md)
+- [Reporting Issues](rdoc-ref:contributing/reporting_issues.md)
+- [Building Ruby](rdoc-ref:contributing/building_ruby.md)
+- [Testing Ruby](rdoc-ref:contributing/testing_ruby.md)
+- [Issue Tracker](https://bugs.ruby-lang.org/projects/ruby-master/issues)
+
+## Additional Resources
+
+- [Ruby Homepage](https://www.ruby-lang.org/)
+- [RubyGems](https://rubygems.org/)
+- [Ruby Community](https://www.ruby-lang.org/en/community/)
diff --git a/doc/irb/irb-tools.rd.ja b/doc/irb/irb-tools.rd.ja
deleted file mode 100644