这是密集的代码,毫无疑问。因此,正如您所说before
,并且after
是作为参数传递给方法的哈希(-like?)对象。调用before.diff(after)
返回另一个哈希,然后立即.keys
调用它。这将返回返回的哈希中的所有键diff
。键作为数组返回,然后立即排序。
然后我们得到最复杂/最密集的位。使用inject
该排序的键数组,该方法构建一个数组(diffs
在inject
块内调用),该数组将作为该inject
方法的返回值。
该数组由差异记录组成。before.diff(after)
每条记录都是一个散列 - 通过从返回值的排序键数组中获取一个键来构建。这些散列存储了被区分的属性,它在前散列中的样子以及在后散列中的样子。
因此,简而言之,该方法获取两个散列之间的一堆差异,并将它们收集到一个散列数组中。该哈希数组是该方法的最终返回值。
注意:inject
可以而且经常比这简单得多。通常它用于简单地将一组值简化为一个结果,方法是一遍又一遍地应用一个操作并将结果存储在累加器中。您可能知道inject
其他reduce
语言;reduce
是inject
Ruby 中的别名。这是一个更简单的示例inject
:
[1,2,3,4].inject(0) do |sum, number|
sum + number
end
# => 10
0 是累加器 - 初始值。在 pair|sum, number|
中,sum
将是累加器,并且number
将是数组中的每个数字,一个接一个。什么inject
是加 1 到 0,将结果存储到sum
下一轮,将 2 加到sum
,sum
再次存储结果等等。累加器的单个最终值sum
将是返回值。这里 10. 在您的示例中增加的复杂性是累加器与块内的值在类型上不同。这不太常见,但还不错或不习惯。(编辑:Andrew Marshall 提出了一个很好的观点,也许这很糟糕。请参阅他对原始问题的评论。@tokland 指出,inject
这里只是地图的一个非常复杂的替代方案。它不好。)有关更多示例,请参阅我在对您的问题的评论中链接到的文章inject
。
编辑:正如@tokland 在一些评论中指出的那样,代码似乎只需要一个简单的map
. 那时它会更容易阅读。
def differences(before, after)
before.diff(after).keys.sort.map do |k|
{ :attribute => k, :before => before[k], :after => after[k] }
end
end
我太专注于解释代码在做什么。我什至没有想到如何简化它。