This is a companion to Why Leo Works 
<https://groups.google.com/d/msg/leo-editor/t4PC8ffJr28/GaV2jQ7HL98J>. It 
shows how I spend much of my design time.

Today I "invented" a new encapsulation pattern.  It allows a command to be 
implemented by a *persistent *singleton class::

    def checkForChangedFiles(self):
        '''
        For each @<file> node that has been changed outside Leo,
        prompt the user whether to update the file.
        '''

        class CheckForChangedFiles:
            '''A class implementing c.checkForChangedFiles.'''
            @others

        c = self
        if not hasattr(c,'checkForChangedFilesInstance'):
            c.checkForChangedFilesInstance = CheckForChangedFiles(c)
        c.checkForChangedFilesInstance.check()

The last three lines allocate a singleton instance of the 
CheckForChangedFiles (ccf) class and then call ccf.check().  All 
invocations of c.checkForChangedFiles use this shared singleton class.

Previously, c.checkForChangedFiles used several *commander *methods as 
helpers.  Leo makes it easy to see the relation between a method and it's 
helpers, but using the ccf class is *much *better:

- ccf methods do not pollute c's namespace.  As a result, ccf methods can 
be named freely.

The *only *effect on the commander's namespace is the injection of the 
c.checkForChangedFilesInstance ivar into c. At present, this ivar is not 
defined in c.initCommandIvars.  It would be reasonable to define it there, 
but the risk of stepping on another ivar with the same name is negligible.

- The ccf ctor defines shared persistent data, again without polluting the 
namespace of the commander class. Furthermore, the ctor inits the data, not 
in various init methods of c.  This makes it *much *easier to add private 
data. This is reason enough to use a class.

Edward

P.S.  Contrast this with a more typical way of using classes as helpers for 
a command.

Several commands use the c.GoToLineNumber class. For example:

    def goToScriptLineNumber (self,p,script,n):
        c = self
        scriptData = {'p':p.copy(),'lines':g.splitLines(script)}
        c.GoToLineNumber(c).go(n=n,scriptData=scriptData)

The big difference between this code and the pattern shown above is that 
each invocation of the command creates a "throwaway" temporary instance of 
the GoToLineNumber class.  No data is retained between invocation of the 
command.

EKR

-- 
You received this message because you are subscribed to the Google Groups 
"leo-editor" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To post to this group, send email to [email protected].
Visit this group at http://groups.google.com/group/leo-editor.
For more options, visit https://groups.google.com/d/optout.

Reply via email to