escape.c documents html_escape as converting with #to_s "only if it's
not T_STRING", and the C extension implements that. The pure fallback
converted unconditionally, so a String subclass overriding to_s
escaped different bytes on JRuby than on CRuby.
https://github.com/ruby/erb/commit/0f8b6ce9ce
The recent change to use `BasicObject.instance_method(:equal?)` broke
the ability to share frozen ERB templates across Ractors because
`UnboundMethod` isn't shareable.
Freezing the `UnboundMethod` _may_ fix the issue (dependong on Ruby
version), but replacing the constant with an inline call to the
`singleton_class` is simpler (and still avoids calling `equal?` on
`@init`).
There have previously been many contributions to make ERB Ractor safe,
but no tests added to ensure it continues to be Ractor safe, so this
commit also adds some regression tests.
https://github.com/ruby/erb/commit/75f1ea059e
The guard for methods that eval ERB source compared @_init with self.class.singleton_class by calling equal? on @_init. A marshal-loaded object can control @_init, so make the comparison through BasicObject#equal? directly instead of dispatching to the restored object.
This keeps normal ERB instances working while preserving the ArgumentError for marshal-loaded instances.
https://github.com/ruby/erb/commit/4bf35f1749
Extends the @_init guard to def_method so that an ERB object created
via Marshal.load (which bypasses initialize) raises ArgumentError
instead of evaluating arbitrary source. def_module and def_class both
delegate to def_method and are covered by the same check.
https://github.com/ruby/erb/commit/9d017be4e3
Co-authored-by: Tristan Madani <TristanInSec@gmail.com>
This commit inlines instructions for Class#new. To make this work, we
added a new YARV instructions, `opt_new`. `opt_new` checks whether or
not the `new` method is the default allocator method. If it is, it
allocates the object, and pushes the instance on the stack. If not, the
instruction jumps to the "slow path" method call instructions.
Old instructions:
```
> ruby --dump=insns -e'Object.new'
== disasm: #<ISeq:<main>@-e:1 (1,0)-(1,10)>
0000 opt_getconstant_path <ic:0 Object> ( 1)[Li]
0002 opt_send_without_block <calldata!mid:new, argc:0, ARGS_SIMPLE>
0004 leave
```
New instructions:
```
> ./miniruby --dump=insns -e'Object.new'
== disasm: #<ISeq:<main>@-e:1 (1,0)-(1,10)>
0000 opt_getconstant_path <ic:0 Object> ( 1)[Li]
0002 putnil
0003 swap
0004 opt_new <calldata!mid:new, argc:0, ARGS_SIMPLE>, 11
0007 opt_send_without_block <calldata!mid:initialize, argc:0, FCALL|ARGS_SIMPLE>
0009 jump 14
0011 opt_send_without_block <calldata!mid:new, argc:0, ARGS_SIMPLE>
0013 swap
0014 pop
0015 leave
```
This commit speeds up basic object allocation (`Foo.new`) by 60%, but
classes that take keyword parameters see an even bigger benefit because
no hash is allocated when instantiating the object (3x to 6x faster).
Here is an example that uses `Hash.new(capacity: 0)`:
```
> hyperfine "ruby --disable-gems -e'i = 0; while i < 10_000_000; Hash.new(capacity: 0); i += 1; end'" "./ruby --disable-gems -e'i = 0; while i < 10_000_000; Hash.new(capacity: 0); i += 1; end'"
Benchmark 1: ruby --disable-gems -e'i = 0; while i < 10_000_000; Hash.new(capacity: 0); i += 1; end'
Time (mean ± σ): 1.082 s ± 0.004 s [User: 1.074 s, System: 0.008 s]
Range (min … max): 1.076 s … 1.088 s 10 runs
Benchmark 2: ./ruby --disable-gems -e'i = 0; while i < 10_000_000; Hash.new(capacity: 0); i += 1; end'
Time (mean ± σ): 627.9 ms ± 3.5 ms [User: 622.7 ms, System: 4.8 ms]
Range (min … max): 622.7 ms … 633.2 ms 10 runs
Summary
./ruby --disable-gems -e'i = 0; while i < 10_000_000; Hash.new(capacity: 0); i += 1; end' ran
1.72 ± 0.01 times faster than ruby --disable-gems -e'i = 0; while i < 10_000_000; Hash.new(capacity: 0); i += 1; end'
```
This commit changes the backtrace for `initialize`:
```
aaron@tc ~/g/ruby (inline-new)> cat test.rb
class Foo
def initialize
puts caller
end
end
def hello
Foo.new
end
hello
aaron@tc ~/g/ruby (inline-new)> ruby -v test.rb
ruby 3.4.2 (2025-02-15 revision d2930f8e7a) +PRISM [arm64-darwin24]
test.rb:8:in 'Class#new'
test.rb:8:in 'Object#hello'
test.rb:11:in '<main>'
aaron@tc ~/g/ruby (inline-new)> ./miniruby -v test.rb
ruby 3.5.0dev (2025-03-28T23:59:40Z inline-new c4157884e4) +PRISM [arm64-darwin24]
test.rb:8:in 'Object#hello'
test.rb:11:in '<main>'
```
It also increases memory usage for calls to `new` by 122 bytes:
```
aaron@tc ~/g/ruby (inline-new)> cat test.rb
require "objspace"
class Foo
def initialize
puts caller
end
end
def hello
Foo.new
end
puts ObjectSpace.memsize_of(RubyVM::InstructionSequence.of(method(:hello)))
aaron@tc ~/g/ruby (inline-new)> make runruby
RUBY_ON_BUG='gdb -x ./.gdbinit -p' ./miniruby -I./lib -I. -I.ext/common ./tool/runruby.rb --extout=.ext -- --disable-gems ./test.rb
656
aaron@tc ~/g/ruby (inline-new)> ruby -v test.rb
ruby 3.4.2 (2025-02-15 revision d2930f8e7a) +PRISM [arm64-darwin24]
544
```
Thanks to @ko1 for coming up with this idea!
Co-Authored-By: John Hawthorn <john@hawthorn.email>
We attempted to remove things like this and reverted all of them, but I
think nobody relies on this unlike the positional arguments of
`ERB#initialize`.
https://github.com/ruby/erb/commit/92fde7e403
(https://github.com/ruby/erb/pull/34)
There seems to be no way to fix this. It doesn't happen in an installed
directory, so it's likely a false positive and/or a bug in rubygems.
| <internal:/home/runner/.rubies/ruby-head/lib/ruby/3.2.0+3/rubygems/core_ext/kernel_require.rb>:85: warning: <internal:/home/runner/.rubies/ruby-head/lib/ruby/3.2.0+3/rubygems/core_ext/kernel_require.rb>:85: warning: loading in progress, circular require considered harmful - /home/runner/.rubies/ruby-head/lib/ruby/3.2.0+3/bundler/setup.rb
| from /home/runner/work/erb/erb/libexec/erb:0:in `require'
| from /home/runner/.rubies/ruby-head/lib/ruby/3.2.0+3/bundler/setup.rb:3:in `<top (required)>'
| from /home/runner/.rubies/ruby-head/lib/ruby/3.2.0+3/bundler/setup.rb:3:in `require_relative'
| from /home/runner/.rubies/ruby-head/lib/ruby/3.2.0+3/bundler/shared_helpers.rb:8:in `<top (required)>'
| from /home/runner/.rubies/ruby-head/lib/ruby/3.2.0+3/bundler/shared_helpers.rb:8:in `require_relative'
| from /home/runner/.rubies/ruby-head/lib/ruby/3.2.0+3/bundler/rubygems_integration.rb:3:in `<top (required)>'
| from /home/runner/.rubies/ruby-head/lib/ruby/3.2.0+3/bundler/rubygems_integration.rb:3:in `require'
| from /home/runner/.rubies/ruby-head/lib/ruby/3.2.0+3/rubygems.rb:1352:in `<top (required)>'
| from <internal:/home/runner/.rubies/ruby-head/lib/ruby/3.2.0+3/rubygems/core_ext/kernel_require.rb>:85:in `require'
| from <internal:/home/runner/.rubies/ruby-head/lib/ruby/3.2.0+3/rubygems/core_ext/kernel_require.rb>:85:in `require'
because, when Ruby 3.1 is released, Ruby 2.5, the last version with the
old method signature, will have been EOL. Therefore we can safely warn
the old interface from Ruby 3.1.
https://github.com/ruby/erb/commit/c3a753f49f
is given.
This is merging Eric's patch in [Bug #15479] to Ruby 2.6's behavior in r66631.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@66632 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This reverts commit b5569b9ab2.
The deprecation is indefinitely postponed.
[Bug #15478]
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@66631 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This was planned to be removed in Ruby 2.7 at first, but I changed my
mind to just keep warning it in Ruby 2.7.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@66556 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Also, as it's in the middle of the list of 4 arguments, 3rd and 4th arguments
(trim_mode, eoutvar) are changed to keyword arguments.
Old ways to specify arguments are deprecated and warned now.
bin/erb: deprecate -S option.
We'll remove all of deprecated ones at Ruby 2.7+.
enc/make_encmake.rb: stopped using deprecated interface
ext/etc/mkconstants.rb: ditto
ext/socket/mkconstants.rb: ditto
sample/ripper/ruby2html.rb: ditto
spec/ruby/library/erb/defmethod/def_erb_method_spec.rb: ditto
spec/ruby/library/erb/new_spec.rb: ditto
test/erb/test_erb.rb: ditto
test/erb/test_erb_command.rb: ditto
tool/generic_erb.rb: ditto
tool/ruby_vm/helpers/dumper.rb: ditto
tool/transcode-tblgen.rb: ditto
lib/rdoc/erbio.rb: ditto
lib/rdoc/generator/darkfish.rb: ditto
[Feature #14256]
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@62529 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
comment. Fix regression at r58948.
I even don't want to deprecate it because deprecation needs to lex all
embedded Ruby script using Ripper and it would be slow. So Let me just
keep this behavior of Ruby 2.4. No change is the best compatibility.
This commit stopped using String#-@ because it's harmful for "ambiguous
first argument" warning if we really want to maintain this behavior.
[Bug #14243]
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@61497 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
* lib/erb.rb (ERB#new_toplevel): shadow already defined local
variables by block local variabes, not to overwrite them.
[ruby-core:84390] [Bug #14215]
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@61411 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Unlike Ruby source file encoding (script encoding) whose default is
changed to UTF-8 in Ruby 2.0 (Feature #6679), template's file encoding
given to erb(1) has been ASCII-8BIT since ERB supports m17n at r21170.
Like Ruby source file encoding, erb template file encoding should be
UTF-8 in Ruby 2.
[Bug #14095] [ruby-core:83708]
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@60739 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
when trim_mode is "-", for Windows environments.
[ruby-core:39625] [Bug #5339]
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@58825 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
when trim_mode is "<>", for Windows environments.
[Bug #11464]
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@58823 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Based on patch by madeofcode (Mark Dodwell).
[ruby-core:46168] [Bug #6696] [Fix GH-54]
`~` is a unreserved character.
https://tools.ietf.org/html/rfc3986#section-2.3
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@58772 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
* lib/erb.rb (ERB::Compiler#detect_magic_comment): allow
fronzen-string-literal in comment as well as encoding.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@53685 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
* test/erb/test_erb.rb: improve failure messages with
assert_respond_to and assert_not_respond_to.
* test/erb/test_erb.rb: use assert_raise instead of assert(false).
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@53683 b2dd03c8-39d4-4d8f-98ff-823fe69b080e