Skip to content

browser

4 posts with the tag “browser”

Manage rules using MooseCritics

Software projects often leave specific architectural or programming rules that are not checked by the off-the-shelf static analysis tools and linters.
But MooseCritics is now here to make such things easy!

The first step to use this tool is of course to open its browser, findable in the Moose menu under the name Moose Critic Browser. As with every other tool of MooseIDE, we also need to propagate a model to give our tool entities to analyze. For this analysis, we will use a model of ArgoUML, an open-source Java project used in this wiki.

"MooseCritics browser"

Rules in MooseCritics are divided into two components: Context, and Condition.
A context is a collection of entities to specify the scope of our analysis. Using this, we are only executing our rules on the relevant entities for them.
Once we have a context, we add conditions to it, to verify the validity of every entity belonging to this context.

Let’s start building a few of those, to appreciate how easy and versatile this system can be!

To begin, we will right-click on the root context, the root of our rules, doing nothing but passing the whole set of entities propagated into our browser. Then, clicking on “Add Context” will open a new window, in which we can write our first context.

"Context maker user interface"

As you can see, a context has three properties :

  • Name: the name of our context
  • Context Block: a code block, using as a parameter the collection given by the parent context, and that must return a collection of entities
  • Summary: a quick explanation of the selection performed

In this case, the selection is very basic (keeping only the classes defined within our model), but any way of manipulating a collection (so long as it remains a collection) can be used to make a very specific choice of entities.
But for now, let’s keep things simple, and add a few more contexts to our root.

First, we select methods…

"Title:"
'Methods'
"Context Block:"
[ :collection | collection allMethods ]
"Summary:"
'Every method in our model or called by a model entity.'

… and secondly attributes.

"Title:"
'Attributes'
"Context Block:"
[ :collection | collection allAttributes ]
"Summary:"
'Every attributes in our model or accessed by a model entity.'

Once this is all done, we are met with this screen :

"Three contexts"

Now that our contexts are set, we can write a few conditions for those.
To do so, right-clicking on our Model Classes context and choosing “Add condition” which will open a new interface to write our conditions.

"Condition in Pharo Code : Dead Classes"

The properties are almost identical to a context, but we now use a query to know whether or not an entity violates a rule.
This query will have as a parameter every entity of our context, one by one, and will add a violation to it if the query returns true.

Now, the most perceptive readers (all of my readers, no doubts 😄) will have noticed the two radio buttons; Pharo Code and Queries Browser.
We can indeed use a query built in the Queries Browser, and we will do so for the next one, to find God Classes.

"Condition with Queries Browser : God Classes"

This may not be an option for every kind of rule, especially the more complex ones, but conditions verifying several simple things can be easily designed, thanks to the Queries Browser.

Now that we saw all possibilities, time to write one more condition, this time for the methods :

"Title:"
'Deprecated'
"Query Block:"
[ :entity |
entity annotationInstances notEmpty and: [
entity annotationTypes
anySatisfy: [ :a | a name = 'Deprecated' ] ] ]
"Summary:"
'Deprecated methods, that should be removed or not used anymore.'

We are now all set, and all that remains to do is pressing the “Run” button in the bottom right corner, and look at the result of our analysis in the right pane, showing every violation found, on the format violatingEntity -> violatedCondition.

"Analysis results"

Now that we executed our rules, you can also have fun clicking on contexts and conditions to see that the left and right panels will change to match your selection, the left one showing the context, and the right one showing the violations of the selected condition, or the violations of every condition of the selected context.

We may also be a bit more specific, both on the condition side of things, but also when it comes to context.
For the conditions, our perceptive minds did not forget about the attributes, so we will write a condition for them too :

"Title:"
'Directly accessed'
"Query Block:"
[ :entity |
entity accessors anySatisfy: [ :m |
m isGetter not and: [ m isSetter not ] ] ]
"Summary:"
'Every attribute accessed without the use of a getter or setter method.'

For a final rule, let’s work a bit more on our context. Let’s say we want to build a rule around getter methods, to verify that their cyclomatic complexity is equal to 1.
For that, we can start by making a new context, using the “Methods” context as its parent :

"Title:"
'Getters'
"Context Block:"
[ :collection |
collection select: [ :m |
(m name beginsWith: 'get') and: [ m isGetter ] ] ]
"Summary:"
'Every getter method of our model, meaning :
- Their name starts with 'get'
- They have the property 'isGetter' set to true'

Once that sub-context has been created, we can give it a condition to verify ! Let’s do so right away, with our cyclomatic complexity example :

"Title:"
'Cyclomatic Complexity > 1'
"Query Block:"
[ :entity | entity cyclomaticComplexity > 1 ]
"Summary:"
'A getter must have a cyclomatic complexity of one.'

We are now done with all of our rules. To get the result of our new conditions, you can use again the “Run” button, or, execute only the new ones by right-clicking on them and selecting the “Run condition” option.

"Analysis results"

Our work is now done, but we would like to be able to monitor the state of our project in the long run, and to simplify this, we can export and import sets of rules built with MooseCritics.

