Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Deprecate the delegation of Array bang methods in ActiveRecord::Deleg…
…ation The primary means of returning results for Array bang methods is to modify the array in-place. When you call these methods on a relation, that array is created, modified, and then thrown away. Only the secondary return value is exposed to the caller. Removing this delegation is a straight-forward way to reduce user error by forcing callers to first explicitly call #to_a in order to expose the array to be acted on by the bang method.
- Loading branch information
Showing
3 changed files
with
117 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,97 @@ | ||
require 'cases/helper' | ||
require 'models/post' | ||
require 'models/comment' | ||
|
||
module ActiveRecord | ||
class DelegationTest < ActiveRecord::TestCase | ||
fixtures :posts | ||
|
||
def assert_responds(target, method) | ||
assert target.respond_to?(method) | ||
assert_nothing_raised do | ||
case target.to_a.method(method).arity | ||
when 0 | ||
target.send(method) | ||
when -1 | ||
if method == :shuffle! | ||
target.send(method) | ||
else | ||
target.send(method, 1) | ||
end | ||
else | ||
raise NotImplementedError | ||
end | ||
end | ||
end | ||
end | ||
|
||
class DelegationAssociationTest < DelegationTest | ||
def target | ||
Post.first.comments | ||
end | ||
|
||
[:map, :collect].each do |method| | ||
test "##{method} is delgated" do | ||
assert_responds(target, method) | ||
assert_equal(target.pluck(:body), target.send(method) {|post| post.body }) | ||
end | ||
|
||
test "##{method}! is not delgated" do | ||
assert_deprecated do | ||
assert_responds(target, "#{method}!") | ||
end | ||
end | ||
end | ||
|
||
[:compact!, :flatten!, :reject!, :reverse!, :rotate!, | ||
:shuffle!, :slice!, :sort!, :sort_by!].each do |method| | ||
test "##{method} delegation is deprecated" do | ||
assert_deprecated do | ||
assert_responds(target, method) | ||
end | ||
end | ||
end | ||
|
||
[:select!, :uniq!].each do |method| | ||
test "##{method} is implemented" do | ||
assert_responds(target, method) | ||
end | ||
end | ||
end | ||
|
||
class DelegationRelationTest < DelegationTest | ||
def target | ||
Comment.where.not(body: nil) | ||
end | ||
|
||
[:map, :collect].each do |method| | ||
test "##{method} is delgated" do | ||
assert_responds(target, method) | ||
assert_equal(target.pluck(:body), target.send(method) {|post| post.body }) | ||
end | ||
|
||
test "##{method}! is not delgated" do | ||
assert_deprecated do | ||
assert_responds(target, "#{method}!") | ||
end | ||
end | ||
end | ||
|
||
[:compact!, :flatten!, :reject!, :reverse!, :rotate!, | ||
:shuffle!, :slice!, :sort!, :sort_by!].each do |method| | ||
test "##{method} delegation is deprecated" do | ||
assert_deprecated do | ||
assert_responds(target, method) | ||
end | ||
end | ||
end | ||
|
||
[:select!, :uniq!].each do |method| | ||
test "##{method} is triggers an immutable error" do | ||
assert_raises ActiveRecord::ImmutableRelation do | ||
assert_responds(target, method) | ||
end | ||
end | ||
end | ||
end | ||
end |
1a40be0
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.
delete_if() is also an in-place modification method - judging just by bang name is not reliable enough!