如何组合.select来执行两个过程?

时间:2014-07-30 16:25:39

标签: ruby-on-rails ruby

以下是代码:

params[:controller_id].select(&check_if_controller_exists)
params[:controller_id].select(&check_controller_permissions)

这很有效。我有一个数组,我正在将Proc转换成块。

我不知道该怎么做才能将它们结合起来 - 有些人可能会说这更适合代码审查,但在我看来,我有一个关于如何编写代码的问题。

是否可以在不修改单个过程的情况下组合上述内容?或者我应该只是组合成一个Super Proc而不是两个不同的块?

要求提供更多信息:

def check_if_controller_exists # in case they pass an array of controllers
  Proc.new { |c| raise CanCan::AccessDenied.new("One or more of the specified controllers does not exist for this site") unless Controller.find_by_id(c) }
end

def check_controller_permissions # in case they pass an array of controllers
  Proc.new { |c| raise CanCan::AccessDenied unless can? :read, Controller.find_by_id(c) } 
end

与大多数编程一样,这个结构是从移动其中一个被复制的异常,然后移动另一个,然后看到我有两个基本相同,并希望将它们合并为一个调用而演变而来的,但由于它们已经被渲染为Procs,我偶然发现了如何合并Procs。

这在技术上是这篇文章的目标 - 学习如何合并几个Procs。

显然,对于这两件事,我不需要多次点击数据库。

3 个答案:

答案 0 :(得分:1)

或者您可以避免Symbol#to_proc转换并使用

params[:controller_id].select do |p| 
  p.check_if_contoller_exists && p.check_controller_permissions
end

提供相同的功能。 Symbol#to_proc已被证明更快,但我不确定它是否适用于多次迭代,也许我会对它进行基准测试。

好的,即使在背靠背通话Symbol#to_proc更快。

require 'benchmark'
a = (1..500).to_a
num_times = 1000
proc1 = proc {|a| a.to_s.is_a?(String)}
proc2 = proc {|a| a.to_s.to_i == a}

Benchmark.bm do |x|
  x.report('Symbol#to_proc') { num_times.times{ a.select(&proc1).select(&proc2) } }
  x.report('block') { num_times.times{ a.select{ |e| proc1.call(e) && proc2.call(e) } } }
end

#=>                      user     system      total        real
        Symbol#to_proc   0.343000   0.000000   0.343000 (  0.343475)
        block            0.453000   0.000000   0.453000 (  0.445722)

答案 1 :(得分:0)

如果通过"结合"你的意思是得到&&结果的结果,你可以:

result = params[:controller_id].select(&check_if_controller_exists)
                               .select(&check_controller_permissions)

它将在枚举中旋转两次,根据您的情况,这可能是也可能不是问题。

答案 2 :(得分:0)

如果我们只是代码审核你,我的第一个建议是两个写一个方法同时检查两个条件。这样你只需要迭代你的params Hash一次。

result = params[:controller_id].select(&:check_controller_presence_and_permissions)

private
def check_controller_presence_and_permissions
  check_if_controller_exists && check_controller_permissions
end

尽管如此,如果不了解check_if_controller_existscheck_controller_permissions的实施情况,我很难提供好的建议。如果您可以编辑您的问题并包含更多代码,我们可以帮助您重构此问题。