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
).
精彩评论