how to design plugin functionality

F

Florian Weber

hi!

i have a design question. for example i have a class which reads a file
and prints out each line with line numbers. what if now i wanna be able
to plugin some functionality which sorts the file, depending on some
conditions (extension, etc) before its passed on to the line numbering
functionality. the class should be as less tied as possible to the
sorting
functionality as possible..

how would you normally design that in ruby?

would you just overwrite the method which calls the file read method
and passes it to the numbering method?

would you pack an object in between, which would check if the file
has to be sorted, because the conditions are true, read the file and
the return the sorted or unsorted content?

basically im wondering if its considered a good practice to overwrite
methods on the same class or if its kinda hackish.. =)

thanks a lot!

ciao!
florian
 
Z

Zach Dennis

I would maybe add a filter class (TextFilter maybe?) and then add them as an
aggregate objects to your File reading class, I'd maybe have 2 types of
filters.

- Inprocess filter (while you're reading in the files by lines)
- Postprocess filter (after you've read the file in)

So maybe a outline like:

class TextFilter
def read( text )
return text
end
end

class SortTextFilter < TextFilter
def read( text )
text = self.sort( text )
end

def sort( text )
#Sort text, maybe ascending by default
return text
end
end

fr = FileReader.new( SortTextFilter.new() );
fr.read( "myfile.txt" )
puts fr

Whatcha think?

Zach








-----Original Message-----
From: Florian Weber [mailto:[email protected]]
Sent: Wednesday, June 16, 2004 11:11 AM
To: ruby-talk ML
Subject: how to design plugin functionality


hi!

i have a design question. for example i have a class which reads a file
and prints out each line with line numbers. what if now i wanna be able
to plugin some functionality which sorts the file, depending on some
conditions (extension, etc) before its passed on to the line numbering
functionality. the class should be as less tied as possible to the
sorting
functionality as possible..

how would you normally design that in ruby?

would you just overwrite the method which calls the file read method
and passes it to the numbering method?

would you pack an object in between, which would check if the file
has to be sorted, because the conditions are true, read the file and
the return the sorted or unsorted content?

basically im wondering if its considered a good practice to overwrite
methods on the same class or if its kinda hackish.. =)

thanks a lot!

ciao!
florian
 
A

Ara.T.Howard

hi!

i have a design question. for example i have a class which reads a file
and prints out each line with line numbers. what if now i wanna be able
to plugin some functionality which sorts the file, depending on some
conditions (extension, etc) before its passed on to the line numbering
functionality. the class should be as less tied as possible to the
sorting
functionality as possible..

how would you normally design that in ruby?

would you just overwrite the method which calls the file read method
and passes it to the numbering method?

would you pack an object in between, which would check if the file
has to be sorted, because the conditions are true, read the file and
the return the sorted or unsorted content?

basically im wondering if its considered a good practice to overwrite
methods on the same class or if its kinda hackish.. =)

thanks a lot!

ciao!
florian

first i'd separate the notion of a file's lines into it's own class - one that
simply loads a file and provides a method to access those lines, but does no
printing. then i'd design outputter classes that operate on line sets.
somewhere in between you can filter/munge the lines - possible using a class
hierarchy of Mungers, possibly using duck-typed objects which respond_to?
'munge', possibly just using callbacks (Procs). this uses the last approach:

~ > cat a.rb
class LineSet < Array
attr :path
def initialize path
super()
@path = path
replace(IO.readlines(path))
end
def munge(*procs)
c = self.cp
unless procs.empty?
procs.each{|pc| c = pc.call(c)}
else
c = yield c
end
c
end
def munge!(*procs, &block)
replace(munge(*procs, &block))
end
def cp
Marshal.load(Marshal.dump(self))
end
end
class Outputter
def initialize lines
@lines = lines
end
def output out
raise NotImplementedError
end
end
class NumberedOutputter < Outputter
def output out = STDOUT
@lines.each_with_index do |line, idx|
out << "#{ idx }: #{ line }"
end
end
end


lines = LineSet.new __FILE__

reverser = lambda{|ls| ls.reverse}
shrinker = lambda{|ls| ls[0,2]}

puts '----'
munged = lines.munge reverser, shrinker
no = NumberedOutputter.new munged
no.output

