Subclassing string

J

John

I'm making a basic Template class, which is just a string that has
methods like replace {placeholder} with value. I would like this class
to have the ability to do things like

t = Template.new('lalala')
t.gsub!('a','o')

Right now I can do that by doing

def gsub!(match, replacewith)
@s = @s.gsub!(match, replacewith)
end

but this seems clunky. If I make Template a subclass of String, I
could just use gsub directly.

My question is, how to do this? Where does a String instance keep it's
data? Right now my Template class keeps its string in an instance
variable called @s. But doing

mystring = "attempt"
mystring.instance_variables

results in [].

I hope my question is clear. When I write my own classes, I can keep
data in instance variables. But if I subclass a built-in class like
String, I don't know where the data is.
 
P

Phil Tomson

It's clunky if you really do want to just pass on most method calls
unchanged to the included String. In that case inheritance is better.
Although composition of the sort you refer to above is often cleaner,
and you can use method_missing to forward methods by default without
having to write duplicates like that.


Well, if you make Template a subclass of String, you don't have to do
anything. Once you've done

class Template < String; end

then you can call .gsub! on any Template instance automatically.

However, then you can't use "", '', etc. to construct strings like so:

str = "this is a string/template"

Maybe that's not a big deal for your application, though.
But if you want to manipulate the string data within a method, just use "self":

class Template < String
def applySubstitutions(valuesHash)
valuesHash.each do
|key, value|
self.gsub!(/@{#{key}}/, value)
end
end
end


Alternatively, you could extend String by adding the methods you need to
it. I know it's not considered as 'safe' or 'correct' in some circles,
but that's probably the way I'd be inclined to go.

class String
def your_added_method
#...
end
end

Or alternatively, you could put your added methods into a module and then
mix them into String.

Phil
 
R

Robert Klemme

Phil Tomson said:
However, then you can't use "", '', etc. to construct strings like so:

str = "this is a string/template"

Maybe that's not a big deal for your application, though.

You don't even need to use self in this case since self is implicit. In
fact, self does hurt if you want to invoke private methods of the
superclass: you can't.
Alternatively, you could extend String by adding the methods you need to
it. I know it's not considered as 'safe' or 'correct' in some circles,
but that's probably the way I'd be inclined to go.

class String
def your_added_method
#...
end
end

Or alternatively, you could put your added methods into a module and then
mix them into String.

Or use delegation:

require 'delegate'

class Template < DelegateClass(String)
def initialize(*args)
super(String.new(*args))
end

# your methods here:

def upcaseA
gsub!( /a/i, 'A' )
end

end

Now you can do:

irb(main):034:0> x=Template.new("roar!")
=> "roar!"
irb(main):035:0> x.upcaseA
=> "roAr!"
irb(main):036:0> x.gsub!(/r/, 'RRR')
=> "RRRoARRR!"
irb(main):037:0>

http://www.rubycentral.com/book/lib_patterns.html

For the sake of completeness(TM) there's another option: add your methods
to each instance of String like this:

def createTemplate(s="")
str = s.dup

class <<str
def upcaseA
gsub!( /a/i, 'A' )
end
end

str
end

irb(main):013:0* x = createTemplate("roar!")
=> "roar!"
irb(main):014:0> x.upcaseA
=> "roAr!"
irb(main):015:0> x.gsub!(/r/, 'RRR')
=> "RRRoARRR!"
irb(main):016:0>

BUT: this is not a good solution if you're going to create a lot of these
instances, because it's inefficient - memory and performance wise. For
each instance you get a new definition of your set of methods which costs
time in createTemplate and memory.

Kind regards

robert
 

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,744
Messages
2,569,483
Members
44,903
Latest member
orderPeak8CBDGummies

Latest Threads

Top