For that, by pressing the “Export rules” button, we can choose where we wish to save our rules. The loading works similarly and will restore the tree as it was when it was saved (if rules were already present, the imported rules are added after those).

"Export window"

MooseCritics can also propagate those violations, in order to access them in the entities exporter, to be able to save those violations in a CSV file.
The exported selection will be the violations found in the right pane when using the propagate button.

"Entities exporter"

MooseCritics enables us to verify the validity of our defined rules and puts us in the right direction to correct our mistakes by finding violations. Dividing our model into contexts allows us to make specific analyses while working on a large scale.
Even if most of the examples shown here are fairly simple, MooseCritics can represent complex structural rules using Famix properties and will surely make your life easier when it comes to software analysis using Moose. 😄

Introducing the new Queries Browser

Let’s say that you want to know which classes of your Moose model are stub. That means: which classes are not defined in your Moose model but are used by some of your defined classes. Those classes are part of your model, although they are not part of your code. Checking those stub classes is easy. You only have to create a Boolean query (assuming that your model contains only classes) with the property isStub. Like:

FQBooleanQuery property: #isStub

However, creating queries programmatically can be a tedious task. Of course, not all the queries are as frivolous as the one in the example. For queries with lots of children, the code is not easy to understand at first sight.

The new Queries Browser was developed to create queries in a more visual way. This is a Moose tool that allows one to create and manipulate queries without the need of knowing the FamixQueries syntax or how to instantiate them. It has a friendly and intuitive user interface.

"The brand new Queries Browser"

If you want to know:

  1. What are all the classes that are not stub.
  2. What are the entities with incoming references and inheritances.
  3. What are the entities that have more than 50 lines of code.
  4. Finally, what is the intersection of those three queries.

This is an easy task for the Queries Browser. First, we need to create a type query that filters all the entities except the classes. To do that, we select Type Query in the queries browser and then select type “Classes”.

"Type Query"

Then, we create a child query from the Type Query. This child is going to be a Boolean Query that has the property isStub.

"The brand new Queries Browser"

Now, we create a Complement Query, a.k.a Negation Query, and choose the Boolean Query to be the query to be negated.

"The brand new Queries Browser"

Now we have the first task completed: All the classes that are not stub.

For the second task, we need to create another query, a Navigation Query, select the Incoming direction, and only select the associations Reference and Inheritance.

The third one is also simple. We only need to create a Numeric Query, select the property number of lines of code, the operator >, and put the value 50.

Now, our Queries Browser looks like this:

"The brand new Queries Browser"

For the final task, we need to create an And Query, a.k.a Intersection Query, click on the ”+” button to add a new query to intersect, and select the three previous queries that we created.

"The brand new Queries Browser"

If we wanted to the the above queries programmatically, the code would have look like this:

