1

Ruby でインスタンスの属性のメソッドをどのように定義しますか?

HtmlSnippetRails の ActiveRecord::Base を拡張し、属性を持つというクラスがあるとしますcontentreplace_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

String クラスのインスタンスと同様contentに、String クラスの再定義も 1 つのオプションです。しかし、それは String のすべてのインスタンスの動作を上書きするため、私はそれを実行したくありません。

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

何か提案はありますか?

4

1 に答える 1

0

コードが機能しない理由は単純です。nil実行のコンテキストにある @content を使用しています (これselfはインスタンスではなくクラスです)。したがって、基本的に nil の固有クラスを変更しています。

そのため、設定時に @content のインスタンスを拡張する必要があります。いくつかの方法がありますが、次の 1 つがあります。

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。値を別の方法で処理する必要があります。しかし、それは非常に簡単です。

もう 1 つのことは、なぜdupセッターで使用するのかということです。コードにnodupが含まれている場合、次のコードの動作が間違っている可能性があります (明らかに要件によって異なります)。

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

x.contentdupだけでなく、割り当てた元の文字列も拡張しません。

于 2012-09-12T10:31:53.790 に答える