如何 DRY ruby 中仅一行代码不同的函数列表?
How to DRY a list of functions in ruby that are differ only by a single line of code?
我在 ROR 应用程序中有一个用户模型,它有多个像这样的方法
#getClient() returns an object that knows how to find certain info for a date
#processHeaders() is a function that processes output and updates some values in the database
#refreshToken() is function that is called when an error occurs when requesting data from the object returned by getClient()
def transactions_on_date(date)
if blocked?
# do something
else
begin
output = getClient().transactions(date)
processHeaders(output)
return output
rescue UnauthorizedError => ex
refresh_token()
output = getClient().transactions(date)
process_fitbit_rate_headers(output)
return output
end
end
end
def events_on_date(date)
if blocked?
# do something
else
begin
output = getClient().events(date)
processHeaders(output)
return output
rescue UnauthorizedError => ex
refresh_token()
output = getClient().events(date)
processHeaders(output)
return output
end
end
end
我的用户 class 中有几个功能看起来完全一样。这些函数之间的唯一区别是 output = getClient().something(date)
行。有什么方法可以让这段代码看起来更简洁,这样我就没有重复的函数列表了。
是的,您可以使用 Object#send
:getClient().send(:method_name, date)
。
顺便说一句,getClient
不是正确的 Ruby 方法名称。应该是 get_client
.
答案通常是传入一个块并以函数式的方式进行:
def handle_blocking(date)
if blocked?
# do something
else
begin
output = yield(date)
processHeaders(output)
output
rescue UnauthorizedError => ex
refresh_token
output = yield(date)
process_fitbit_rate_headers(output)
output
end
end
end
那你这样称呼它:
handle_blocking(date) do |date|
getClient.something(date)
end
这允许进行大量自定义。 yield
调用执行您提供的代码块并将 date
参数传递给它。
干燥代码的过程通常涉及寻找模式并将它们归结为像这样的有用方法。使用函数式方法可以保持整洁。
两个答案的组合如何:
class User
def method_missing sym, *args
m_name = sym.to_s
if m_name.end_with? '_on_date'
prop = m_name.split('_').first.to_sym
handle_blocking(args.first) { getClient().send(prop, args.first) }
else
super(sym, *args)
end
end
def respond_to? sym, private=false
m_name.end_with?('_on_date') || super(sym, private)
end
def handle_blocking date
# see other answer
end
end
然后你可以调用 "transaction_on_date", "events_on_date", "foo_on_date" 就可以了。
我在 ROR 应用程序中有一个用户模型,它有多个像这样的方法
#getClient() returns an object that knows how to find certain info for a date
#processHeaders() is a function that processes output and updates some values in the database
#refreshToken() is function that is called when an error occurs when requesting data from the object returned by getClient()
def transactions_on_date(date)
if blocked?
# do something
else
begin
output = getClient().transactions(date)
processHeaders(output)
return output
rescue UnauthorizedError => ex
refresh_token()
output = getClient().transactions(date)
process_fitbit_rate_headers(output)
return output
end
end
end
def events_on_date(date)
if blocked?
# do something
else
begin
output = getClient().events(date)
processHeaders(output)
return output
rescue UnauthorizedError => ex
refresh_token()
output = getClient().events(date)
processHeaders(output)
return output
end
end
end
我的用户 class 中有几个功能看起来完全一样。这些函数之间的唯一区别是 output = getClient().something(date)
行。有什么方法可以让这段代码看起来更简洁,这样我就没有重复的函数列表了。
是的,您可以使用 Object#send
:getClient().send(:method_name, date)
。
顺便说一句,getClient
不是正确的 Ruby 方法名称。应该是 get_client
.
答案通常是传入一个块并以函数式的方式进行:
def handle_blocking(date)
if blocked?
# do something
else
begin
output = yield(date)
processHeaders(output)
output
rescue UnauthorizedError => ex
refresh_token
output = yield(date)
process_fitbit_rate_headers(output)
output
end
end
end
那你这样称呼它:
handle_blocking(date) do |date|
getClient.something(date)
end
这允许进行大量自定义。 yield
调用执行您提供的代码块并将 date
参数传递给它。
干燥代码的过程通常涉及寻找模式并将它们归结为像这样的有用方法。使用函数式方法可以保持整洁。
两个答案的组合如何:
class User
def method_missing sym, *args
m_name = sym.to_s
if m_name.end_with? '_on_date'
prop = m_name.split('_').first.to_sym
handle_blocking(args.first) { getClient().send(prop, args.first) }
else
super(sym, *args)
end
end
def respond_to? sym, private=false
m_name.end_with?('_on_date') || super(sym, private)
end
def handle_blocking date
# see other answer
end
end
然后你可以调用 "transaction_on_date", "events_on_date", "foo_on_date" 就可以了。