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 |
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] |
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 |
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 |
"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 |
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 |
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 |
> 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 |
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 |
> 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 |
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 |
Free forum by Nabble | Edit this page |