diff --git a/.github/workflows/ubuntu-ibm.yml b/.github/workflows/ubuntu-ibm.yml deleted file mode 100644 index 8bcce6e4a1867e..00000000000000 --- a/.github/workflows/ubuntu-ibm.yml +++ /dev/null @@ -1,183 +0,0 @@ -name: Ubuntu IBM -on: - push: - paths-ignore: - - 'doc/**' - - '**/man/*' - - '**.md' - - '**.rdoc' - - '**/.document' - - '.*.yml' - pull_request: - # Do not use paths-ignore for required status checks - # https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/collaborating-on-repositories-with-code-quality-features/troubleshooting-required-status-checks#handling-skipped-but-required-checks - merge_group: - -concurrency: - group: ${{ github.workflow }} / ${{ startsWith(github.event_name, 'pull') && github.ref_name || github.sha }} - cancel-in-progress: ${{ startsWith(github.event_name, 'pull') }} - -permissions: - contents: read - -jobs: - make: - strategy: - matrix: - test_task: [check] - configure: [''] - os: - - ubuntu-24.04-ppc64le - - ubuntu-24.04-s390x - # Add a x86_64 case to make this CI pass on fork repositories. - - ubuntu-24.04 - # The ppc64le/s390x runners work only in the registered repositories. - # They don't work in forked repositories. - # https://github.com/IBM/actionspz/blob/main/docs/FAQ.md#what-about-forked-repos - upstream: - - ${{ github.repository == 'ruby/ruby' }} - exclude: - - os: ubuntu-24.04-ppc64le - upstream: false - - os: ubuntu-24.04-s390x - upstream: false - - os: ubuntu-24.04 - upstream: true - fail-fast: false - - env: - GITPULLOPTIONS: --no-tags origin ${{ github.ref }} - RUBY_DEBUG: ci - - runs-on: ${{ matrix.os }} - - if: >- - ${{!(false - || contains(github.event.head_commit.message, '[DOC]') - || contains(github.event.pull_request.title, '[DOC]') - || contains(github.event.pull_request.labels.*.name, 'Documentation') - || (github.event_name == 'push' && github.event.pull_request.user.login == 'dependabot[bot]') - )}} - - steps: - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 - with: - sparse-checkout-cone-mode: false - sparse-checkout: /.github - - - uses: ./.github/actions/setup/ubuntu - - - uses: ruby/setup-ruby@a9bfc2ecf3dd40734a9418f89a7e9d484c32b990 # v1.248.0 - with: - ruby-version: '3.1' - bundler: none - if: ${{ !endsWith(matrix.os, 'ppc64le') && !endsWith(matrix.os, 's390x') }} - - # Avoid possible test failures with the zlib applying the following patch - # on s390x CPU architecture. - # https://github.com/madler/zlib/pull/410 - - name: Disable DFLTCC - run: echo "DFLTCC=0" >> $GITHUB_ENV - working-directory: - if: ${{ endsWith(matrix.os, 's390x') }} - - # A temporary workaround: Set HOME env to pass the step - # ./.github/actions/setup/directories. - # https://github.com/IBM/actionspz/issues/30 - - name: Set HOME env - run: | - echo "HOME: ${HOME}" - echo "HOME=$(ls -d ~)" >> $GITHUB_ENV - working-directory: - if: ${{ endsWith(matrix.os, 'ppc64le') || endsWith(matrix.os, 's390x') }} - - - uses: ./.github/actions/setup/directories - with: - srcdir: src - builddir: build - makeup: true - clean: true - dummy-files: ${{ matrix.test_task == 'check' }} - # Set fetch-depth: 10 so that Launchable can receive commits information. - fetch-depth: 10 - - - name: Run configure - env: - configure: ${{ matrix.configure }} - run: >- - ../src/configure -C --disable-install-doc ${configure:-cppflags=-DRUBY_DEBUG} - - - run: make - - - run: make hello - - - name: runirb - run: | - echo IRB::VERSION | make runirb RUNOPT="-- -f" - - - name: Set test options for skipped tests - run: | - set -x - TESTS="$(echo "${{ matrix.skipped_tests }}" | sed 's| |$$/ -n!/|g;s|^|-n!/|;s|$|$$/|')" - echo "TESTS=${TESTS}" >> $GITHUB_ENV - if: ${{ matrix.test_task == 'check' && matrix.skipped_tests }} - - - name: Set up Launchable - id: launchable - uses: ./.github/actions/launchable/setup - with: - os: ${{ matrix.os }} - test-opts: ${{ matrix.configure }} - launchable-token: ${{ secrets.LAUNCHABLE_TOKEN }} - builddir: build - srcdir: src - continue-on-error: true - timeout-minutes: 3 - - # A temporary workaround: Set the user's primary group to avoid a mismatch - # between the group IDs of "id -g" and C function getpwuid(uid_t uid) - # pw_gid. - # https://github.com/IBM/actionspz/issues/31 - - name: Set user's group id - run: sudo usermod -g "$(id -g)" runner - if: ${{ endsWith(matrix.os, 'ppc64le') || endsWith(matrix.os, 's390x') }} - - - name: make ${{ matrix.test_task }} - run: | - test -n "${LAUNCHABLE_STDOUT}" && exec 1> >(tee "${LAUNCHABLE_STDOUT}") - test -n "${LAUNCHABLE_STDERR}" && exec 2> >(tee "${LAUNCHABLE_STDERR}") - - make -s ${{ matrix.test_task }} \ - ${TESTS:+TESTS="$TESTS"} \ - ${{ !contains(matrix.test_task, 'bundle') && 'RUBYOPT=-w' || '' }} - timeout-minutes: ${{ matrix.timeout || 40 }} - env: - RUBY_TESTOPTS: '-q --tty=no' - TEST_BUNDLED_GEMS_ALLOW_FAILURES: '' - PRECHECK_BUNDLED_GEMS: 'no' - LAUNCHABLE_STDOUT: ${{ steps.launchable.outputs.stdout_report_path }} - LAUNCHABLE_STDERR: ${{ steps.launchable.outputs.stderr_report_path }} - - - name: make skipped tests - run: | - make -s test-all TESTS="${TESTS//-n!\//-n/}" - env: - GNUMAKEFLAGS: '' - RUBY_TESTOPTS: '-v --tty=no' - if: ${{ matrix.test_task == 'check' && matrix.skipped_tests }} - continue-on-error: ${{ matrix.continue-on-skipped_tests || false }} - - - name: test-pc - run: | - DESTDIR=${RUNNER_TEMP-${TMPDIR-/tmp}}/installed - make test-pc "DESTDIR=$DESTDIR" - - - uses: ./.github/actions/slack - with: - label: ${{ matrix.test_task }} ${{ matrix.configure }} - SLACK_WEBHOOK_URL: ${{ secrets.SIMPLER_ALERTS_URL }} # ruby-lang slack: ruby/simpler-alerts-bot - if: ${{ failure() }} - -defaults: - run: - working-directory: build diff --git a/.github/workflows/ubuntu.yml b/.github/workflows/ubuntu.yml index 4358e4c3a7e8ce..6174e991708704 100644 --- a/.github/workflows/ubuntu.yml +++ b/.github/workflows/ubuntu.yml @@ -45,7 +45,7 @@ jobs: extra_checks: [capi] fail-fast: false - env: + env: &make-env GITPULLOPTIONS: --no-tags origin ${{ github.ref }} RUBY_DEBUG: ci @@ -59,7 +59,7 @@ jobs: || (github.event_name == 'push' && github.event.pull_request.user.login == 'dependabot[bot]') )}} - steps: + steps: &make-steps - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 with: sparse-checkout-cone-mode: false @@ -73,7 +73,19 @@ jobs: with: ruby-version: '3.1' bundler: none - if: ${{ !endsWith(matrix.os, 'arm') }} + if: >- + ${{ !endsWith(matrix.os, 'arm') + && !endsWith(matrix.os, 'ppc64le') && !endsWith(matrix.os, 's390x') }} + + # A temporary workaround: Set HOME env to pass the step + # ./.github/actions/setup/directories. + # https://github.com/IBM/actionspz/issues/30 + - name: Set HOME env + run: | + echo "HOME: ${HOME}" + echo "HOME=$(ls -d ~)" >> $GITHUB_ENV + working-directory: + if: ${{ endsWith(matrix.os, 'ppc64le') || endsWith(matrix.os, 's390x') }} - uses: ./.github/actions/setup/directories with: @@ -123,6 +135,21 @@ jobs: continue-on-error: true timeout-minutes: 3 + # Avoid possible test failures with the zlib applying the following patch + # on s390x CPU architecture. + # https://github.com/madler/zlib/pull/410 + - name: Disable DFLTCC + run: echo "DFLTCC=0" >> $GITHUB_ENV + if: ${{ endsWith(matrix.os, 's390x') }} + + # A temporary workaround: Set the user's primary group to avoid a mismatch + # between the group IDs of "id -g" and C function getpwuid(uid_t uid) + # pw_gid. + # https://github.com/IBM/actionspz/issues/31 + - name: Set user's group id + run: sudo usermod -g "$(id -g)" runner + if: ${{ endsWith(matrix.os, 'ppc64le') || endsWith(matrix.os, 's390x') }} + - name: make ${{ matrix.test_task }} run: | test -n "${LAUNCHABLE_STDOUT}" && exec 1> >(tee "${LAUNCHABLE_STDOUT}") @@ -168,6 +195,31 @@ jobs: SLACK_WEBHOOK_URL: ${{ secrets.SIMPLER_ALERTS_URL }} # ruby-lang slack: ruby/simpler-alerts-bot if: ${{ failure() }} + make-ibm: + strategy: + matrix: + include: + - test_task: check + os: ubuntu-24.04-ppc64le + - test_task: check + os: ubuntu-24.04-s390x + fail-fast: false + + env: *make-env + + runs-on: ${{ matrix.os }} + + if: >- + ${{github.repository == 'ruby/ruby' + && !(false + || contains(github.event.head_commit.message, '[DOC]') + || contains(github.event.pull_request.title, '[DOC]') + || contains(github.event.pull_request.labels.*.name, 'Documentation') + || (github.event_name == 'push' && github.event.pull_request.user.login == 'dependabot[bot]') + )}} + + steps: *make-steps + result: if: ${{ always() }} name: ${{ github.workflow }} result diff --git a/gc/default/default.c b/gc/default/default.c index 423d27dde11c84..b5879b0ec25e7c 100644 --- a/gc/default/default.c +++ b/gc/default/default.c @@ -577,7 +577,9 @@ typedef struct rb_objspace { VALUE gc_stress_mode; struct { + bool parent_object_old_p; VALUE parent_object; + int need_major_gc; size_t last_major_gc; size_t uncollectible_wb_unprotected_objects; @@ -4309,15 +4311,11 @@ init_mark_stack(mark_stack_t *stack) static void rgengc_check_relation(rb_objspace_t *objspace, VALUE obj) { - const VALUE old_parent = objspace->rgengc.parent_object; - - if (old_parent) { /* parent object is old */ + if (objspace->rgengc.parent_object_old_p) { if (RVALUE_WB_UNPROTECTED(objspace, obj) || !RVALUE_OLD_P(objspace, obj)) { - rgengc_remember(objspace, old_parent); + rgengc_remember(objspace, objspace->rgengc.parent_object); } } - - GC_ASSERT(old_parent == objspace->rgengc.parent_object); } static inline int @@ -4385,12 +4383,7 @@ gc_mark_check_t_none(rb_objspace_t *objspace, VALUE obj) rb_raw_obj_info(obj_info_buf, info_size, obj); char parent_obj_info_buf[info_size]; - if (objspace->rgengc.parent_object == Qfalse) { - strlcpy(parent_obj_info_buf, "(none)", info_size); - } - else { - rb_raw_obj_info(parent_obj_info_buf, info_size, objspace->rgengc.parent_object); - } + rb_raw_obj_info(parent_obj_info_buf, info_size, objspace->rgengc.parent_object); rb_bug("try to mark T_NONE object (obj: %s, parent: %s)", obj_info_buf, parent_obj_info_buf); } @@ -4405,14 +4398,9 @@ gc_mark(rb_objspace_t *objspace, VALUE obj) if (!gc_mark_set(objspace, obj)) return; /* already marked */ if (0) { // for debug GC marking miss - if (objspace->rgengc.parent_object) { - RUBY_DEBUG_LOG("%p (%s) parent:%p (%s)", - (void *)obj, obj_type_name(obj), - (void *)objspace->rgengc.parent_object, obj_type_name(objspace->rgengc.parent_object)); - } - else { - RUBY_DEBUG_LOG("%p (%s)", (void *)obj, obj_type_name(obj)); - } + RUBY_DEBUG_LOG("%p (%s) parent:%p (%s)", + (void *)obj, obj_type_name(obj), + (void *)objspace->rgengc.parent_object, obj_type_name(objspace->rgengc.parent_object)); } gc_mark_check_t_none(objspace, obj); @@ -4505,8 +4493,6 @@ rb_gc_impl_mark_weak(void *objspace_ptr, VALUE *ptr) { rb_objspace_t *objspace = objspace_ptr; - GC_ASSERT(objspace->rgengc.parent_object == 0 || !RVALUE_WB_UNPROTECTED(objspace, objspace->rgengc.parent_object)); - VALUE obj = *ptr; gc_mark_check_t_none(objspace, obj); @@ -4565,7 +4551,8 @@ mark_roots(rb_objspace_t *objspace, const char **categoryp) } while (0) MARK_CHECKPOINT("objspace"); - objspace->rgengc.parent_object = Qfalse; + objspace->rgengc.parent_object = Qundef; + objspace->rgengc.parent_object_old_p = false; if (finalizer_table != NULL) { st_foreach(finalizer_table, pin_value, (st_data_t)objspace); @@ -4580,12 +4567,8 @@ mark_roots(rb_objspace_t *objspace, const char **categoryp) static inline void gc_mark_set_parent(rb_objspace_t *objspace, VALUE obj) { - if (RVALUE_OLD_P(objspace, obj)) { - objspace->rgengc.parent_object = obj; - } - else { - objspace->rgengc.parent_object = Qfalse; - } + objspace->rgengc.parent_object = obj; + objspace->rgengc.parent_object_old_p = RVALUE_OLD_P(objspace, obj); } static void diff --git a/lib/erb.rb b/lib/erb.rb index b9b4ef7a1deec3..884a63035c1564 100644 --- a/lib/erb.rb +++ b/lib/erb.rb @@ -12,6 +12,24 @@ # # You can redistribute it and/or modify it under the same terms as Ruby. +# A NOTE ABOUT TERMS: +# +# Formerly: The documentation in this file used the term _template_ to refer to an ERB object. +# +# Now: The documentation in this file uses the term _template_ +# to refer to the string input to ERB.new. +# +# The reason for the change: When documenting the ERB executable erb, +# we need a term that refers to its string input; +# _source_ is not a good idea, because ERB#src means something entirely different; +# the two different sorts of sources would bring confusion. +# +# Therefore we use the term _template_ to refer to: +# +# - The string input to ERB.new +# - The string input to executable erb. +# + require 'erb/version' require 'erb/compiler' require 'erb/def_method' @@ -22,15 +40,6 @@ # Class **ERB** (the name stands for **Embedded Ruby**) # is an easy-to-use, but also very powerful, [template processor][template processor]. # -# Like method [sprintf][sprintf], \ERB can format run-time data into a string. -# \ERB, however,s is *much more powerful*. -# -# \ERB is commonly used to produce: -# -# - Customized or personalized email messages. -# - Customized or personalized web pages. -# - Software code (in code-generating applications). -# # ## Usage # # Before you can use \ERB, you must first require it @@ -44,7 +53,8 @@ # # Here's how \ERB works: # -# - You can create an \ERB object (a *template*) to store text that includes specially formatted *tags*. +# - You can create a *template*: a plain-text string that includes specially formatted *tags*.. +# - You can create an \ERB object to store the template. # - You can call instance method ERB#result to get the *result*. # # \ERB supports tags of three kinds: @@ -53,83 +63,85 @@ # each begins with `'<%'`, ends with `'%>'`; contains a Ruby expression; # in the result, the value of the expression replaces the entire tag: # +# template = 'The magic word is <%= magic_word %>.' +# erb = ERB.new(template) # magic_word = 'xyzzy' -# template.result(binding) # => "The magic word is xyzzy." -# -# ERB.new('Today is <%= Date::DAYNAMES[Date.today.wday] %>.').result # => "Today is Monday." +# erb.result(binding) # => "The magic word is xyzzy." # -# The first call to #result passes argument `binding`, +# The above call to #result passes argument `binding`, # which contains the binding of variable `magic_word` to its string value `'xyzzy'`. # -# The second call need not pass a binding, +# The below call to #result need not pass a binding, # because its expression `Date::DAYNAMES` is globally defined. # +# ERB.new('Today is <%= Date::DAYNAMES[Date.today.wday] %>.').result # => "Today is Monday." +# # - [Execution tags][execution tags]: # each begins with `'<%='`, ends with `'%>'`; contains Ruby code to be executed: # -# s = '<% File.write("t.txt", "Some stuff.") %>' -# ERB.new(s).result +# template = '<% File.write("t.txt", "Some stuff.") %>' +# ERB.new(template).result # File.read('t.txt') # => "Some stuff." # # - [Comment tags][comment tags]: # each begins with `'<%#'`, ends with `'%>'`; contains comment text; # in the result, the entire tag is omitted. # -# s = 'Some stuff;<%# Note to self: figure out what the stuff is. %> more stuff.' -# ERB.new(s).result # => "Some stuff; more stuff." +# template = 'Some stuff;<%# Note to self: figure out what the stuff is. %> more stuff.' +# ERB.new(template).result # => "Some stuff; more stuff." # # ## Some Simple Examples # # Here's a simple example of \ERB in action: # # ``` -# s = 'The time is <%= Time.now %>.' -# template = ERB.new(s) -# template.result +# template = 'The time is <%= Time.now %>.' +# erb = ERB.new(template) +# erb.result # # => "The time is 2025-09-09 10:49:26 -0500." # ``` # # Details: # -# 1. A plain-text string is assigned to variable `s`. +# 1. A plain-text string is assigned to variable `template`. # Its embedded [expression tag][expression tags] `'<%= Time.now %>'` includes a Ruby expression, `Time.now`. -# 2. The string is put into a new \ERB object, and stored in variable `template`. -# 4. Method call `template.result` generates a string that contains the run-time value of `Time.now`, +# 2. The string is put into a new \ERB object, and stored in variable `erb`. +# 4. Method call `erb.result` generates a string that contains the run-time value of `Time.now`, # as computed at the time of the call. # -# The template may be re-used: +# The +# \ERB object may be re-used: # # ``` -# template.result +# erb.result # # => "The time is 2025-09-09 10:49:33 -0500." # ``` # # Another example: # # ``` -# s = 'The magic word is <%= magic_word %>.' -# template = ERB.new(s) +# template = 'The magic word is <%= magic_word %>.' +# erb = ERB.new(template) # magic_word = 'abracadabra' -# # => "abracadabra" -# template.result(binding) +# erb.result(binding) # # => "The magic word is abracadabra." # ``` # # Details: # -# 1. As before, a plain-text string is assigned to variable `s`. +# 1. As before, a plain-text string is assigned to variable `template`. # Its embedded [expression tag][expression tags] `'<%= magic_word %>'` has a variable *name*, `magic_word`. -# 2. The string is put into a new \ERB object, and stored in variable `template`; +# 2. The string is put into a new \ERB object, and stored in variable `erb`; # note that `magic_word` need not be defined before the \ERB object is created. # 3. `magic_word = 'abracadabra'` assigns a value to variable `magic_word`. -# 4. Method call `template.result(binding)` generates a string +# 4. Method call `erb.result(binding)` generates a string # that contains the *value* of `magic_word`. # -# As before, the template may be re-used: +# As before, the \ERB object may be re-used: # # ``` # magic_word = 'xyzzy' -# template.result(binding) +# erb.result(binding) # # => "The magic word is xyzzy." # ``` # @@ -157,18 +169,17 @@ # these expression tags refer only to Ruby's global constant `RUBY_COPYRIGHT` and global variable `$0`: # # ``` -# s = <. # The current process is <%= $0 %>. -# EOT -# puts ERB.new(s).result +# TEMPLATE +# puts ERB.new(template).result # The Ruby copyright is "ruby - Copyright (C) 1993-2025 Yukihiro Matsumoto". # The current process is irb. # ``` # # (The current process is `irb` because that's where we're doing these examples!) # -# # ### Local Binding # # The default binding is *not* sufficient for an expression @@ -177,26 +188,27 @@ # ``` # Foo = 1 # Defines local constant Foo. # foo = 2 # Defines local variable foo. -# s = <. # The current value of variable foo is <%= foo %>. # The Ruby copyright is <%= RUBY_COPYRIGHT.inspect %>. # The current process is <%= $0 %>. -# EOT +# TEMPLATE +# erb = ERB.new(template) # ``` # -# This call raises `NameError` because although `Foo` and `foo` are defined locally, +# This call below raises `NameError` because although `Foo` and `foo` are defined locally, # they are not defined in the default binding: # # ``` -# ERB.new(s).result # Raises NameError. +# erb.result # Raises NameError. # ``` # # To make the locally-defined constants and variables available, # you can call #result with the local binding: # # ``` -# puts ERB.new(s).result(binding) +# puts erb.result(binding) # The current value of constant Foo is 1. # The current value of variable foo is 2. # The Ruby copyright is "ruby - Copyright (C) 1993-2025 Yukihiro Matsumoto". @@ -211,19 +223,21 @@ # in a copy of the default binding: # # ``` -# s = <. # The current value of variable baz is <%= baz %>. # The Ruby copyright is <%= RUBY_COPYRIGHT.inspect %>. # The current process is <%= $0 %>. +# TEMPLATE +# erb = ERB.new(template) # ``` # # Both of these calls raise `NameError`, because `bar` and `baz` # are not defined in either the default binding or the local binding. # # ``` -# puts ERB.new(s).result # Raises NameError. -# puts ERB.new(s).result(binding) # Raises NameError. +# puts erb.result # Raises NameError. +# puts erb.result(binding) # Raises NameError. # ``` # # This call passes a hash that causes `bar` and `baz` to be defined @@ -231,14 +245,11 @@ # # ``` # hash = {bar: 3, baz: 4} -# # => {bar: 3, baz: 4} -# ERB.new(s).result_with_hash(hash) -# puts ERB.new(s).result_with_hash(variables) +# puts erb.result_with_hash(hash) # The current value of variable bar is 3. # The current value of variable baz is 4. # The Ruby copyright is "ruby - Copyright (C) 1993-2025 Yukihiro Matsumoto". # The current process is irb. -# EOT # ``` # # ## Tags @@ -246,7 +257,7 @@ # The examples above use expression tags. # These are the tags available in \ERB: # -# - [Expression tag][expression tags]: the tag contains a Ruby exprssion; +# - [Expression tag][expression tags]: the tag contains a Ruby expression; # in the result, the entire tag is to be replaced with the run-time value of the expression. # - [Execution tag][execution tags]: the tag contains Ruby code; # in the result, the entire tag is to be replaced with the run-time value of the code. @@ -310,19 +321,19 @@ # Conditional: # # ``` -# s = < # An error has occurred. # <% else %> # Oops! # <% end %> -# EOT -# template = ERB.new(s) +# TEMPLATE +# erb = ERB.new(template) # verbosity = true -# template.result(binding) +# erb.result(binding) # # => "\nAn error has occurred.\n\n" # verbosity = false -# template.result(binding) +# erb.result(binding) # # => "\nOops!\n\n" # ``` # @@ -331,12 +342,12 @@ # Loop: # # ``` -# s = < # <%= dayname %> # <% end %> -# EOT -# ERB.new(s).result +# TEMPLATE +# ERB.new(template).result # # => "\nSun\n\nMon\n\nTue\n\nWed\n\nThu\n\nFri\n\nSat\n\n" # ``` # @@ -344,20 +355,20 @@ # and the Ruby code may itself contain regular Ruby comments: # # ``` -# s = < # <%= Time.now %> # <% sleep(1) # Let's make the times different. %> # <% end %> -# EOT -# ERB.new(s).result +# TEMPLATE +# ERB.new(template).result # # => "\n2025-09-09 11:36:02 -0500\n\n\n2025-09-09 11:36:03 -0500\n\n\n2025-09-09 11:36:04 -0500\n\n\n" # ``` # # The execution tag may also contain multiple lines of code: # # ``` -# s = < -# EOT -# ERB.new(s).result +# TEMPLATE +# ERB.new(template).result # # => "\n* 0,0\n\n* 0,1\n\n* 0,2\n\n* 1,0\n\n* 1,1\n\n* 1,2\n\n* 2,0\n\n* 2,1\n\n* 2,2\n\n" # ``` # @@ -378,16 +389,16 @@ # this example uses the shorthand format `% _code_` instead of `<% _code_ %>`: # # ``` -# s = < # % end -# EOT -# template = ERB.new(s, trim_mode: '%') +# TEMPLATE +# erb = ERB.new(template, trim_mode: '%') # priorities = [ 'Run Ruby Quiz', # 'Document Modules', # 'Answer Questions on Ruby Talk' ] -# puts template.result(binding) +# puts erb.result(binding) # * Run Ruby Quiz # * Document Modules # * Answer Questions on Ruby Talk @@ -402,12 +413,12 @@ # all blank lines go into the result: # # ``` -# s = < # <%= RUBY_VERSION %> # <% end %> -# EOT -# ERB.new(s).result.lines.each {|line| puts line.inspect } +# TEMPLATE +# ERB.new(template).result.lines.each {|line| puts line.inspect } # "\n" # "3.4.5\n" # "\n" @@ -417,38 +428,38 @@ # whose source line ends with `-%>` (instead of `%>`): # # ``` -# s = < # <%= RUBY_VERSION %> # <% end -%> -# EOT -# ERB.new(s, trim_mode: '-').result.lines.each {|line| puts line.inspect } +# TEMPLATE +# ERB.new(template, trim_mode: '-').result.lines.each {|line| puts line.inspect } # "3.4.5\n" # ``` # # It is an error to use the trailing `'-%>'` notation without `trim_mode: '-'`: # # ``` -# ERB.new(s).result.lines.each {|line| puts line.inspect } # Raises SyntaxError. +# ERB.new(template).result.lines.each {|line| puts line.inspect } # Raises SyntaxError. # ``` # # #### Suppressing Unwanted Newlines # -# Consider this input string: +# Consider this template: # # ``` -# s = < # <%= RUBY_VERSION %> # foo <% RUBY_VERSION %> # foo <%= RUBY_VERSION %> -# EOT +# TEMPLATE # ``` # # With keyword argument `trim_mode` not given, all newlines go into the result: # # ``` -# ERB.new(s).result.lines.each {|line| puts line.inspect } +# ERB.new(template).result.lines.each {|line| puts line.inspect } # "\n" # "3.4.5\n" # "foo \n" @@ -459,7 +470,7 @@ # for each line that ends with `'%<'` (regardless of its beginning): # # ``` -# ERB.new(s, trim_mode: '>').result.lines.each {|line| puts line.inspect } +# ERB.new(template, trim_mode: '>').result.lines.each {|line| puts line.inspect } # "3.4.5foo foo 3.4.5" # ``` # @@ -467,7 +478,7 @@ # for each line that both begins with `'<%'` and ends with `'%>'`: # # ``` -# ERB.new(s, trim_mode: '<>').result.lines.each {|line| puts line.inspect } +# ERB.new(template, trim_mode: '<>').result.lines.each {|line| puts line.inspect } # "3.4.5foo \n" # "foo 3.4.5\n" # ``` @@ -493,11 +504,11 @@ # Example: # # ``` -# s = 'Some stuff;<%# Note to self: figure out what the stuff is. %> more stuff.' -# ERB.new(s).result # => "Some stuff; more stuff." +# template = 'Some stuff;<%# Note to self: figure out what the stuff is. %> more stuff.' +# ERB.new(template).result # => "Some stuff; more stuff." # ``` # -# A comment tag may appear anywhere in the template text. +# A comment tag may appear anywhere in the template. # # Note that the beginning of the tag must be `'<%#'`, not `'<% #'`. # @@ -511,32 +522,32 @@ # # ## Encodings # -# An \ERB template has an [encoding][encoding], -# which is by default the encoding of the source string; +# An \ERB object has an [encoding][encoding], +# which is by default the encoding of the template string; # the result string will also have that encoding. # # ``` -# s = < -# EOT -# template = ERB.new(s) -# s.encoding # => # -# template.encoding # => # -# template.result.encoding # => # +# TEMPLATE +# erb = ERB.new(template) +# template.encoding # => # +# erb.encoding # => # +# erb.result.encoding # => # # ``` # # You can specify a different encoding by adding a [magic comment][magic comments] -# at the top of the given string: +# at the top of the given template: # # ``` -# s = < # <%# Comment. %> -# EOT -# template = ERB.new(s) -# s.encoding # => # -# template.encoding # => # -# template.result.encoding # => # +# TEMPLATE +# erb = ERB.new(template) +# template.encoding # => # +# erb.encoding # => # +# erb.result.encoding # => # # ``` # # ## Error Reporting @@ -544,8 +555,8 @@ # Consider this template (containing an error): # # ``` -# s = '<%= nosuch %>' -# template = ERB.new(s) +# template = '<%= nosuch %>' +# erb = ERB.new(template) # ``` # # When \ERB reports an error, @@ -556,9 +567,9 @@ # these initial values are reported as `'(erb)'` and `1`, respectively: # # ``` -# template.filename # => nil -# template.lineno # => 0 -# template.result +# erb.filename # => nil +# erb.lineno # => 0 +# erb.result # (erb):1:in '
': undefined local variable or method 'nosuch' for main (NameError) # ``` # @@ -566,31 +577,29 @@ # that are more meaningful in your context: # # ``` -# template.filename = 't.txt' -# # => "t.txt" -# template.lineno = 555 -# # => 555 -# template.result +# erb.filename = 't.txt' +# erb.lineno = 555 +# erb.result # t.txt:556:in '
': undefined local variable or method 'nosuch' for main (NameError) # ``` # # You can use method #location= to set both values: # # ``` -# template.location = ['u.txt', 999] -# template.result +# erb.location = ['u.txt', 999] +# erb.result # u.txt:1000:in '
': undefined local variable or method 'nosuch' for main (NameError) # ``` # -# ## Plain Text Example +# ## Plain Text with Embedded Ruby # -# Here's a plain-text string; -# it uses the literal notation `'%q{ ... }'` to define the string +# Here's a plain-text template; +# it uses the literal notation `'%q{ ... }'` to define the template # (see [%q literals][%q literals]); # this avoids problems with backslashes. # # ``` -# s = %q{ +# template = %q{ # From: James Edward Gray II # To: <%= to %> # Subject: Addressing Needs @@ -623,11 +632,11 @@ # 'Answer Questions on Ruby Talk' ] # ``` # -# Finally, make the template and get the result +# Finally, create the \ERB object and get the result # # ``` -# template = ERB.new(s, trim_mode: '%<>') -# puts template.result(binding) +# erb = ERB.new(template, trim_mode: '%<>') +# puts erb.result(binding) # # From: James Edward Gray II # To: Community Spokesman @@ -650,7 +659,7 @@ # James Edward Gray II # ``` # -# ## HTML Example +# ## HTML with Embedded Ruby # # This example shows an HTML template. # @@ -696,7 +705,7 @@ # Here's the HTML: # # ``` -# s = < # Ruby Toys -- <%= @name %> # @@ -716,14 +725,14 @@ #

