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

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:csshsh@structbench.com]
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

---
Incoming mail is certified Virus Free.
Checked by AVG anti-virus system (http://www.grisoft.com).
Version: 6.0.705 / Virus Database: 461 - Release Date: 6/12/2004

---
Outgoing mail is certified Virus Free.
Checked by AVG anti-virus system (http://www.grisoft.com).
Version: 6.0.705 / Virus Database: 461 - Release Date: 6/12/2004

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

···

On Thu, 17 Jun 2004, Florian Weber wrote:

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

----
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

===============================================================================

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

···

il Thu, 17 Jun 2004 00:10:40 +0900, Florian Weber <csshsh@structbench.com> ha scritto::

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?

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

···

On 6/16/04 11:10 AM, "Florian Weber" <csshsh@structbench.com> wrote:

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

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

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:csshsh@structbench.com]
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

---
Incoming mail is certified Virus Free.
Checked by AVG anti-virus system (http://www.grisoft.com).
Version: 6.0.705 / Virus Database: 461 - Release Date: 6/12/2004

---
Outgoing mail is certified Virus Free.
Checked by AVG anti-virus system (http://www.grisoft.com).
Version: 6.0.705 / Virus Database: 461 - Release Date: 6/12/2004

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

···

On 6/16/04 4:41 PM, "Florian Weber" <csshsh@structbench.com> wrote:

ciao!
florian