New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add default:
support for ActiveSupport::CurrentAttributes.attribute
#50677
Add default:
support for ActiveSupport::CurrentAttributes.attribute
#50677
Conversation
Does this decrease the performance of the creation of those objects in any meaningful way? |
@rafaelfranca these are the benchmark results:
source: # frozen_string_literal: true
require "bundler/inline"
gemfile(true) do
source "https://rubygems.org"
git_source(:github) { |repo| "https://github.com/#{repo}.git" }
# Activate the gem you are reporting the issue against.
gem "activesupport", path: "."
gem "benchmark-ips"
end
require "active_support/code_generator"
require "active_support/current_attributes"
class Current < ActiveSupport::CurrentAttributes
attribute :counter
end
class CurrentWithDefaultValue < ActiveSupport::CurrentAttributes
attribute :counter, default: 0
end
class CurrentWithDefaultProc < ActiveSupport::CurrentAttributes
attribute :counter, default: -> { 0 }
end
Benchmark.ips do |x|
x.report("no default") do
instance = Current.new
instance.counter = 0
instance.counter += 1
instance.reset
end
x.report("default from value") do
instance = CurrentWithDefaultValue.new
instance.counter += 1
instance.reset
end
x.report("default from proc") do
instance = CurrentWithDefaultProc.new
instance.counter += 1
instance.reset
end
x.compare!
end |
2bda7bd
to
8f8f359
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Amazing. Can you rebase please?
Extend the `.attribute` class method to accept a `:default` option for its list of attributes: ```ruby class Current < ActiveSupport::CurrentAttributes attribute :counter, default: 0 end ``` Internally, `ActiveSupport::CurrentAttributes` will maintain a `.defaults` class attribute to determine default values during instance initialization.
8f8f359
to
d1d6b6b
Compare
value = | ||
case default | ||
when Proc then default.call | ||
else default.dup | ||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To compare to prior art, this is the code that Active Model uses when determining the default:
rails/activemodel/lib/active_model/attribute/user_provided_default.rb
Lines 17 to 23 in beb6214
def value_before_type_cast | |
if user_provided_value.is_a?(Proc) | |
@memoized_value_before_type_cast ||= user_provided_value.call | |
else | |
@user_provided_value | |
end | |
end |
Follow-up to rails#50677. Prior to this commit, all `ActiveSupport::CurrentAttributes` subclasses stored their default values in the same `Hash`, causing default values to leak between classes. This commit ensures each subclass maintains a separate `Hash`. This commit also simplifies the resolution of default values, replacing the `merge_defaults!` method with `resolve_defaults`.
Detail
Extend the
.attribute
class method to accept a:default
option for its list of attributes:Checklist
Before submitting the PR make sure the following are checked:
[Fix #issue-number]