puts '----'
lines.munge! shrinker, reverser
no = NumberedOutputter.new lines
no.output

~ > ruby a.rb
----
0: no.output
1: no = NumberedOutputter.new lines
----
0: attr :path
1: class LineSet < Array



-a
--
===============================================================================
| EMAIL :: Ara [dot] T [dot] Howard [at] noaa [dot] gov
| PHONE :: 303.497.6469
| A flower falls, even though we love it; and a weed grows, even though we do
| not love it. --Dogen
===============================================================================
 
G

gabriele renzi

il Thu, 17 Jun 2004 00:10:40 +0900, Florian Weber
hi!

i have a design question. for example i have a class which reads a file
and prints out each line with line numbers. what if now i wanna be able
to plugin some functionality which sorts the file, depending on some
conditions (extension, etc) before its passed on to the line numbering
functionality. the class should be as less tied as possible to the
sorting
functionality as possible..

how would you normally design that in ruby?

I'd say that you could use some kind of pattern and so on.
You may find this thread useful:
http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/48648

As of now I'd probably use some trick similar to this:
http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/97440

to allow the user to write something like add_filter:)read) do.. end
 
R

Richard Kilmer

You could use modules:

module SortedOutput
def read
@lines = File.readlines(@file).sort
end
end

Then you can do:

class MyFileOutputter
def initialize(file)
@file = file
end

def read
@lines = File.readlines(@file)
end

def output(io=$stdout)
read unless @lines
@lines.each_with_index do |line, i|
io.puts "#{i+1}. #{line}"
end
end
end


outputter = MyFileOutputter.new("myfile.txt")
outputter.extend SortedOutput
outputter.output

I find mixing in Modules that replace methods on object instances pretty
handy.

-rich
 
F

Florian Weber

im really sorry. i think it was really misleading to give such a
concret example. basically the example i gave is purely fictional.

basically i was more wondering if overwriting methods (methods of
the same class, not methods of a superclass) is a recommended
good practice for functionality which can be plugged in or
if such things should be done in a traditional way, where a object
is 'plugged' in between, which decides if the additional functionality
should be executed or not.

sorry for the misunderstanding =)

ciao!
florian
 
Z

Zach Dennis

I think overriding the methods of the existing class is poor choice. The
only reason that I would suggest this is if there was some drastic
performance issue when moving the functionality outside of the class, but I
don't see that happening. It is better program design to leave the original
class alone. It makes your code more readable, reusable and maintainable. It
also allows your class to be more reusable for other projects and other
people.

I suggest a book reading...

"Design Patterns
Elements of Reusable Object-Oriented Software" by Erich Gamma, Richard
Helm, Ralph Johnson and John Vlissides.

It's a deep reading, but it's a good one.

HTH,

Zac





-----Original Message-----
From: Florian Weber [mailto:[email protected]]
Sent: Wednesday, June 16, 2004 4:42 PM
To: ruby-talk ML
Subject: Re: how to design plugin functionality


im really sorry. i think it was really misleading to give such a
concret example. basically the example i gave is purely fictional.

basically i was more wondering if overwriting methods (methods of
the same class, not methods of a superclass) is a recommended
good practice for functionality which can be plugged in or
if such things should be done in a traditional way, where a object
is 'plugged' in between, which decides if the additional functionality
should be executed or not.

sorry for the misunderstanding =)

ciao!
florian
 
R

Richard Kilmer

im really sorry. i think it was really misleading to give such a
concret example. basically the example i gave is purely fictional.

basically i was more wondering if overwriting methods (methods of
the same class, not methods of a superclass) is a recommended
good practice for functionality which can be plugged in or
if such things should be done in a traditional way, where a object
is 'plugged' in between, which decides if the additional functionality
should be executed or not.

Well, methods can be replaced on classes at runtime as then can on instances
of classes. Although changing class methods changes the behavior of all
instances (and _could_ be very bad), changing methods on objects can be very
powerful. I don't see any reason not to do it if the design requires that
kind of changeable behavior. But again, all these choices need to be
balanced against the requirements of what you are trying to do.
sorry for the misunderstanding =)

No problem!

-rich
 

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,768
Messages
2,569,574
Members
45,048
Latest member
verona

Latest Threads

Top