rails--rails/activemodel/lib
Jean Boussier bf33510d86 Optimize CurrentAttributes method generation
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
```
2021-11-02 15:52:25 +01:00
..
active_model Optimize CurrentAttributes method generation 2021-11-02 15:52:25 +01:00
active_model.rb