Ruby / Rails:如何临时定义调用方法的范围

时间:2011-05-11 10:02:48

标签: ruby module include

我有一个模块:

module LiquidFilters
  include ActionView::Helpers::AssetTagHelper

  def stylesheet_tag(stylesheet_file_path)
    stylesheet_link_tag stylesheet_file_path
  end
end

我的规格:

describe LiquidFilters do
  describe "#stylesheet_tag" do
    it "should return the css file in an html (media=screen) tag" do
      helper.stylesheet_tag("/path/css").should match(/<link href="\/path\/css\.css" media="screen" rel="stylesheet" type="text\/css"\s*\/>/)
    end
  end
end

但是我得到错误的参数数量(2对1)错误:

Failures:
  1) LiquidFilters#stylesheet_tag should return the css file in an html (media=screen) tag
     Failure/Error: helper.stylesheet_tag("/path/css").should match(/<link href="\/path\/css\.css" media="screen" rel="stylesheet" type="text\/css"\s*\/>/)
     wrong number of arguments (2 for 1)
     # ./app/filters/liquid_filters.rb:16:in `stylesheet_tag'
     # ./spec/helpers/liquid_filters_spec.rb:13

我可以看到问题发生在stylesheet_link_tag stylesheet_file_path模块的LiquidFilters - stylesheet_link_tag应该调用AssetTagHelper private method "stylesheet_tag",但最终会调用{{1} }} LiquidFilter方法。

问题

如何强制stylesheet_tag调用stylesheet_link_tag方法,而不是AssetTagHelper

注意:我想保留方法名称LiquidFilter

2 个答案:

答案 0 :(得分:1)

您可以在AssetTagHelper类中包含Helper模块,以避免方法名称覆盖,如下所示:

require 'singleton'

module LiquidFilters
  class Helper
    include Singleton  
    include ActionView::Helpers::AssetTagHelper
  end

  def stylesheet_tag(stylesheet_file_path)
    Helper.instance.stylesheet_link_tag stylesheet_file_path
  end
end

这样,您的stylesheet_tag方法就不会与AssetTagHelper的私有方法混淆。

修改

根据您的反馈,我猜这是您最接近的反馈:

module LiquidFilters
  include ActionView::Helpers::AssetTagHelper

  alias :old_stylesheet_tag :stylesheet_tag

  def stylesheet_tag(stylesheet_file_path, options = nil)
    if options
      old_stylesheet_tag(stylesheet_file_path, options)
    else
      stylesheet_link_tag stylesheet_file_path
    end 
  end 
end

你基本上覆盖私有方法,所以我认为除代理呼叫之外还有其他选择。

答案 1 :(得分:0)

Rails的alias_method_chain可以提供帮助:

module LiquidFilters
  include ActionView::Helpers::AssetTagHelper

  def stylesheet_tag_with_liquid(stylesheet_file_path, options = nil)
    # if this got called with two arguments, proxy them to original
    if options
      stylesheet_tag_without_liquid(stylesheet_file_path, options)
    else
      stylesheet_link_tag stylesheet_file_path
    end
  end

  def self.included(receiver)
    alias_method_chain :stylesheet_tag, :liquid
  end
end

当您仍然屏蔽原始方法时,您现在可以代理它。

编辑:alias_method_chain移至self.included回调,因此在模块实际包含在某处之前不会调用它。