Skip to content

Commit 2f68387

Browse files
committed
extract the delegate naming logic out of delegate definition
1 parent a0ba3a2 commit 2f68387

File tree

2 files changed

+43
-10
lines changed

2 files changed

+43
-10
lines changed

lib/active_record/virtual_attributes/virtual_delegates.rb

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,8 @@ def virtual_delegate(*methods, to:, type: nil, prefix: nil, allow_nil: nil, defa
2424
end
2525

2626
to = to.to_s
27-
if to.include?(".") && methods.size > 1
28-
raise ArgumentError, 'Delegation only supports specifying a method name when defining a single virtual method'
27+
if to.include?(".") && (methods.size > 1 || prefix)
28+
raise ArgumentError, 'Delegation only supports specifying a target method name when defining a single virtual method with no prefix'
2929
end
3030

3131
if to.count(".") > 1
@@ -35,12 +35,7 @@ def virtual_delegate(*methods, to:, type: nil, prefix: nil, allow_nil: nil, defa
3535
# put method entry per method name.
3636
# This better supports reloading of the class and changing the definitions
3737
methods.each do |method|
38-
method_prefix = virtual_delegate_name_prefix(prefix, to)
39-
method_name = "#{method_prefix}#{method}"
40-
if to.include?(".") # to => "target.method"
41-
to, method = to.split(".").map(&:to_sym)
42-
end
43-
38+
method_name, to, method = determine_method_names(method, to, prefix)
4439
define_delegate(method_name, method, :to => to, :allow_nil => allow_nil, :default => default)
4540

4641
self.virtual_delegates_to_define =
@@ -122,8 +117,25 @@ def #{method_name}(#{definition})
122117
end
123118
# rubocop:enable Style/TernaryParentheses
124119

125-
def virtual_delegate_name_prefix(prefix, to) # rubocop:disable Naming/MethodParameterName
126-
"#{prefix == true ? to : prefix}_" if prefix
120+
# Sometimes the `to` contains the column name target.column, split it up to the source method_name and target column
121+
# If `to` does specify the column name, `to` becomes the target (i.e.: association)
122+
#
123+
# @param column [Symbol|String] the name of the column
124+
# @param to [Symbol|String]
125+
# @param prefix [Boolean|Nil|Symbol]
126+
# @return [Symbol, Symbol, Symbol] method_name, relation, relation's column name
127+
def determine_method_names(column, to, prefix) # rubocop:disable Naming/MethodParameterName
128+
method_name = column = column.to_sym
129+
130+
tos = to.to_s
131+
if tos.include?(".") # to => "target.method"
132+
to, column = tos.split(".").map(&:to_sym)
133+
end
134+
135+
method_prefix = "#{prefix == true ? to : prefix}_" if prefix
136+
method_name = "#{method_prefix}#{method_name}".to_sym
137+
138+
[method_name, to.to_sym, column]
127139
end
128140

129141
# @param col [String] attribute name

spec/virtual_delegates_spec.rb

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -299,4 +299,25 @@ def self.connection
299299
expect(actual).to eq(author)
300300
end
301301
end
302+
303+
describe "#determine_method_names (private)" do
304+
it "works with column and to" do
305+
expect(determine_method_names("column", "relation", nil)).to eq([:column, :relation, :column])
306+
expect(determine_method_names("column", "relation", true)).to eq([:relation_column, :relation, :column])
307+
expect(determine_method_names("column", "relation", "pre")).to eq([:pre_column, :relation, :column])
308+
expect(determine_method_names("column", "relation.column2", false)).to eq([:column, :relation, :column2])
309+
expect(determine_method_names("column", "relation.column2", true)).to eq([:relation_column, :relation, :column2])
310+
311+
TestClass.virtual_delegate :str, :to => :ref1, :prefix => true, :type => :string
312+
expect(TestClass.new.respond_to?(:ref1_str)).to eq(true)
313+
314+
expect do
315+
TestClass.virtual_delegate :my_method, :to => "ref1.str", :prefix => true, :type => :string
316+
end.to raise_exception(ArgumentError)
317+
end
318+
end
319+
320+
def determine_method_names(*args)
321+
TestClass.send(:determine_method_names, *args)
322+
end
302323
end

0 commit comments

Comments
 (0)