programmatically install metod

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
11 messages Options
Reply | Threaded
Open this post in threaded view
|

programmatically install metod

Jochen Riekhof-3
Hi...

As I now overwrite PackageSelector>>openPackageFile: in one of my packages,
I would like to set it back to the original method on package uninstall.
My problem is i.e. how to programmatically add a method to a class? I found
an addSelector:withMethod: in Behaviour, but it requires a Compiled Method.

Or is there maybe a more elegant solution?

Ciao

...Jochen


Reply | Threaded
Open this post in threaded view
|

Re: programmatically install metod

Bill Schwab-2
Jochen,

> As I now overwrite PackageSelector>>openPackageFile: in one of my
packages,
> I would like to set it back to the original method on package uninstall.
> My problem is i.e. how to programmatically add a method to a class? I
found
> an addSelector:withMethod: in Behaviour, but it requires a Compiled
Method.
>
> Or is there maybe a more elegant solution?

Elegant?  Hardly, but have a look at my CodeGenerator goodie.  Hopefull it
will answer your questions.

Have a good one,

Bill

--
Wilhelm K. Schwab, Ph.D.
[hidden email]


Reply | Threaded
Open this post in threaded view
|

Re: programmatically install metod

Ian Bartholomew-18
In reply to this post by Jochen Riekhof-3
Jochen,

> Or is there maybe a more elegant solution?

Over the years I've tried 3 ways of doing this, none of which I would
describe as particularly elegant.

1) Copy the original method source (i.e. as part of your manual package
creation process) into the packages postuninstall script and then wrap
it in code that recompiles it into the image.

The postuninstall script would then look something like ...

AClass compile: 'the complete original method source '

You may need to play around with resetting category/package affiliations
after this.


2) Dynamically rename the method and leave it in the image.

The package preinstall script would be ...

AClass compile: 'replaced_' , (AClass compiledMethodAt: #aSelector)
getSource

You now have a #aSelector and #replaced_aSelector methods in the class
but your packaged method will overwrite the original.

Your postuninstall script would then be ...

AClass compile: ((AClass compiledMethodAt: #replaced_aSelector)
getSource copyFrom: 10).
aClass removeSelector: #replaced_aSelector

You may need to play around with resetting category/package affiliations
after this one as well.


3) (The way I now prefer).  Create two .st files, one for the original
and one for the new method source - don't add the method to the package!

The postinstall script is then just ...

SourceManager default fileIn: (FileLocator imageRelative
localFileSpecFor:  (File splitPathFrom: self packagePathname) ,
'modified method.st')

and the postuninstall script...

SourceManager default fileIn: (FileLocator imageRelative
localFileSpecFor: (File splitPathFrom: self packagePathname) , 'original
method.st')

The extra bits just mean that you can put the st files in the same
location as the package file and (hopefully) they will be found.

You can add extra code to the files that resets category and package.

--
Ian


Reply | Threaded
Open this post in threaded view
|

Re: programmatically install metod

Jochen Riekhof
Ian...

thank you for the great tips! Likely I will try a combination of 2 and 3
(filing out the original method pre-install and filing in post-install). I
will try it out ASAP!

Ciao

...Jochen


Reply | Threaded
Open this post in threaded view
|

Re: programmatically install metod

Peter van Rooijen
"Jochen Riekhof" <[hidden email]> wrote in message
news:3fcb8b22$[hidden email]...
> Ian...
>
> thank you for the great tips! Likely I will try a combination of 2 and 3
> (filing out the original method pre-install and filing in post-install). I
> will try it out ASAP!

Jochen,

This might help you put the code in the desired category and package:

| newCompiledMethod |

newCompiledMethod := [
 (self classWithName: classNameString) class
  compile: sourceString
  classified: categoryNameString
]
 on: CompilerWarningNotification
 do: [:exceptionOccurrence | exceptionOccurrence resume]
.
(self packageWithName: packageNameString)
 addMethod: newCompiledMethod

where

packageWithName: aString

^
PackageManager current packageNamed: aString

Ciao,

Peter


Reply | Threaded
Open this post in threaded view
|

Re: programmatically install metod

Jochen Riekhof
In reply to this post by Ian Bartholomew-18
Ian...

thanks for version 3, it made me experiment with filein/out! My current
version is a number 4 and goes as follows:
1. in "preinstall" I save the original version of the method (here
PackageSelector>>openPackageFile):

|filepath filer|
filepath := FileLocator imageRelative localFileSpecFor: (File splitPathFrom:
self packagePathname).
"file out original"
filer := ChunkSourceFiler on: (FileStream write: (File composePath: filepath
subPath: 'PackageSelector_openPackageFile_original.st')).
[filer fileOutMessages: #(#openPackageFile:) ofBehavior: PackageSelector;
flush.] ensure:[filer close].
!

This has the good side effect of saving also the categories.

2. The loose method is still a loose method, as it calculates prerequisites
for me and gives the nice overvrite warning.

3. on "postuninstall", I restore the original as you showed me:

|filepath|
filepath := FileLocator imageRelative localFileSpecFor:  (File
splitPathFrom: self packagePathname).
SourceManager default fileIn: (File composePath: filepath subPath:
'PackageSelector_openPackageFile_original.st').
!

If desired, step 2 can of course be replaced (or extended) with a file-in of
a modified version in "postinstall".

Ciao

...Jochen


Reply | Threaded
Open this post in threaded view
|

Re: programmatically install metod

Ian Bartholomew-18
Jochen,

> thanks for version 3, it made me experiment with filein/out! My
> current version is a number 4 and goes as follows:

I preferred manually saving the original method as a separate file to
avoid the, unlikely I admit, situation where the existing method had
already been modified by someone else. Even after saving/reloading the
original in a file you can still have problems after uninstalling but
the chances of crashing the image are less.

<aside> I wonder if there should be a CompiledMethod>>fileOutOn: method
in the default image, to match Class>>fileOutOn: and Package>>fileOutOn:

Just to clarify one comment I made earlier, about _not_ including the
modified method in the package.  There are occasions where this won't
work so you have to be a bit selective about when you do it (the reason
why I decided to use two separate file as standard).  When you uninstall
the package any loose methods contained in the package will be deleted
from the image between the pre and postuninstall scripts.  If the
evaluation of your postuninstall script relies on the method, even
indirectly, its absence will cause a DNU walkback.

--
Ian


Reply | Threaded
Open this post in threaded view
|

Re: programmatically install metod

Jochen Riekhof
> I preferred manually saving the original method as a separate file to
> avoid the, unlikely I admit, situation where the existing method had
> already been modified by someone else. Even after saving/reloading the
> original in a file you can still have problems after uninstalling but
> the chances of crashing the image are less.

Yes and I am afraid I install my oldish package and on uninstall it restores
a stale version :-). Package management is not perfect anyway, best would be
some method history management in the base system.
.
> Just to clarify one comment I made earlier, about _not_ including the
> modified method in the package.  There are occasions where this won't
> work so you have to be a bit selective about when you do it (the reason
> why I decided to use two separate file as standard).  When you uninstall
> the package any loose methods contained in the package will be deleted
> from the image between the pre and postuninstall scripts.  If the
> evaluation of your postuninstall script relies on the method, even
> indirectly, its absence will cause a DNU walkback.

Thanks for the hinet! Fortunately, it is not an issue in my case.

Ciao

...Jochen


Reply | Threaded
Open this post in threaded view
|

Re: programmatically install metod

Ian Bartholomew-18
In reply to this post by Ian Bartholomew-18
I wrote ...

> <aside> I wonder if there should be a CompiledMethod>>fileOutOn:
> method in the default image, to match Class>>fileOutOn: and
> Package>>fileOutOn:

Seemed like a good idea so I wrote something similar (but different
:-) )

