我的rails应用程序有一个名为Game
的{{1}}模型,用于存储和关联体育竞赛的相关信息,包括home_team_id
和home_team_score
等数据库项目以及类似的方法winning_team_id
和winning_team_score
将逻辑应用于存储的数据。
我在app/models/
中有另一个文件,它定义了一个独立的类Record
。通过将record
和games
数组作为参数传递来创建team_id
,以便为@wins
创建实例变量,例如@points_for
和team
} {}对应team_id
。
在Record
内我定义两个实例方法average_points_for
和average_points_against
,它们完全符合您的期望:
class Record
def games_played
return @wins + @losses
end
def average_points_for
return (@points_for.to_f / games_played).round(2)
end
def average_points_against
return (@points_against.to_f / games_played).round(2)
end
end
似乎非DRY将average_points_for
和average_points_against
声明为两种不同的方法。我意识到我能做到这一点......
class Record
def games_played
return @wins + @losses
end
def average_points(which)
return eval("(@points_#{which}.to_f / games_played).round(2)")
end
end
...但average_points("for")
看起来很丑陋 - 我更喜欢average_points_for
的惯例。
我更喜欢的是这样的:
class Record
def games_played
return @wins + @losses
end
def average_points_#{which}
return (@points_#{which}.to_f / games_played).round(2)
end
end
有办法做到这一点吗?
答案 0 :(得分:4)
在我看来,对于你的用例,重构它来干它会更清晰:
private def average(value)
(value.to_f / games_played).round(2)
end
def average_points_for
average(@points_for)
end
def average_points_against
average(@points_against)
end
但是,正如评论所示,您可以使用define_method
。 Rails确实带来了很大的好处,就像Ruby本身一样,OpenStruct
;但在这种情况下,这是一种矫枉过正。如果你真的想这样做,那就是这种方式(未经测试,可能包含错误):
%i(for against).each do |which|
define_method(:"average_points_#{which}") do
(instance_variable_get(:"@points_#{which}").to_f / games_played).round(2)
end
end