(FQComplementQuery queryToNegate:
(FQTypeQuery types: { FamixStClass })
--> (FQBooleanQuery property: #isStub))
& (FQNavigationQuery incoming associations: {
FamixStReference.
FamixStInheritance }) & (FQNumericQuery
property: #numberOfLinesOfCodeWithMoreThanOneCharacter
comparator: #>
valueToCompare: 50)

The code is also shown in the “Current query code tab”: "The brand new Queries Browser"

As you may already noticed, there are two button for saving and loading the queries. The save button saves all queries that are currently present on the queries browser as a STON file. The queries will be saved inside a folder in the same location as the image. The path is determinated in MiSaveQueriesCommand class>>#path.

When loading the queries, the saved queries will be put after the queries that are present in the browser, if any. For example, if we save the queries that we have created above.

"Save queries as"

Then, with an empty browser, we create a new query and then loading the file we get:

"Load queries"

The new Queries Browser can simplify how the Famix Queries are created and make it more visual and understandable. Even if the example in this post is not complex, it made our tasks easier. Analyzing models with real-life examples can lead to very nested queries. Create those queries programmatically can be very tedious and error-prone. The Queries Browser is here to help us in those cases. 😄

How to build a new Moose tool: The MooseInspector

How to build a new Moose tool: The MooseInspector

Section titled “How to build a new Moose tool: The MooseInspector”

To create a new Moose Tool, you must create a child class of MiAbstractBrowser. This abstract class contains the basic infrastructure to all Moose browsers. It provides a toolbar with: buttons to inspect and propagate the current selection; Radio buttons to choose a reception mode; and a help button that shows the class comment for each browser.

"MiAbstactBrowser toolbar"

Also, it provides the logic to connect the browser to the Moose bus.

So, let us get started. We will create a “Moose Inspector”. It would be like the Pharo’s inspector but as a Moose browser. Firstly, we create the subclass as following:

MiAbstractBrowser subclass: #MiInspectorBrowser
instanceVariableNames: 'stInspector'
classVariableNames: ''
package: 'Moose-Core-Inspector'

As one can see, it has one instance variable which will hold an instance of Pharo’s inspector: StInspector.

Now, we must implement some basic methods. First let us implement initializePresenters method:

initializePresenters
super initializePresenters.
stInspector := self instantiate: StInspector.
stInspector model: self model

We instantiate stInspector variable an instance of Pharo’s inspector. Then we set the inspector model to be the same as the browser model.

Now we are going to implement canReceiveEntity: method. This method returns a Boolean which tells us if the entities received on the bus are usable in this browser. As we are building an inspector all entities can be accepted. So, we are going to return true always.

canReceiveEntity: anEntity
^ true

Then, we must implement followEntity: method. This method is called when new entities are received from the bus. In this case, we only need update the inspector model with the new entity. This method has the responsibility of defining the behaviour of the browser when new entities arrives from the bus. This is part of the bus mechanism of MiAbstractBrowser. This method is called if canReceiveEntity: anEntity returns true.

followEntity: anEntity
self model: anEntity.
stInspector model: self model

Next, the miSelectedItem method tells the bus what to propagate (when the user hits the “Propagate” button). In this case we want to propagate the object selected in the last inspector page.

miSelectedItem
| lastInspectorPage |
lastInspectorPage := stInspector millerList pages last.
^ lastInspectorPage model inspectedObject

Now we have all the logic and we can define the layout of this new browser. Now in Spec, the framework used to buld GUi in Pharo, we can implement dynamic layouts. So, we create a initializeLayout method. In that method, we take the layout of the super class, which is the toolbar, and we will add the other presenter.

initializeLayout
self layout: (SpBoxLayout newTopToBottom
add: self class defaultSpec expand: false;
add: stInspector;
yourself)

And do not forget to call this at the end of initializePresenters.

initializePresenters
super initializePresenters.
stInspector := self instantiate: StInspector.
stInspector model: self model.
self initializeLayout

Finally, we can define which will be the default model on which the browser will open. This is in case the bus does not have any entities. We want the Moose models, so create on class side:

newModel
^ MooseModel root entities

Optionally, we can override class side methods title and windowSize. We are ready to go. All we must do now is to run MiInspectorBrowser open on a Playground. This will open our new browser.

"Moose Inspector"

How to add new tabs in the Moose Inspector Browser

The new browser is not effective yet. We want to add some custom tabs to inspect the entities in a more visual way. To do so we can add some custom inspector tabs. When it displays an object, the inspector looks for methods of that object that have the <inspectorPresentationOrder:title:> pragma. The method should return a spec presenter that will be included in the inspector’s tab.

We will migrate the old “Properties” tab that is found in MooseFinder. The code is in MooseObject>>#mooseFinderPropertiesIn: We only have to rewrite it using Spec framework and use the pragma <inspectorPresentationOrder:title:>. We will create a method in MooseObject called inspectorPropertiesIn.

inspectorPropertiesIn
<inspectorPresentationOrder: 2 title: 'Properties'>
^ SpTablePresenter new
items: self mooseInterestingEntity mooseDescription allPrimitiveProperties;
sortingBlock: [ :x :y | x name < y name ];
addColumn: (SpStringTableColumn title: 'Properties' evaluated: #name);
addColumn: (SpStringTableColumn title: 'Value' evaluated: [ :each | (self mooseInterestingEntity mmGetProperty: each) asString ]);
yourself

Because the method is defined in MooseObject, any subclass (MooseModel, MooseEntity, …) will have this tab when displayed in the inspector.

That it is! Now we run again: MiInspectorBrowser open and we will se that the new tab now appears.

"Moose Inspector"

Dependency Structure Matrix for a Java project using Moose

Dependency Structure Matrix for a Java project using Moose

Section titled “Dependency Structure Matrix for a Java project using Moose”

As an extension to Analyzing Java With Moose, in this post I will show how one can create a Design Structure Matrix (DSM) in Moose, in particular from a model of a Java project.

First, you need to generate and load an MSE file into Moose for a Java project. Refer to this post for those steps, which uses the Java code from from Head First Design Patterns.

Roassal (which is a visualization platform that’s part of Moose) has a visualization for DSM called RTDSM. It’s explained here, but with Pharo classes. How to use it with Moose on a Java model?

The key is in the dependency: block, which we define using a Moose Query with allClients. Open a Moose Playground and paste the following Pharo code:

| dsm classes |
dsm := RTDSM new.
classes := (MooseModel root first allModelClasses
select: [ :c |
c mooseName
beginsWith:
'headfirst::designpatterns::combining::decorator' ])
reject: #isAnonymousClass.
"Avoid arbitrary ordering by sorting"
dsm objects: (classes asSortedCollection: [ :a :b | a name < b name]).
"Change the default label from asString which is very long"
dsm labelShapeX label text: #name.
dsm labelShapeY label text: #name.
"Moose Query equivalent to #dependentClasses for a Pharo class"
dsm dependency: #allClients.
dsm rotation: 270.
^dsm

Roassal DSM visualization

This visualization may not be as powerful as IDEA’s DSM analysis or Lattix’s, but it’s open source and can be manipulated in Pharo.

In Moose Query, the opposite to allClients is allProviders.