Releases: pharo-ide/ClassAnnotation
Sources converted to tonel format
Registry updating is improved
Commenting classAnnotation pragma now removes annotation from class
Redefined annotations
Now there is special mechanizm to redefine all collected annotations. When cache is updated all redefined annotations are restored.
Read details in readme section "Redefined annotations"
Also in this versions the message to reset cache was renamed from #resetAll to #resetCache
ClassAnnotationRegistry and CompositeAnnotationContext
-
ClassAnnotationRegistry is extracted
Now annotation cache is reified as default registry instance. It is not managed in class variable of ClassAnnotation. -
The annotation registry do not depends on PragmaCollector
PragmaCollector update logic was not enough for updating inherited class annotations in the cache. -
classAnnotationDependency pragma is added.
It force update of annotation cache (registry) when dependency methods are modified (dependancy methods are sent inside annotation definition methods). -
fix class change handling logic #22
Registry is updated when change happens with class which have or will have inherited annotations from superclasses -
CompositeAnnotationContext is added
Now contexts can be concatenated by comma message. They all should be satisfied to activate annotation.
It is stable major version 0.2
Contextual annotations
Now annotations can be defined with context where they can be used.
Imaging that you want annotate command classes with shortcuts for specific widgets:
MyCommand class>>widget1ShortcutAnnotation
<classAnnotation>
ShortcutAnnotation using: $r meta for: MyWidgetClass1
MyCommand class>> widget2ShortcutAnnotation
<classAnnotation>
ShortcutAnnotation using: $t meta for: MyWidgetClass2
Then you can query all shortcuts which should be active for concrete widget:
ShortcutAnnotation activeAnnotationsInContext: aMyWidgetInstance
Declaring context using classes is simplest case. Underhood class is converted to AnnotationContext instance using #asAnnotationContext message. Then during annotations lookup it simply asks #isKindOf: for given context instances.
For advanced scenarios you can implement more complex annotation context and define specific DSL to use them for annotations and queries.
Any annotation class can redefine meaning of active annotation with extra conditions. For example it can delegate decision to annotated class itself:
ShortcutAnnotation >>isActiveInContext: aMyWidgetInstance
^(super isActiveInContext: aMyWidgetInstance)
and: [annotatedClass canBeUsedInWidget: aMyWidgetInstance]
But for some scenarios you may need to query annotations according to original "active" definition despite of extra conditions. For such cases the "visibility" of annotation is introduced: the annotation is visible if it is declared for given context:
ClassAnnotation>>isVisibleInContext: aContext
^activeContext describes: aContext
So the visible annotation is not necessary active. But active annotation is always visible in given context:
ClassAnnotation>>isActiveInContext: aContext
^self isVisibleInContext: aContext
Imaging that you want annotate commands with context menu information (where they should be accessible). In that case disabled menu items can represent commands which are visible for application but not active in given context (because selected items is not appropriate for them).
To query visible annotations where are few methods:
ContextMenuAnnotation visibleInstancesInContext: anUserContext
ContextMenuAnnotation visibleInstancesInContext: anUserContext do: aBlock
Annotation priority
For particular scenarios it can be important to define order in which annotations are processed.
For context menu example this order can be used to sort menu items.
For shortcut example it allows override existing shortcuts of application.
So concept of annotation priority was introduced for this reason. Any annotation can define it. Annotation with greater priority value is processed first by enumeration methods:
- registeredInstancesDo:
- activeInstancesInContext:do:
- visibleInstancesInContext:do:
Priority is holden as instance variable. So you can specify it in declaration method:
MyCommand class>>shortcutAnnotation
<classAnnotation>
(ShortcutAnnotation using: $r meta for: MyWidgetClass)
priority: 1000
Of course for your annotation you can add methods which are suitable for your domain.
In some cases you would need override order in which annotations should be sorted. For example, you can say that command with greater priority should be at the end of menu.
For such cases you can override class side method #createContainerForRegistry:
MySpecificAnnotation class>>createContainerForRegistry
^SortedCollection sortBlock: #priority ascending
Forbidden annotation
Annotation can forbid annotating of particular classes. For example it can forbid abstract classes.
MySpecificAnnotation>>isForbidden
^annotatedClass isAbstract
Such annotations will not be added to the registry and forbidden classes will not include them
Better understanding of contextual annotations
Now it is clear that annotation context describes users of annotation.
And activeContext of annotation restricts its possible set of users.
So argument of query messages is renamed to the anAnnotationUser.
And other changes according to this idea.
So it is cosmetic changes. But it is important for understanding the model of contextual annotations
Annotations with context and priority
Contextual annotations
Now annotations can be defined with context where they can be used.
Imaging that you want annotate command classes with shortcuts for specific widgets:
MyCommand class>>widget1ShortcutAnnotation
<classAnnotation>
ShortcutAnnotation using: $r meta for: MyWidgetClass1
MyCommand class>> widget2ShortcutAnnotation
<classAnnotation>
ShortcutAnnotation using: $t meta for: MyWidgetClass2
Then you can query all shortcuts which should be active for concrete widget:
ShortcutAnnotation activeAnnotationsInContext: aMyWidgetInstance
Declaring context using classes is simplest case. Underhood class is converted to AnnotationContext instance using #asAnnotationContext message. Then during annotations lookup it simply asks #isKindOf: for given context instances.
For advanced scenarios you can implement more complex annotation context and define specific DSL to use them for annotations and queries.
Any annotation class can redefine meaning of active annotation with extra conditions. For example it can delegate decision to annotated class itself:
ShortcutAnnotation >>isActiveInContext: aMyWidgetInstance
^(super isActiveInContext: aMyWidgetInstance)
and: [annotatedClass canBeUsedInWidget: aMyWidgetInstance]
But for some scenarios you may need to query annotations according to original "active" definition despite of extra conditions. For such cases the "visibility" of annotation is introduced: the annotation is visible if it is declared for given context:
ClassAnnotation>>isVisibleInContext: aContext
^activeContext describes: aContext
So the visible annotation is not necessary active. But active annotation is always visible in given context:
ClassAnnotation>>isActiveInContext: aContext
^self isVisibleInContext: aContext
Imaging that you want annotate commands with context menu information (where they should be accessible). In that case disabled menu items can represent commands which are visible for application but not active in given context (because selected items is not appropriate for them).
To query visible annotations where are few methods:
ContextMenuAnnotation visibleInstancesInContext: anUserContext
ContextMenuAnnotation visibleInstancesInContext: anUserContext do: aBlock
Annotation priority
For particular scenarios it can be important to define order in which annotations are processed.
For context menu example this order can be used to sort menu items.
For shortcut example it allows override existing shortcuts of application.
So concept of annotation priority was introduced for this reason. Any annotation can define it. Annotation with greater priority value is processed first by enumeration methods:
- registeredInstancesDo:
- activeInstancesInContext:do:
- visibleInstancesInContext:do:
Priority is holden as instance variable. So you can specify it in declaration method:
MyCommand class>>shortcutAnnotation
<classAnnotation>
(ShortcutAnnotation using: $r meta for: MyWidgetClass)
priority: 1000
Of course for your annotation you can add methods which are suitable for your domain.
In some cases you would need override order in which annotations should be sorted. For example, you can say that command with greater priority should be at the end of menu.
For such cases you can override class side method #createContainerForRegistry:
MySpecificAnnotation class>>createContainerForRegistry
^SortedCollection sortBlock: #priority ascending
Forbidden annotation
Annotation can forbid annotating of particular classes. For example it can forbid abstract classes.
MySpecificAnnotation>>isForbidden
^annotatedClass isAbstract
Such annotations will not be added to the registry and forbidden classes will not include them
it is the stable version 0.1
Readme fix classAnnotation instead of metaAnnotation
First version is stabilised names and API
Readme fix classAnnotation instead of metaAnnotation