# # -# EOT +# TEMPLATE # ``` # -# Finally, build the template and get the result (omitting some blank lines): +# Finally, create the \ERB object and get the result (omitting some blank lines): # # ``` -# template = ERB.new(s) -# puts template.result(toy.get_binding) +# erb = ERB.new(template) +# puts erb.result(toy.get_binding) # # Ruby Toys -- Rubysapien # @@ -785,11 +794,11 @@ def self.version # :markup: markdown # # :call-seq: - # ERB.new(string, trim_mode: nil, eoutvar: '_erbout') + # ERB.new(template, trim_mode: nil, eoutvar: '_erbout') # - # Returns a new \ERB object containing the given +string+. + # Returns a new \ERB object containing the given string +template+. # - # For details about `string`, its embedded tags, and generated results, see ERB. + # For details about `template`, its embedded tags, and generated results, see ERB. # # **Keyword Argument `trim_mode`** # @@ -825,7 +834,7 @@ def self.version # which is: # # ``` - # ERB.new(string, + # ERB.new(template, # safe_level=NOT_GIVEN, legacy_trim_mode=NOT_GIVEN, legacy_eoutvar=NOT_GIVEN, # trim_mode: nil, eoutvar: '_erbout') # ``` @@ -892,23 +901,23 @@ def make_compiler(trim_mode) # :markup: markdown # - # Returns a string containing the Ruby code that, when executed, generates the result; + # Returns the Ruby code that, when executed, generates the result; # the code is executed by method #result, # and by its wrapper methods #result_with_hash and #run: # # ``` - # s = 'The time is <%= Time.now %>.' - # template = ERB.new(s) - # template.src + # template = 'The time is <%= Time.now %>.' + # erb = ERB.new(template) + # erb.src # # => "#coding:UTF-8\n_erbout = +''; _erbout.<< \"The time is \".freeze; _erbout.<<(( Time.now ).to_s); _erbout.<< \".\".freeze; _erbout" - # template.result + # erb.result # # => "The time is 2025-09-18 15:58:08 -0500." # ``` # # In a more readable format: # # ``` - # # puts template.src.split('; ') + # # puts erb.src.split('; ') # # #coding:UTF-8 # # _erbout = +'' # # _erbout.<< "The time is ".freeze @@ -922,7 +931,7 @@ def make_compiler(trim_mode) # and can be changed via keyword argument `eoutvar`: # # ``` - # template = ERB.new(s, eoutvar: '_foo') + # erb = ERB.new(template, eoutvar: '_foo') # puts template.src.split('; ') # #coding:UTF-8 # _foo = +'' @@ -1027,7 +1036,7 @@ def run(b=new_toplevel) # :call-seq: # result(binding = new_toplevel) -> new_string # - # Returns the new string formed by processing \ERB tags found in the stored string in `self`. + # Returns the string result formed by processing \ERB tags found in the stored template in `self`. # # With no argument given, uses the default binding; # see [Default Binding][default binding]. @@ -1050,9 +1059,9 @@ def result(b=new_toplevel) # :markup: markdown # # :call-seq: - # result_with_hash(hash) -> string + # result_with_hash(hash) -> new_string # - # Returns the new string formed by processing \ERB tags found in the stored string in `self`; + # Returns the string result formed by processing \ERB tags found in the stored string in `self`; # see [Augmented Binding][augmented binding]. # # See also #result. @@ -1112,10 +1121,10 @@ def new_toplevel(vars = nil) # [error reporting]: rdoc-ref:ERB@Error+Reporting # # ``` - # s = '<%= arg1 %> <%= arg2 %>' - # template = ERB.new(s) + # template = '<%= arg1 %> <%= arg2 %>' + # erb = ERB.new(template) # MyModule = Module.new - # template.def_method(MyModule, 'render(arg1, arg2)') # => :render + # erb.def_method(MyModule, 'render(arg1, arg2)') # => :render # class MyClass; include MyModule; end # MyClass.new.render('foo', 123) # => "foo 123" # ``` @@ -1135,8 +1144,8 @@ def def_method(mod, methodname, fname='(ERB)') # Returns a new nameless module that has instance method `method_name`. # # ``` - # s = '<%= arg1 %> <%= arg2 %>' - # template = ERB.new(s) + # template = '<%= arg1 %> <%= arg2 %>' + # erb = ERB.new(template) # MyModule = template.def_module('render(arg1, arg2)') # class MyClass # include MyModule @@ -1162,14 +1171,14 @@ def def_module(methodname='erb') # Create a template from HTML that has embedded expression tags that use `@arg1` and `@arg2`: # # ``` - # html = < # #

