The bulk of the optimization is to generate code rather than use
`define_method` with a closure.
```
Warming up --------------------------------------
original 207.468k i/100ms
code-generator 340.849k i/100ms
Calculating -------------------------------------
original 2.127M (± 1.1%) i/s - 10.788M in 5.073860s
code-generator 3.426M (± 0.9%) i/s - 17.383M in 5.073965s
Comparison:
code-generator: 3426241.0 i/s
original: 2126539.2 i/s - 1.61x (± 0.00) slower
```
```ruby
require 'benchmark/ips'
require 'active_support/all'
class Original < ActiveSupport::CurrentAttributes
attribute :foo
end
class CodeGen < ActiveSupport::CurrentAttributes
class << self
def attribute(*names)
ActiveSupport::CodeGenerator.batch(generated_attribute_methods, __FILE__, __LINE__) do |owner|
names.each do |name|
owner.define_cached_method(name, namespace: :current_attributes) do |batch|
batch <<
"def #{name}" <<
"attributes[:#{name}]" <<
"end"
end
owner.define_cached_method("#{name}=", namespace: :current_attributes) do |batch|
batch <<
"def #{name}=(value)" <<
"attributes[:#{name}] = value" <<
"end"
end
end
end
ActiveSupport::CodeGenerator.batch(singleton_class, __FILE__, __LINE__) do |owner|
names.each do |name|
owner.define_cached_method(name, namespace: :current_attributes_delegation) do |batch|
batch <<
"def #{name}" <<
"instance.#{name}" <<
"end"
end
owner.define_cached_method("#{name}=", namespace: :current_attributes_delegation) do |batch|
batch <<
"def #{name}=(value)" <<
"instance.#{name} = value" <<
"end"
end
end
end
end
end
attribute :foo
end
Benchmark.ips do |x|
x.report('original') { Original.foo }
x.report('code-generator') { CodeGen.foo }
x.compare!
end
```