http://www.idb.me.uk/files/methodfiler.zip

Contains a new IDE extension package (so you will need to have installed
the IDE extension base classes that come with my goodies) which adds a
"File Out" option to the "Method" menu of the class hierarchy, system
and method browsers.  It files out the currently selected method and
category (in chunk format) and the dialog also suggests a name for the
file.

It can also be use programmatically

SourceManager default
    fileOutMethod: (aClass compiledMethodAt: #aSelector)

uses the default filename and

SourceManager default
    fileOutMethod: (aClass compiledMethodAt: #aSelector)
    to: 'aPathName'

allows you to select a new path/file name

--
Ian


Reply | Threaded
Open this post in threaded view
|

Re: programmatically install metod

Jochen Riekhof
> SourceManager default
>     fileOutMethod: (aClass compiledMethodAt: #aSelector)
>
> uses the default filename and
>
> SourceManager default
>     fileOutMethod: (aClass compiledMethodAt: #aSelector)
>     to: 'aPathName'
>
> allows you to select a new path/file name

Well, these were exactly the methods I was looking for when attempting to
file out a method :-)

Ciao

...Jochen


Reply | Threaded
Open this post in threaded view
|

Re: programmatically install metod

Ian Bartholomew-18
In reply to this post by Ian Bartholomew-18
I wrote:

> Seemed like a good idea so I wrote something similar

... which contained the required stupid error.  The following method
needs to be changed or else getter and setter methods will be given
the same default filename. Duh!!!

CompiledMethod>>fileOutName
    "Answers a string that can be used as a filename for the receiver"
    #idbAdded.
    ^(String writeStream)
        nextPutAll: self methodClass printString;
        space;
        "**** changed line follows"
        nextPutAll: (self selector copyReplacing: $: withObject: $_)
trimBlanks;
        nextPutAll: '.st';
        contents
--
Ian