<%= @arg1 %>

#

<%= @arg2 %>

# # - # EOT + # TEMPLATE # template = ERB.new(html) # ``` # diff --git a/lib/ipaddr.rb b/lib/ipaddr.rb index 525466bbd946ac..1ad7980e9e6480 100644 --- a/lib/ipaddr.rb +++ b/lib/ipaddr.rb @@ -381,7 +381,9 @@ def ipv4_compat if !ipv4? raise InvalidAddressError, "not an IPv4 address: #{@addr}" end - return self.clone.set(@addr, Socket::AF_INET6) + clone = self.clone.set(@addr, Socket::AF_INET6) + clone.instance_variable_set(:@mask_addr, @mask_addr | 0xffffffffffffffffffffffff00000000) + clone end # Returns a new ipaddr built by converting the IPv6 address into a diff --git a/libexec/erb b/libexec/erb index 4381671f2501b7..a1fb7457585d9b 100755 --- a/libexec/erb +++ b/libexec/erb @@ -90,29 +90,49 @@ class ERB when '-P' disable_percent = true when '--help' - raise "print this help" + raise '' when /\A-/ - raise "unknown switch #{switch.dump}" + raise "Unknown switch: #{switch.dump}" else var, val = *switch.split('=', 2) (variables ||= {})[var] = val end end rescue # usage - STDERR.puts $!.to_s - STDERR.puts File.basename($0) + - " [switches] [var=value...] [inputfile]" + message = $!.to_s + STDERR.puts message unless message.empty? + STDERR.puts 'Usage:' + STDERR.puts " #{File.basename($0)} [options] [filepaths]" STDERR.puts <'; '2' means '<>'; '-' means '%-'. + -U Set default encoding to UTF-8. + -v Set $VERBOSE to enable debugging, + --version Print ERB version string and exit. + -x Print generated Ruby source code. + -- Treat all following words as filepaths (not options). + name=value Set the variable named name to the given string value. + +Filepaths: + The erb program reads the text from all files at the filepaths as a single ERB template: + plain text, possibly with embedded ERB tags; + filepaths may be repeated. + + The pseudo-filepath '-' (hyphen character) specifies the standard input. + + If no filepaths are given, the sole input is the standard input. + +See details and examples at https://docs.ruby-lang.org/en/master/erb_executable_md.html EOU exit 1 end diff --git a/string.c b/string.c index 624c61896f01f7..a5743ceda596ce 100644 --- a/string.c +++ b/string.c @@ -10728,19 +10728,44 @@ rb_str_scan(VALUE str, VALUE pat) * call-seq: * hex -> integer * - * Interprets the leading substring of +self+ as hexadecimal; - * returns its integer value: + * Interprets the leading substring of +self+ as hexadecimal, possibly signed; + * returns its value as an integer. * - * '0xFFFF'.hex # => 65535 - * 'FFzzzFF'.hex # => 255 # Hex ends at first non-hex character, 'z'. - * 'ffzzzFF'.hex # => 255 # Case does not matter. - * '-FFzzzFF'.hex # => -255 # May have leading '-'. - * '0xFFzzzFF'.hex # => 255 # May have leading '0x'. - * '-0xFFzzzFF'.hex # => -255 # May have leading '-0x'. + * The leading substring is interpreted as hexadecimal when it begins with: * - * Returns zero if there is no such leading substring: + * - One or more character representing hexadecimal digits + * (each in one of the ranges '0'..'9', 'a'..'f', or 'A'..'F'); + * the string to be interpreted ends at the first character that does not represent a hexadecimal digit: + * + * 'f'.hex # => 15 + * '11'.hex # => 17 + * 'FFF'.hex # => 4095 + * 'fffg'.hex # => 4095 + * 'foo'.hex # => 15 # 'f' hexadecimal, 'oo' not. + * 'bar'.hex # => 186 # 'ba' hexadecimal, 'r' not. + * 'deadbeef'.hex # => 3735928559 + * + * - '0x' or '0X', followed by one or more hexadecimal digits: + * + * '0xfff'.hex # => 4095 + * '0xfffg'.hex # => 4095 + * + * Any of the above may prefixed with '-', which negates the interpreted value: + * + * '-fff'.hex # => -4095 + * '-0xFFF'.hex # => -4095 + * + * For any substring not described above, returns zero: + * + * 'xxx'.hex # => 0 + * ''.hex # => 0 + * + * Note that, unlike #oct, this method interprets only hexadecimal, + * and not binary, octal, or decimal notations: * - * 'zzz'.hex # => 0 + * '0b111'.hex # => 45329 + * '0o777'.hex # => 0 + * '0d999'.hex # => 55705 * * Related: See {Converting to Non-String}[rdoc-ref:String@Converting+to+Non--5CString]. */ diff --git a/test/test_ipaddr.rb b/test/test_ipaddr.rb index 7ecd37e9a40419..ac8921e75c8e47 100644 --- a/test/test_ipaddr.rb +++ b/test/test_ipaddr.rb @@ -196,6 +196,13 @@ def test_ipv4_compat } assert_equal("::192.168.1.2", b.to_s) assert_equal(Socket::AF_INET6, b.family) + assert_equal(128, b.prefix) + + a = IPAddr.new("192.168.0.0/16") + b = a.ipv4_compat + assert_equal("::192.168.0.0", b.to_s) + assert_equal(Socket::AF_INET6, b.family) + assert_equal(112, b.prefix) end def test_ipv4_mapped