0

原代码:

  def self.user_admin_links
    ADMIN_PAGES.inject([]) do |result, page|
      result << Page.new(controller: page[:name]) if page[:menu] && (page[:group_admin] || page[:company_admin])
      result
    end
  end

  def self.super_admin_links
    ADMIN_PAGES.inject([]) do |result, page|
      result << Page.new(controller: page[:name]) if page[:super_admin]
      result
    end
  end

我试图像这样重构:

array_builder = Proc.new do |conditional|
    ADMIN_PAGES.inject([]) do |result, page|
      result << Page.new(controller: page[:name]) if conditional
      result
    end
  end

  def self.user_admin_links
    array_builder.call(page[:menu] && (page[:group_admin] || page[:company_admin]))
  end

  def self.super_admin_links
    array_builder.call(page[:super_admin])
  end

但我得到这个错误:

Error: undefined local variable or method `array_builder' for Page:Class.

当我把 array_builder 变成一个类方法时,像这样:

  def self.array_builder 
    Proc.new do |conditional|
      ADMIN_PAGES.inject([]) do |result, hsh|
        result << Page.new(controller: hsh[:name]) if conditional
        result
      end
    end
  end

我在 self.user_admin_links 方法中收到一个错误,即“页面”无法识别。

4

1 回答 1

1

在 Ruby 中,方法不是闭包。即,它们不能使用周围范围内的局部变量,例如array_builder.

而且,如果您想page对 的每个元素进行评估ADMIN_PAGES,则应该使用块参数(这基本上只是将 procs 作为参数传递的一些语法)。否则,它只在links方法中评估一次,其中page未定义。

def array_builder &conditional
  ADMIN_PAGES.inject([]) do |result, page|
    result << Page.new(controller: page[:name]) if conditional[page]
    result
  end
end

此外,这里有一个更好的 Ruby 习惯用法。而不是手动推送到数组并使用注入,使用Enumerable#selectEnumerable#map

def array_builder &conditional
  ADMIN_PAGES.select(&conditional).map {|page| Page.new(controller: page[:name])}
end

然后其他方法传递一个块:

def self.user_admin_links
  array_builder {|page| page[:menu] && (page[:group_admin] || page[:company_admin])}
end

def self.super_admin_links
  array_builder {|page| page[:super_admin]}
end
于 2012-07-19T16:22:18.750 回答