A ruby course

  • Thread starter Brian Schröder
  • Start date
B

Brian Candler

What I was getting at here, is that #rot13 could be reasonably applied
to any text; and that is the primary use of strings in ruby: a text
container. Whereas, #remove_html_attributes would only be used on
special types of text: html documents/snippets. In this case, I would
subclass; in the rot13 case, I would extend. But that's just me, you
might feel differently. :)

There are a couple of caveats to extending or subclassing built-in classes
though:

(1) There is no way to 'coerce' an object of class X into an instance of
class Y, where Y is a subclass of X. So subclassing built-in types relies on
the existence of a constructor which takes an instance of an existing
object. e.g.

class HTMLString < String
...
end

foo = HTMLString.new("<html>hello</html>")

In this case, HTMLString#initialize(str) can call String#initialize(str)
- implicitly in this case, or explicitly using 'super'. Or it could use the
'replace' method:

foo = HTMLString.new
foo.class # => HTMLString
foo.replace("abc")
foo.class # => HTMLString

But this makes me a bit uncomfortable because no class is *required* to have
an initializer which takes an existing instance of the same class, nor a
'replace' method. And when you're talking about a built-in class, the value
is not accessible via an instance variable. So, in theory at least, this
approach might not work at all.

Consider subclassing Range, for example; you have to be careful to pass the
right bits to the superclass constructor, if you want to allow an existing
Range or MyRange object to be passed in.

class MyRange < Range
def initialize(r)
super(r.begin, r.end, r.exclude_end?)
end
end

(2) If you're running multiple applications within a shared interpreter,
such as mod_ruby, then clearly you don't want these applications to step on
each others' toes, so leaving the core classes alone is usually a good
principle.

I personally prefer two alternative strategies:

(a) using the singleton class of objects

module HTMLString
def flatten
gsub(/<[^>]*>/,' ')
end
end

a = "<html>hello world</html>"
a.extend HTMLString
a.flatten # => " hello world "

Now string 'a' has this method, but we've not polluted String. This is the
nearest to coercion that I can find in Ruby; don't change the actual class,
but mix in something else.

(b) using delegation ("has_a") rather than inheritance ("is_a"). It's often
a hands-down win in terms of flexibility and clarity anyway. For a
HTMLString object, I would write something like

class HTMLString
def initialize(str)
@str = str
end
def flatten
@str.gsub(/<[^>]*>/,' ')
end
end

Working with an instance variable gives more control over which methods you
wish to delegate, which you wish to hide (e.g. if they make no sense for
this new class), and which to make behave differently; and you can easily
compose objects out of two or more other objects this way.

Regards,

Brian.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,772
Messages
2,569,593
Members
45,112
Latest member
VinayKumar Nevatia
Top