【问题标题】:Adding a method to an attribute in Ruby在 Ruby 中为属性添加方法
【发布时间】:2012-09-12 08:03:08
【问题描述】:

如何在 Ruby 中为实例的属性定义方法?

假设我们有一个名为 HtmlSnippet 的类,它扩展了 Rails 的 ActiveRecord::Base 并有一个属性 content。而且,我想为它定义一个方法replace_url_to_anchor_tag! 并通过以下方式调用它;

html_snippet = HtmlSnippet.find(1)
html_snippet.content = "Link to http://stackoverflow.com"
html_snippet.content.replace_url_to_anchor_tag!
# => "Link to <a href='http://stackoverflow.com'>http://stackoverflow.com</a>"



# app/models/html_snippet.rb
class HtmlSnippet < ActiveRecord::Base    
  # I expected this bit to do what I want but not
  class << @content
    def replace_url_to_anchor_tag!
      matching = self.match(/(https?:\/\/[\S]+)/)
      "<a href='#{matching[0]}'/>#{matching[0]}</a>"
    end
  end
end

由于content 是String 类的一个实例,重新定义String 类是一种选择。但我不想这样做,因为它会覆盖所有 String 实例的行为;

class HtmlSnippet < ActiveRecord::Base    
  class String
    def replace_url_to_anchor_tag!
      ...
    end
  end
end

有什么建议吗?

【问题讨论】:

  • 哎呀,我总是通过评论说谢谢,而不是通过 Stackoverflow 中的任何操作。这次我会做的
  • @oldergod 你能给我一个样品吗?

标签: ruby-on-rails ruby methods metaprogramming


【解决方案1】:

您的代码无法正常工作的原因很简单——您在执行上下文中使用@content,即nilself 是类,而不是实例)。所以你基本上是在修改 nil 的特征类。

所以你需要在设置时扩展@content 的实例。有几种方法,有一个:

class HtmlSnippet < ActiveRecord::Base

  # getter is overrided to extend behaviour of freshly loaded values
  def content
    value = read_attribute(:content)
    decorate_it(value) unless value.respond_to?(:replace_url_to_anchor_tag)
    value
  end

  def content=(value)
    dup_value = value.dup
    decorate_it(dup_value)
    write_attribute(:content, dup_value)
  end

  private
  def decorate_it(value)
    class << value
      def replace_url_to_anchor_tag
        # ...
      end
    end
  end
end

为了简单起见,我省略了“nil 场景”——您应该以不同的方式处理 nil 值。但这很简单。

另一件事是你可能会问为什么我在 setter 中使用dup。如果代码中没有dup,则以下代码的行为可能是错误的(显然这取决于您的要求):

x = "something"
s = HtmlSnippet.find(1)
s.content = x

s.content.replace_url_to_anchor_tag # that's ok
x.content.replace_url_to_anchor_tag # that's not ok

没有dup,您不仅扩展了 x.content,还扩展了您分配的原始字符串。

【讨论】:

  • 哇,这太棒了!我了解了如何访问类中的实例属性。
猜你喜欢
  • 1970-01-01
  • 2012-03-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多