Encapsulation and good practices

Hi.

I'm working on a small project of mine (a system to collect and easily
graph data via a "smart" wrapper around rrdtool), and I'm thinking about
the design (while the whole stuff is already in production, how
typical).

Overall, it goes like this : the system has a few types of plugins ; to
be classified as a plugin, an object must inherit from a pre-defined
class and implement a few methods. Some of these methods receive helper
objects and have to call methods on these objects to achieve something.

The trouble is I have a few "dangerous" methods defined in the various
objects, and a few which aren't useful for the user. With this design,
I don't see how I could protect those methods - and logically, I think
they belong to their objects.

So, my questions are : does this look like a sound design ? What are
the ways to have a better "protection" of the code ? Should I care ?
(It's a rhetoric question - I care, only if that gives me the occasion
to learn something... :slight_smile: )

For instance (not actual code, but a very simplified example) :

$tests = []

class Tester
        def Tester.inherited(c)
                $tests.push(c.new())
        end
        def initdatastruct(datastruct)
                raise "initdatastruct must be implemented"
        end
end

class DataStruct
        attr_reader :sources
        def initialize()
                @sources = []
        end
        def addsource(name = nil, min = nil, max = nil)
                @sources.push(Source.new(name, min, max))
        end
        def doit()
                cl = "program -c " + @sources.collect do |s|
                  s.to_cmd
                end.join(' ')
                system(cl)
                # puts cl
        end
end

class Source
        attr_reader :name, :min, :max
        def initialize(name = nil, min = nil, max = nil)
                @name, @min, @max = name, min, max
        end
        def to_cmd()
                [ @name, @min, @max ].join(':')
        end
end

class PluginTester < Tester
        def initdatastruct(ds)
                ds.addsource("blah", 0, 100)
                ds.addsource("blih", -100, 100)
        end
end

$tests.each do |t|
        ds = DataStruct.new()
        t.initdatastruct(ds)
        ds.doit
end

(The dangerous method would be the DataStruct#doit part ; the unuseful
one would be Source#to_cmd.)