Skip to content

Commit e28972a

Browse files
authored
Merge pull request rails#44544 from jonathanhefner/active_model-access
Add `ActiveModel::Access`
2 parents f807513 + de5a4b3 commit e28972a

File tree

6 files changed

+115
-45
lines changed

6 files changed

+115
-45
lines changed

activemodel/lib/active_model.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
module ActiveModel
3131
extend ActiveSupport::Autoload
3232

33+
autoload :Access
3334
autoload :API
3435
autoload :Attribute
3536
autoload :Attributes
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# frozen_string_literal: true
2+
3+
require "active_support/core_ext/enumerable"
4+
require "active_support/core_ext/hash/indifferent_access"
5+
6+
module ActiveModel
7+
module Access # :nodoc:
8+
def slice(*methods)
9+
methods.flatten.index_with { |method| public_send(method) }.with_indifferent_access
10+
end
11+
12+
def values_at(*methods)
13+
methods.flatten.map! { |method| public_send(method) }
14+
end
15+
end
16+
end

activemodel/lib/active_model/model.rb

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,5 +42,27 @@ module ActiveModel
4242
module Model
4343
extend ActiveSupport::Concern
4444
include ActiveModel::API
45+
include ActiveModel::Access
46+
47+
##
48+
# :method: slice
49+
#
50+
# :call-seq: slice(*methods)
51+
#
52+
# Returns a hash of the given methods with their names as keys and returned
53+
# values as values.
54+
#
55+
#--
56+
# Implemented by ActiveModel::Access#slice.
57+
58+
##
59+
# :method: values_at
60+
#
61+
# :call-seq: values_at(*methods)
62+
#
63+
# Returns an array of the values returned by the given methods.
64+
#
65+
#--
66+
# Implemented by ActiveModel::Access#values_at.
4567
end
4668
end

activemodel/test/cases/access_test.rb

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
# frozen_string_literal: true
2+
3+
require "cases/helper"
4+
require "active_support/core_ext/hash/indifferent_access"
5+
6+
class AccessTest < ActiveModel::TestCase
7+
class Point
8+
include ActiveModel::Access
9+
10+
def initialize(*vector)
11+
@vector = vector
12+
end
13+
14+
def x
15+
@vector[0]
16+
end
17+
18+
def y
19+
@vector[1]
20+
end
21+
22+
def z
23+
@vector[2]
24+
end
25+
end
26+
27+
setup do
28+
@point = Point.new(123, 456, 789)
29+
end
30+
31+
test "slice" do
32+
expected = { z: @point.z, x: @point.x }.with_indifferent_access
33+
actual = @point.slice(:z, :x)
34+
35+
assert_equal expected.keys, actual.keys
36+
37+
expected.each do |key, value|
38+
assert_equal value, actual[key.to_s]
39+
assert_equal value, actual[key.to_sym]
40+
end
41+
end
42+
43+
test "slice with array" do
44+
expected = { z: @point.z, x: @point.x }.with_indifferent_access
45+
assert_equal expected, @point.slice([:z, :x])
46+
end
47+
48+
test "values_at" do
49+
assert_equal [@point.x, @point.z], @point.values_at(:x, :z)
50+
assert_equal [@point.z, @point.x], @point.values_at(:z, :x)
51+
end
52+
53+
test "values_at with array" do
54+
assert_equal [@point.x, @point.z], @point.values_at([:x, :z])
55+
assert_equal [@point.z, @point.x], @point.values_at([:z, :x])
56+
end
57+
end

activerecord/lib/active_record/core.rb

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
# frozen_string_literal: true
22

33
require "active_support/core_ext/enumerable"
4-
require "active_support/core_ext/hash/indifferent_access"
54
require "active_support/core_ext/string/filters"
65
require "active_support/parameter_filter"
76
require "concurrent/map"
87

98
module ActiveRecord
109
module Core
1110
extend ActiveSupport::Concern
11+
include ActiveModel::Access
1212

1313
included do
1414
##
@@ -722,15 +722,26 @@ def pretty_print(pp)
722722
end
723723
end
724724

725-
# Returns a hash of the given methods with their names as keys and returned values as values.
726-
def slice(*methods)
727-
methods.flatten.index_with { |method| public_send(method) }.with_indifferent_access
728-
end
725+
##
726+
# :method: slice
727+
#
728+
# :call-seq: slice(*methods)
729+
#
730+
# Returns a hash of the given methods with their names as keys and returned
731+
# values as values.
732+
#
733+
#--
734+
# Implemented by ActiveModel::Access#slice.
729735

736+
##
737+
# :method: values_at
738+
#
739+
# :call-seq: values_at(*methods)
740+
#
730741
# Returns an array of the values returned by the given methods.
731-
def values_at(*methods)
732-
methods.flatten.map! { |method| public_send(method) }
733-
end
742+
#
743+
#--
744+
# Implemented by ActiveModel::Access#values_at.
734745

735746
private
736747
# +Array#flatten+ will call +#to_ary+ (recursively) on each of the elements of

activerecord/test/cases/base_test.rb

Lines changed: 0 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1479,43 +1479,6 @@ def test_typecasting_aliases
14791479
assert_equal 10, Topic.select("10 as tenderlove").first.tenderlove
14801480
end
14811481

1482-
def test_slice
1483-
company = Company.new(rating: 1, name: "37signals", firm_name: "37signals")
1484-
hash = company.slice(:name, :rating, "arbitrary_method")
1485-
assert_equal hash[:name], company.name
1486-
assert_equal hash["name"], company.name
1487-
assert_equal hash[:rating], company.rating
1488-
assert_equal hash["arbitrary_method"], company.arbitrary_method
1489-
assert_equal hash[:arbitrary_method], company.arbitrary_method
1490-
assert_nil hash[:firm_name]
1491-
assert_nil hash["firm_name"]
1492-
end
1493-
1494-
def test_slice_accepts_array_argument
1495-
attrs = {
1496-
title: "slice",
1497-
author_name: "@Cohen-Carlisle",
1498-
content: "accept arrays so I don't have to splat"
1499-
}.with_indifferent_access
1500-
topic = Topic.new(attrs)
1501-
assert_equal attrs, topic.slice(attrs.keys)
1502-
end
1503-
1504-
def test_values_at
1505-
company = Company.new(name: "37signals", rating: 1)
1506-
1507-
assert_equal [ "37signals", 1, "I am Jack's profound disappointment" ],
1508-
company.values_at(:name, :rating, :arbitrary_method)
1509-
assert_equal [ "I am Jack's profound disappointment", 1, "37signals" ],
1510-
company.values_at(:arbitrary_method, :rating, :name)
1511-
end
1512-
1513-
def test_values_at_accepts_array_argument
1514-
topic = Topic.new(title: "Budget", author_name: "Jason")
1515-
1516-
assert_equal %w( Budget Jason ), topic.values_at(%w( title author_name ))
1517-
end
1518-
15191482
def test_default_values_are_deeply_dupped
15201483
company = Company.new
15211484
company.description << "foo"

0 commit comments

Comments
 (0)