无法理解以下代码的作用

时间:2012-06-20 23:14:28

标签: ruby ruby-on-rails-3 paper-trail-gem

有人可以向我解释下面的代码是做什么的。 beforeafter是哈希值。

def differences(before, after)
    before.diff(after).keys.sort.inject([]) do |diffs, k|
        diff = { :attribute => k, :before => before[k], :after => after[k] }
        diffs << diff; diffs
    end
end

它来自papertrail不同的宝石。

2 个答案:

答案 0 :(得分:3)

这是密集的代码,毫无疑问。所以,正如你所说beforeafter是散列(类似?)对象,它们作为参数传递给方法。调用before.diff(after)会返回另一个哈希值,然后立即调用.keys。这将返回diff返回的哈希中的所有键。键作为数组返回,然后立即排序。

然后我们到达最复杂/密集的位。在排序的键数组上使用inject,该方法构建一个数组(在diffs块中称为inject),它将是inject方法的返回值。

该数组由差异记录组成。每条记录都是一个哈希 - 通过从before.diff(after)返回值中排序的键数组中取一个键来构建。这些哈希值存储了被分散的属性,它在之前的哈希中的样子以及它在后哈希中的样子。

因此,简而言之,该方法在两个哈希之间获得了一系列差异,并在哈希数组中收集它们。该哈希数组是方法的最终返回值。

注意inject可能并且通常比这更简单。通常,它通过一次又一次地应用一个操作并将结果存储在累加器中来简单地将一组值减少到一个结果。您可能会将inject知道为reduce来自其他语言; reduce是Ruby中inject的别名。这是一个更简单的inject

示例
[1,2,3,4].inject(0) do |sum, number|
  sum + number
end
# => 10

0是累加器 - 初始值。在|sum, number|对中,sum将成为累加器,number将成为数组中的每个数字,一个接一个。 inject执行的操作是将1添加为0,将结果存储在sum中以用于下一轮,将2添加到sum,将结果再次存储在sum中,依此类推。累加器sum的单个最终值将是返回值。这里10.您的示例中增加的复杂性是累加器的类型与块内的值不同。这不太常见,但不是坏或不明显。 (编辑:安德鲁·马歇尔指出可能很糟糕的好点。看看他对原始问题的评论。而且@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

我过于专注于解释代码的作用。我甚至没想到如何简化它。

答案 1 :(得分:1)

它根据底层对象找到之前和之后的条目,然后以更方便的格式建立这些差异的列表。

before.diff(after)查找不同的条目。

keys.sort以排序顺序为您提供(差异地图的)键

inject([])map类似,但以diffs初始化为空数组开始。

该块为每个差异创建diff行(哈希),然后将其附加到diffs