开发者

Looking to write a Tag class

I'm looking to write a Tag class (a tag is a string with no spaces). My first thought is to inher开发者_如何学Pythonit from String:

class Tag < String
  def initialize(str)
    raise ArgumentError if str =~ /\s/
    super
  end
end

Does this look correct? Are there any other methods I should redefine?


Are other letters ok?

you might want to ensure the string matches your criteria instead of not matching it.

Examples:

1. /^\w+$/      ensures at least one word character (ThisIsAValidTag_123)
2. /^[a-z]+$/   ensures at least one lowercase a to z only
3. /^[a-z]+$/i  ensures at least one a to z upper *or* lowercase.

Usage in class:

class Tag < String
  def initialize(str)
    raise ArgumentError unless str =~ /^[a-z]+$/
    super
  end
end

All that said, this sounds a lot like Ruby symbols.


You shouldn't inherit from String, both for reasons of good object-oriented design and pure pragmatism.

If you inherit from String, you are violating the Liskov Substitution Principle, which states that instances of subclasses should be substitutable for instances of their superclass. This is not the case here: I can insert a space in the middle of a String, but I can not insert a space in the middle of a Tag, therefore a Tag is not a substitue for a String, and thus shouldn't be a subclass.

And as a purely practical matter: you are inheriting roughly 100 public instance methods from String. Do you really want to audit (and potentially override) every single one of them to ensure they don't violate Tag's contract?

I would rather do something like this:

require 'facets/multiton'

class Tag
  include Multiton

  attr_reader :name
  attr_accessor :description

  private

  def initialize name, description=nil
    raise ArgumentError, 'Tag name cannot contain whitespace' if str =~ /\s/

    self.name = name.to_s.dup.freeze
    self.description = description unless description.nil?
  end

  attr_writer :name

  def self.multiton_id name, description=nil
    return name.to_s.downcase
  end
end


It will be quite a challenge to make it air tight. Currently:

puts Tag.new("with_space").tr!("_"," ") # ==> prints "with space"

You would basically need to specialize all mutating methods (like #tr!), calling super and adding a check at the end, and all methods returning a modified copy of self too (like #tr).

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