mirror of
https://github.com/EiffelSoftware/eiffel-org.git
synced 2025-12-07 07:12:25 +01:00
create 18.11
git-svn-id: https://svn.eiffel.com/eiffel-org/trunk@2112 abb3cda0-5349-4a8f-a601-0c33ac3a8c38
This commit is contained in:
@@ -0,0 +1,9 @@
|
||||
[[Property:title|Technical papers about EiffelStudio]]
|
||||
[[Property:description|Background, foundation, or supplemental information about uncovered topics]]
|
||||
[[Property:link_title|Papers]]
|
||||
[[Property:weight|4]]
|
||||
[[Property:uuid|97fe7aa0-adbf-405a-b5be-8187470dce50]]
|
||||
Occasionally papers are produced providing background, foundation, or supplemental information about the topics covered by the EiffelStudio documentation. Although the material in these papers might be of interest to many EiffelStudio users, they might not be suitable in their current form for inclusion in the mainstream documentation books.
|
||||
|
||||
You will find a collection of these papers in this book.
|
||||
|
||||
@@ -0,0 +1,119 @@
|
||||
[[Property:title|Appendix: Writing Documentation Filters with EFF, the Eiffel Filter Format]]
|
||||
[[Property:weight|6]]
|
||||
[[Property:uuid|0d17d433-3d4f-9575-49f7-d97eccb1a5b1]]
|
||||
This appendix provides reference information, not needed in simple uses of EiffelStudio.
|
||||
|
||||
We saw in the [[PRODUCING AND EXPORTING DOCUMENTATION|section on documentation]] that you can output documentation about your system in many different formats. A number of predefined formats are available, from Postscript to Microsoft's Rich Text Format, FrameMaker, HTML with and without style sheets, TEX and others. There's nothing special about these formats: they just make their conventions known to EiffelStudio through a '''filter''' expressed in a simple notation called EFF, or Eiffel Filter Format. If you have a favorite format that you'd like EiffelStudio to use for producing documentation, you can define your own filter in EFF. Applications include:
|
||||
* Producing a variant of an existing format, to support some "house style" that you have defined, such as a different formatting or fonts.
|
||||
* Producing documentation for a text processing tool that's not among those supported by default.
|
||||
* Producing documentation that purposely omit some parts of Eiffel texts, in line with the ideas applied by the Contract and Flat Contract forms.
|
||||
|
||||
This appendix describes EFF and its conventions, enabling you to write filters. Note that in practice the best way to write an EFF filter is usually not from scratch, but by copying an existing filter -- one that seems closest to your needs -- and adapting the copy.
|
||||
|
||||
==Where to put filters==
|
||||
|
||||
When you choose to generate documentation, EiffelStudio will ask you to select a filter from a list it obtains by looking up the files of extension <span>.</span> <code>fil</code> in the directory
|
||||
<code>$ISE_EIFFEL/studio/filters</code>
|
||||
|
||||
To make a new filter available to yourself and other users of this installation, just add the corresponding file <code>name</code> <span>.</span> <code>fil</code> to this directory. Make sure to choose the appropriate <code>name</code>, since this is what the menu of available filters will display.
|
||||
|
||||
==Filter basics==
|
||||
|
||||
An EFF filter follows a very simple structure. As with all other Eiffel-related notations (such as Eiffel itself and Lace, the control language for Eiffel systems), any line or part of a line beginning with two consecutive dashes <code>--</code> is a comment, except if it immediately follows a percent sign since, as will be seen below, <code>- %-</code> is used to denote an Eiffel comment in the class text. Blank lines are also permitted. Comments and blank lines carry no semantic value.
|
||||
|
||||
Except for comments and blank lines, a filter is a sequence of entries, all of the form
|
||||
<code>Construct | Replacement</code>
|
||||
|
||||
where: <code>Construct</code> is one of a set of possible strings, most of which correspond to Eiffel constructs such as <code>Class_declaration</code> or Eiffel keywords such as <code>class</code> ; and <code>Replacement</code> is a string indicating how to format specimens of the <code>Construct</code> that appear in a class text.
|
||||
|
||||
For readability, there may be any number of blanks or tabs between the <code>Construct</code> and the vertical bar <code>|</code>, so that you can align all the bars if you wish. On the right of the bar, however, all characters including blanks and tabs are significant, since they are part of the replacement for the <code>Construct</code>.
|
||||
|
||||
==The asterisk==
|
||||
|
||||
In the <code>Replacement</code> part, you may use the symbol <code>*</code> (asterisk) to denote the construct specimen itself. So for example the entry
|
||||
<code>Feature_clause | %N%N*%N%N</code>
|
||||
|
||||
specifies the following formatting for any <code>Feature_clause</code>: two successive blank lines (expressed as <code>%N</code>, New Line, a convention taken from Eiffel); the feature clause itself; two blank lines.
|
||||
|
||||
Similarly, in an HTML format, the entry
|
||||
<code>External |<B> * </B></code>
|
||||
|
||||
means that the Eiffel keyword <code>external</code> must appear in the filtered form immediately preceded by <code><B></code>, the HTML code for switching to boldface, and immediately followed by <code></B></code>, the code for reverting to the previous setup. Here you can also write the right-hand side without the asterisks, as <code><B>external</B></code>. If, however, all keywords are to use boldface, it is preferable to write a single entry
|
||||
<code>Keyword |<B> * </B></code>
|
||||
|
||||
which, thanks to the asterisk, will govern all construct specimens of the <code>Keyword</code> category. You can still override this specification for an individual keyword by including a specific entry for it.
|
||||
|
||||
==Constructs==
|
||||
|
||||
The following general syntactic constructs may appear as the left-hand side, <code>Construct</code>, of an entry:
|
||||
<code>
|
||||
Class_declaration
|
||||
Class_end
|
||||
Class_header
|
||||
Class_name
|
||||
Comment
|
||||
Creators
|
||||
Escape
|
||||
Feature_clause
|
||||
Feature_declaration
|
||||
Features
|
||||
Formal_generics
|
||||
Indexing_clause
|
||||
Inheritance
|
||||
Invariant_clause
|
||||
Keyword
|
||||
New_line
|
||||
Obsolete_clause
|
||||
Suffix
|
||||
Symbol
|
||||
Tab
|
||||
</code>
|
||||
|
||||
Most of these denote Eiffel constructs as they appear in the official language reference, the book <span> [[Eiffel: The Language]] </span>. Since the Eiffel construct names <code>Feature</code>, <code>Invariant</code> and <code>Obsolete</code> are also keywords and EFF, like Eiffel, is case-insensitive, the EFF construct names use the suffix <code>_clause</code>, for example <code>Feature_clause</code>.
|
||||
|
||||
The constructs corresponding to syntactic constructs are self-explanatory. The others are:
|
||||
* <code>Class_end</code>, denoting the final end of a class text.
|
||||
* <code>Keyword</code>, denoting any Eiffel keyword among those listed in boldface in the corresponding appendix in <span> [[Eiffel: The Language]] </span>
|
||||
* <code>New_line</code>, denoting any passage to a new line in the class text.
|
||||
* <code>Suffix</code>, used to introduce the file extension for the generated documentation files. If you don't specify this, EiffelStudio will use the filter's name as extension.
|
||||
* <code>Symbol</code>, denoting any of the Eiffel symbols listed in the corresponding appendix of <span> [[Eiffel: The Language]] </span>.
|
||||
* <code>Escape</code>, to protect special characters of the external tool, as explained below.
|
||||
* <code>Tab</code>, denoting any tab character appearing in the class text.
|
||||
|
||||
==Keywords==
|
||||
|
||||
A <code>Construct</code> part may consist of the name of an Eiffel keyword. To see the complete list of possible keywords, look at the <code>template</code> filter, file <code>format.fil-template</code> in the default filter directory <code>$ISE_EIFFEL/studio/filters</code>, which includes all of them with a single asterisk <code>*</code> as the <code>Replacement</code> part.
|
||||
|
||||
If entries are present for both the <code>Keyword</code> construct and individual keywords, the individual keyword entries will override the general entry for the keywords listed; the general entry will apply to all other keywords. This makes it possible to have both a general convention for keywords and a special convention for some of them.
|
||||
|
||||
==Symbol==
|
||||
|
||||
A <code>Construct</code> part may consist of an Eiffel symbol, such as <code>:=</code>, <code>/=</code> and many others. Again, you may see the complete list by looking at <code>format.fil-template</code>. Note the following conventions:
|
||||
* <code>%</code> <code>*</code> represents an asterisk. For example as a multiplication operator; the <code>%</code> avoids the confusion with the special meaning of the asterisk for EFF. You can find examples of this convention in the EFF filters for troff and gtroff.
|
||||
* Similarly, the Eiffel comment symbol appears as <code>- %-</code>, since just writing <code>- -</code> would introduce a comment in the EFF filter itself.
|
||||
|
||||
As with keywords, you may specify a general convention for symbols, defined by an entry for the construct <code>Symbol</code>, and special conventions for certain individual symbols. Specific symbol entries will override the general <code>Symbol</code> convention.
|
||||
|
||||
==Escape characters==
|
||||
|
||||
A text processing system or other external tool may attach a special role to characters that may normally appear in Eiffel texts. For example, the braces <code>{</code> and <code>}</code>, used in Eiffel's Export clauses, have a special meaning for TEX. Including them without precaution in TEX input will cause trouble. Similarly, many text processing formats attach a special meaning to the backslash character <code>\</code> which, although not special for Eiffel, may appear in an Eiffel string.
|
||||
|
||||
In such cases the filter must " <span>escape</span> " the special character, that is to say, protect it by other characters. For example troff and other text processing tools treat two successive backslash characters <code>\\</code> as denoting a single backslash in the text to be output. The first backslash is the escape character, protecting the second one.
|
||||
|
||||
The <code>Escape</code> construct addresses such cases. The first character that follows <code>Escape</code> (after one or more blanks or tabs) is the character to be escaped. The string after the vertical bar is the replacement for that character.
|
||||
|
||||
Here for example is an escape entry for the backslash in tools that need to escape it through another backslash:
|
||||
|
||||
==Special characters and strings==
|
||||
|
||||
EFF uses Eiffel-like conventions, based on the percent sign, for control characters appearing in <span>Replacement</span> parts of entries. Two of these conventions have just been noted: <code>%</code> <code>*</code> to represent an asterisk and <code>%-</code> to represent a dash that does not introduce an Eiffel comment. In addition:
|
||||
* <code>%|</code> denotes a vertical bar. (This is necessary since EFF uses <code>|</code> by itself in each entry to separate the <span>Construct</span> from the corresponding <span>Replacement</span>.)
|
||||
* <code>%N</code> (recommended form) or <code>%n</code> denotes a new line.
|
||||
* <code>%T</code> (recommended form) or <code>%t</code> denotes a tab.
|
||||
* <code>%%</code> denotes a percent sign.
|
||||
* <code>%</code> (percent followed by a space) denotes a space. This is equivalent to just a space, but more visible.
|
||||
|
||||
If <code>c</code> is not one of the characters for which special conventions have been listed, <code>%</code> <code>c</code> denotes the character <code>c</code> itself.
|
||||
|
||||
A multi-line entry uses the Eiffel convention for string continuations: <code>%</code> at the end of a line to signal that there is a continuation; a continuation line begins with zero or more spaces and tabs followed by a <code>%</code> ; the characters after the <code>%</code> are the continuation of the string.
|
||||
|
||||
@@ -0,0 +1,95 @@
|
||||
[[Property:title|Browsing Features]]
|
||||
[[Property:weight|-6]]
|
||||
[[Property:uuid|2c0b0a6c-08e8-fdbc-1eab-e2d87b01ce48]]
|
||||
Let us get back to EiffelStudio. Before studying the documentation generation we saw how to display properties of '''classes'''. It's also interesting to explore the properties of '''features'''.
|
||||
|
||||
There are two tools with similar sounding names that we will use to explore features:
|
||||
# The [[Features Tool|Features tool]] (plural) which provides a list of the immediate features of the class on which the development window is targeted. This tool is located by default in the vertical pane on the right hand side of the development window.
|
||||
# The Feature tool (singular) which allows you to explore the properties of some particular feature. By default, the Feature tool is available as a tab on the lower pane of the development window along with the Class tool, Outputs tool, and others.
|
||||
|
||||
Your Development Window should still be targeted to class <code>LIST</code>, from the last view, <code>Routines</code>, that you displayed on it. If you've lost it, just retarget a Development Window to this class.
|
||||
|
||||
Let's start by making the [[Features Tool|Features tool]] visible. To see the Features tool click on the tab labeled [[Image:features-tab]] (note that this is the plural "Features" versus the singular "Feature").
|
||||
|
||||
If the tab for the Features tool is not visible, bring it back by following the menu path:
|
||||
<code lang="text">
|
||||
View --> Tools --> Features
|
||||
</code>
|
||||
|
||||
While we are at it, let's get make the Feature tool visible as well. Click on the tab on the lower pane that's labeled [[Image:feature-tab]]. As with the Features tool, if the Feature tab is missing, you can use the menu path to restore it.
|
||||
|
||||
One more thing, and we'll look at some features. If you restarted EiffelStudio since you worked through the [[Viewing Classes]] section, you may have to select <code>Link Context Tool</code> again from the <code>View</code> menu.
|
||||
|
||||
|
||||
==Targeting to a feature==
|
||||
|
||||
The list of features, organized by feature clauses, appears in the Features tool:
|
||||
|
||||
[[Image:es gt features tool 01]]
|
||||
|
||||
The class only has a few immediate features because most of its interesting features are inherited. Make sure the Editor tool is tall enough (as on the above figure) and click the feature <code>forth</code>, the last one, in the Feature Tree on the left. This makes the feature the Editor tool's current target, and scrolls the text to its declaration:
|
||||
|
||||
[[Image:es gt features tool 02]]
|
||||
|
||||
Note how both of the top target fields are now filled: the first one shows the target class, <code>LIST</code>, and the second one shows the target feature, <code>forth</code>.
|
||||
|
||||
|
||||
==Basic feature information==
|
||||
|
||||
Now let's look at the views of the feature <code>forth</code> provided in the Feature tool.
|
||||
|
||||
A view of <code>forth</code> is already visible in the Feature tool. By default, it is the <code>Flat</code> view.
|
||||
|
||||
[[Image:es gt feature tool 01]]
|
||||
|
||||
The flat view of a feature, similar in concept to the flat view of a class, gives the full text of a feature, taking into account any inherited precondition or postcondition clauses. Here the feature as declared in the class appears in the top Editing Tool, with no precondition and an <code>ensure then</code> postcondition clause. But it's a redefinition of an inherited feature; the flat view in the bottom Context Tool shows the full precondition, inherited from the ancestor <code>LINEAR</code>, as well as the postcondition from <code>LIST</code>.
|
||||
|
||||
<code>Flat</code> is just one of the available Feature Views, shown by the buttons on the toolbar of the Feature tool.
|
||||
|
||||
[[Image:es gt feature tool toolbar buttons 01]]
|
||||
|
||||
You can mouse-over the different buttons to see the views they represent.
|
||||
|
||||
Just to the left of <code>Flat</code>, <code>Basic Text</code> gives the feature text, fully clickable.
|
||||
|
||||
|
||||
==Who calls this feature?==
|
||||
|
||||
To the right of <code>Flat</code> is <code>Callers</code>. Try it now by clicking the corresponding button. You may have to scroll down some in the display to see the series of entries show in the image below;
|
||||
|
||||
[[Image:es gt feature tool callers 01]]
|
||||
|
||||
This view shows all the places in the system that call the routine, or one of its redefinitions. Such information can be invaluable for debugging in particular. The successive paragraphs correspond to the various versions of <code>forth</code> in class <code>LIST</code>, its ancestors and its descendants. Reading from the top we'll examine a few entries:
|
||||
* The version from <code>LIST</code> is called in <code>LIST</code> itself by the function <code>is_equal</code>.
|
||||
* The version from <code>LIST</code> is called in routines in two debugger classes <code>RT_DBG_CALL_RECORD</code> and <code>RT_DBG_COMMON</code>
|
||||
* The version <code>forth</code> from <code>MULTI_ARRAY_LIST</code> is a version in a descendant of <code>LIST</code>, and is called by three routines of <code>MULTI_ARRAY_LIST</code> itself: <code>duplicate</code>, <code>put_right</code>, and <code>remove_right</code>.
|
||||
* Although it is not shown in the figure, if you scroll around some, you will find cases in which a descendant of <code>forth</code> has been renamed and that renamed version is called. For example <code>child_forth</code> from <code>LINKED_TREE</code> is descendant version of <code>forth</code> and is called by routines in <code>LINKED_CURSOR_TREE</code> and <code>LINKED_TREE</code>.
|
||||
|
||||
The following five view buttons are similar except that they let you specify what kind of callers you are looking for, or what is being called by the currently selected feature. Feel free to explore these views.
|
||||
|
||||
|
||||
==What happens to my feature through the inheritance hierarchy?==
|
||||
|
||||
After the caller/callee views, the next view button is <code>Implementers</code>.
|
||||
|
||||
This is a very useful view, showing all the ancestors and descendants of <code>LIST</code> that provide a separate version of <code>forth</code>, including the original introduction of this feature in <code>LINEAR</code> and subsequent redeclarations (redefinitions or effectings). The mention <code lang=text>(version from)</code> signals the version applicable to the current class, here <code>LIST</code>.
|
||||
|
||||
Since all class and feature names on these views are hyperlinks, you can display any of the listed versions in a new Development Window by control-right-clicking it (we will see shortly how to display it in the ''same'' tool). Right-click on the feature name <code>forth</code> on the line that reads <code>MULTI_ARRAY_LIST forth</code>. This brings up a context menu and chose <code lang=text>Show --> Text</code>. The tool is now targeted to the routine <code>forth</code> from <code>MULTI_ARRAY_LIST</code>, so that you can see the implementation of the routine in that class.
|
||||
|
||||
We still have two unexplored views, <code>Ancestor versions</code> and <code>Descendant versions</code>. Click the first of these to obtain the ancestor versions of <code>forth</code> from <code>MULTI_ARRAY_LIST</code>.
|
||||
|
||||
The format is self-explanatory: for each ancestor of <code>MULTI_ARRAY_LIST</code> that has a version of <code>MULTI_ARRAY_LIST</code> 's <code>forth</code> feature, it indicates the name of that feature -- which could be something else than <code>forth</code> as a result of renaming, although here this happens only in descendants, not ancestors -- and the version of the feature applicable to the given class.
|
||||
|
||||
In the case of feature merging (combining several features inherited from different parents, in conformance with the rules of the language) there could be more than one history branch, in this case each branch is labeled <code>Branch #X.</code>
|
||||
|
||||
The next button, <code>Descendant versions</code>, similarly tells you all that happens to a feature in the descendants of the current class.
|
||||
|
||||
|
||||
==Who has the same name?==
|
||||
|
||||
The last button, <code>Homonyms</code>, displays all the features of the system which, related or not to the current feature by redeclaration, have the same name. You can then explore any such feature to see if the relationship is more than casual.
|
||||
|
||||
In any system or library that takes advantage of inheritance and its associated mechanisms -- renaming, redefinition, effecting, undefinition, multiple and repeated inheritance, polymorphism, dynamic binding -- the feature browsing facilities that we have just explored are invaluable to track what happens to features. What makes them even more precious is their connection with the rest of the browsing and documentation capabilities, especially the pick-and-drop which we will now study.
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
[[Property:title|The Command-Line Compiler]]
|
||||
[[Property:weight|4]]
|
||||
[[Property:uuid|62bd8d62-a734-3ec0-9533-eaa096e7b81f]]
|
||||
Along with compilation from within EiffelStudio, it is possible to start compilation from a command line (shell). This is useful in particular to recompile your system automatically as part of a script.
|
||||
|
||||
Click [[EiffelStudio: Using command line options|here]] to see how to use the command line compiler and the set of supported options.
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
[[Property:title|Compiling and Executing a System]]
|
||||
[[Property:weight|-12]]
|
||||
[[Property:uuid|58494be3-f29f-3a15-a27e-e635bdc71c53]]
|
||||
EiffelStudio first comes up with a window and a dialog on top of it; the dialog looks like this (from here on the look-and-feel will be slightly different on platforms other than Windows, but the content will be the same):
|
||||
|
||||
[[Image:es gt open 01]]
|
||||
|
||||
|
||||
As this is our first project we want to "<code>Add Project...</code>". We could also
|
||||
* "<code lang="text">Create project</code>", which would let you select one among the common schemes -- basic application, graphical Windows application, graphical multi-platform application, Microsoft .NET application -- and set up everything for you.
|
||||
* "<code>Open project</code>", which would let you open a previously added project.
|
||||
|
||||
In future sessions you'll probably use "<code lang="text">Create project</code>" for a new project, as it takes care of generating a root class and configuration file for you, and <code>Open project</code>" to open an existing project.
|
||||
|
||||
Right now you first have to add the project, so click on the <code>Add Project...</code> button. This brings up a File Explorer inviting you to select an ECF file. The file you want is the file
|
||||
<code>
|
||||
simple.ecf
|
||||
</code>
|
||||
|
||||
in the directory "<code>YOURDIR</code>", (either <code>$ISE_EIFFEL\examples\studio\tour</code> or the copy that you have made). The ".ecf" file is an Eiffel Configuration File which contains the information necessary for construction of an Eiffel project.
|
||||
|
||||
So, use the File Explorer to find and select the file <code>simple.ecf</code>.
|
||||
|
||||
[[Image:es gt open 02]]
|
||||
|
||||
|
||||
Click the button labeled <code>Open</code> to confirm. This starts compilation of your project.
|
||||
|
||||
During Eiffel compilation, you can observe the successive compilation steps, or "degrees", in the [[Outputs tool]]. The bulk of our little project is the EiffelBase library, which the EiffelStudio installation procedure has precompiled; as a result, there are only a few extra classes to compile, and the process is almost instantaneous on a state-of-the-art computer.
|
||||
|
||||
|
||||
{{note|As a frame of reference, on a Toshiba Satellite laptop, mobile dual core 1.73 GHz, 1 GB memory, running Windows Vista, this Eiffel compilation takes about 3.5 seconds. }}
|
||||
|
||||
After Eiffel compilation completes you will see the message
|
||||
<code>
|
||||
Eiffel Compilation Succeeded
|
||||
</code>
|
||||
in the Outputs tool.
|
||||
|
||||
At this stage your project has finished compiling.
|
||||
|
||||
So, congratulations! You have successfully compiled your first Eiffel project. More precisely your project has been "melted". Strange terminology, you may think; in a [[How EiffelStudio Compiles|later section]] we'll see the derivation of the names used in the compilation process.
|
||||
|
||||
==Executing the system==
|
||||
|
||||
Our system doesn't do anything very exciting, but let's execute it anyway. Find and click the Run button ( [[Image:debug-run-icon]] ) on the toolbar at the top of the EiffelStudio window.
|
||||
|
||||
This little application doesn't use graphics or any other fancy stuff. It simply creates some objects and displays some information. Output is accomplished by using the default Eiffel I/O features (from the EiffelBase classes <code>ANY</code> and <code>STANDARD_FILES</code>), and that output goes to a console. On Unix/Linux and OpenVMS it's the window from which you started EiffelStudio. On Windows, by default, it's a new console window that comes up when and if the system does its first output operation, and stays up you dismiss it:
|
||||
|
||||
[[Image:es gt execute 01]]
|
||||
|
||||
|
||||
The message "<code>Press Return to finish the execution...</code>" would not appear if you executed the system from outside of EiffelStudio, for example from a command line. Its purpose within EiffelStudio is clear: to let you see the console output; without it, the console would go away at the end of execution. (None of this applies to Unix/Linux/OpenVMS because no new console window was created when we executed the system.)
|
||||
|
||||
Before closing the console window, if you look at the main EiffelStudio window (by moving the console window aside) you will notice that it looks different than it did before. This is because EiffelStudio is now in debug mode, so it shows the fields useful in monitoring, controlled execution, and debugging. But we'll look at all this later. For the moment just dismiss the console by following the advice to "<code>Press Return to finish the execution...</code>": hit the Return or Enter key.
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
[[Property:title|Computing Project Metrics]]
|
||||
[[Property:weight|0]]
|
||||
[[Property:uuid|8d1a3556-d9a2-0ac8-4d54-458f18cb56ad]]
|
||||
In earlier sections we saw how EiffelStudio provides extensive documentation on your systems. That information was qualitative. Project managers and developers will also be interested in <span>quantitative</span> information about their projects. You can get such information through the <code>Metrics</code> tool, which enables you to perform a number of operations, detailed over the next few pages:
|
||||
* Apply predefined metrics -- number of classes, number of invariants, number of features, number of compilations so far and many others -- to components of a system at various levels including feature, class, cluster, entire system.
|
||||
* Define new metrics, through mathematical formulae or boolean selection, and apply them to your project.
|
||||
* Store measurement results, as well as metric definitions, into an XML archive that can be stored locally or made available on the Web for future reference.
|
||||
* Compare the measurements on a system to those on record locally or on a Web site. Eiffel Software has released on its own site an archive recording the metric properties of its basic libraries, available to any other project for comparison.
|
||||
|
||||
==Methodological observations==
|
||||
|
||||
Although the field of software metrics is a rich one with an abundant literature, its methodological basis is sometimes subject to question. One should resist the tendency to believe numbers just because they are numbers ("lies, damn lies, and metrics").
|
||||
|
||||
Software engineers and their managers expect, however, to reap at least some of the benefits that precise quantification has brought to other engineering fields. Such is the purpose of software metrics, defined as '''quantitative estimates of product and project properties'''. Object-oriented development, with the rich software structures that it induces, is a particularly amenable to metric analysis. Even when some of the measures do not seem to bring much by themselves, comparing them to those of other projects may reveal significant peculiarities of a system or of some of its parts.
|
||||
|
||||
The metrics capabilities of EiffelStudio were designed with these observations in mind. They result from a conservative approach, where no metric is provided without a credible assumption that it reflects some meaningful project or product attribute. For example, you will find a way to define a new metric as a <span>linear combination</span> of existing ones, but not a way to compute arbitrary arithmetic operations, since it isn't clear that -- say -- <span>multiplying</span> two metrics ever makes sense.
|
||||
|
||||
==Metric terminology==
|
||||
|
||||
The following terms are used in the presentation of EiffelStudio metric mechanisms.
|
||||
|
||||
A '''metric''' -- not to be confused with a measure -- is a quantitative property of software products or processes whose possible values are numbers. A '''measure''' is the value of a metric for a certain product or process.
|
||||
|
||||
For example, we can evaluate the metric "number of classes in the system", called just <code>Classes</code>, by counting the classes in our system. This yields a measure.
|
||||
|
||||
We may distinguish between '''product''' ''' metrics''', which measure properties of the elements being turned out (code, designs, documentation, bug reports...) and '''process''' ''' metrics''', which measure properties of the process used to turn them out (salaries, expenses, time spent, delays...). The current metric facilities of EiffelStudio are primarily product-oriented but include a process metric: "number of compilations".
|
||||
|
||||
Any metric should be relevant: related to some interesting property of the processes or products being measured, such as cost, estimated number of bugs, ease of maintenance...A '''metric theory''' is a set of metric definitions accompanied with a set of convincing arguments to show that the metrics are relevant. Neither EiffelStudio nor this manual provide a metric theory.
|
||||
|
||||
The numbers yielded by measures are meaningless unless we describe what they refer to. Every metric is relative to a certain '''unit''', specified as part of its definition. For example the unit for a metric that counts classes, such as <code>Classes</code>, is called <code lang=text>class</code>.
|
||||
|
||||
EiffelStudio provides a set of predefined units. Some simply serve to count occurrences of certain construct specimens in the software; examples include <code>group</code>, <code lang=text>class</code>, <code lang=text>feature</code>, <code>line</code>, <span>...</span> The metric <code>ratio</code> describes metrics whose values are divisions, for example "average number of classes per cluster", obtained by dividing the number of classes by the number of classes.
|
||||
|
||||
A metric can be computed over a scope. This scope is defined using a '''domain'''. A domain is a set of program elements. You build up a domain by adding development objects to a list. These development objects are things like application targets, clusters, libraries, classes, and features.
|
||||
|
||||
|
||||
==Metric tool interface==
|
||||
|
||||
The following links will take you out of the Guided Tour and into the EiffelStudio Reference:
|
||||
|
||||
* EiffelStudio reference: [[Metric Evaluation Panel|Metric Evaluation panel]]
|
||||
* EiffelStudio reference: [[Detailed Result Panel|Detailed Result panel]]
|
||||
* EiffelStudio reference: [[Metric Definition Panel|Metric Definition panel]]
|
||||
* EiffelStudio reference: [[Metric History Panel|Metric History panel]]
|
||||
* EiffelStudio reference: [[Metric Archive Panel|Metric Archive panel]]
|
||||
|
||||
|
||||
{{SeeAlso| The EiffelStudio Reference section on the [[Metrics Tool]] for more comprehensive discussion and precise definitions of terminology.}}
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
[[Property:title|Copying the Example Files]]
|
||||
[[Property:weight|-14]]
|
||||
[[Property:uuid|bb8ff7d7-2e93-d150-339c-d9afb967bc98]]
|
||||
{{note|If you are using Eiffel on a personal computer, you have the option of working directly in the installation directory and would not necessarily need to make copies of files as per the present section. If you choose to work directly in the installation directory, skip this section and go on to the next section, [[Starting EiffelStudio and Opening a Project]]. If you work under Unix or OpenVMS, or may have to share the Eiffel installation with other users, do not have write permissions on the installation, or want to keep the installation unchanged, then please do read the present section and apply its instructions.}}
|
||||
|
||||
If you are going to work on a copy, choose or create a directory of your own; let's call it <code>YOURDIR</code> for the rest of the discussion.
|
||||
|
||||
To copy all the files of the example to <code>YOURDIR</code>:
|
||||
* On Windows, open a Windows Explorer, go to <code>$ISE_EIFFEL\examples\studio\tour</code> , select all the files in that directory, and drag-and-drop them to <code>YOURDIR</code> .
|
||||
* On Unix execute the shell command
|
||||
<code lang="text">
|
||||
cp $ISE_EIFFEL/examples/studio/tour/* YOURDIR</code>
|
||||
|
||||
* On OpenVMS execute the command
|
||||
<code lang=text">
|
||||
copy $ISE_EIFFEL:[examples.studio.tour]*.* YOURDIR</code>
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,267 @@
|
||||
[[Property:modification_date|Tue, 21 Aug 2018 18:55:21 GMT]]
|
||||
[[Property:publication_date|Tue, 21 Aug 2018 18:55:21 GMT]]
|
||||
[[Property:title|Customizing the tools layout and toolbars]]
|
||||
[[Property:weight|-8]]
|
||||
[[Property:uuid|eb75573e-c653-9290-376a-063cb5fa32d4]]
|
||||
==Overview==
|
||||
|
||||
We saw in [[Viewing Classes]] how EiffelStudio panes could be resized and how the Auto Hide feature works for a pane.
|
||||
|
||||
Now let's look at some other ways in which you can customize the layout the EiffelStudio tools.
|
||||
|
||||
The first time you use EiffelStudio, it will display a '''default''' tools layout that reflects the preferences of a majority of users. Typical user preferences change, so don't be too surprised if things look just a little different after installing a new version.
|
||||
|
||||
As you gain more experience with EiffelStudio, you may want to adapt the layout to your personal preferences. For example, you may always want to have certain tools visible which were not visible by default. Once you make a change like this, EiffelStudio generally remembers that change and it will be in force the next time you open EiffelStudio. But you can also save a complete tools layout and recall it at a later time. For example, you might have two or three different development '''modes''' that you work in, and have a saved tools layout for each.
|
||||
|
||||
The ways in which the EiffelStudio tools can be arranged are nearly endless. You can make tools visible or hide them. You can make almost any tool a tab in almost any pane. You can re-order the tabs for a pane. You can pull tools completely out of EiffelStudio as free-floating windows. You can create additional panes as needed. Almost any pane can be "pinned" open or "auto hidden".
|
||||
|
||||
|
||||
==Reverting to the default layout==
|
||||
|
||||
If you changed the layout and are not pleased with the result, you can revert to the default. Use the menu path:
|
||||
<code lang="text">
|
||||
View --> Tools Layout --> Reset Tools Layout
|
||||
</code>
|
||||
to reset EiffelStudio to the default tools layout.
|
||||
|
||||
[[Image:es gt reset tools layout 01|Reset Tools Layout]]
|
||||
|
||||
Figure 1
|
||||
|
||||
|
||||
So at the end of the section [[Viewing Classes]] we manually reversed the changes that we had made to the layout to make additional space. We could have just selected Reset Tools Layout to restore the default layout.
|
||||
|
||||
You can try this now and see the effect. Your tools layout will probably not change very much.
|
||||
|
||||
You can see in the image above that you would also follow that menu path in order to save a tools layout or to activate one that you had previously saved.
|
||||
|
||||
|
||||
==Minimizing, maximizing, restoring, and closing tools==
|
||||
|
||||
At the right end of the top bar for each tool you will see buttons that help you control the way the tool and its containing pane are displayed. Here are the icons and what they mean:
|
||||
|
||||
* [[Image:minimize-icon]] Minimize this pane.
|
||||
* [[Image:maximize-icon]] Maximize this pane.
|
||||
* [[Image:restore-icon]] Restore this pane to its previous size.
|
||||
* [[Image:auto-hide-icon]] Set this pane to Auto Hide.
|
||||
* [[Image:close-icon]] Close this tool.
|
||||
|
||||
There are a few subtleties you should understand when using these:
|
||||
|
||||
The pane in which the Editing tool resides is special. It is the only pane that supports '''minimize'''. And it does not support Auto Hide, nor Close. We'll learn a little more about this in the section on [[#Docking|Docking]].
|
||||
|
||||
When you maximize a pane it fills all available space. At the same time, its maximize icon changes to the Restore icon. When you click Restore, the pane relinquishes the extra space it annexed when you maximized it, and then returns to its original size and location.
|
||||
|
||||
The Close button will close only the current tool. So, that tool goes away, but any other tools in the same pane remain. However, when you close the last tool in a pane, the pane itself disappears and the space is absorbed by other panes. Remember that you can re-display closed tools through the menu path:
|
||||
<code lang="text">
|
||||
View --> Tools --> tool name
|
||||
</code>
|
||||
|
||||
{{note|EiffelStudio supports a number of [[EiffelStudio: Key shortcuts|'''key shortcuts''']] (sometimes called '''accelerators''', some of which can be useful for changing aspects of the Development Window. For example, <code>CTRL+M</code> will toggle the Editing pane between Maximize and Restore, and <code>CTRL+N</code> will create a fresh Development Window. Keyboard shortcuts themselves are tailorable in the [[Keyboard shortcuts preferences|EiffelStudio Preferences]].}}
|
||||
|
||||
|
||||
==Re-ordering tabs==
|
||||
|
||||
Within a particular pane, it is possible to have many tools visible. Each will be represented as a tab at the bottom of the pane. For example, the pane that contains the Class and Feature tools has the following tabs by default in the version that is current at the time of this writing:
|
||||
|
||||
|
||||
[[Image:es gt default pane tabs|A default set of tool tabs]]
|
||||
|
||||
Figure 2
|
||||
|
||||
|
||||
One easy way to customize your tool layout is to change the order of these tabs if you prefer. Just drag a tab horizontally to a new position to the right or left of where it originally was located and release it. As you drag the tab, you'll see it relocate itself, so you'll know just were it will end up when you release it.
|
||||
|
||||
So suppose that you felt that it would be more convenient to your style of work to have the Outputs tool be the left most tool, versus the Class tool. Just drag it over there ... and now your tabs should reflect the new order:
|
||||
|
||||
|
||||
[[Image:es gt reordered pane tabs|Tool tabs after moving Outputs tool to the left end]]
|
||||
|
||||
Figure 3
|
||||
|
||||
|
||||
Try this now, if you'd like but be careful to move the tab '''only''' horizontally along the row of other tabs. If you move it off the row of tabs, you may inadvertently enter the extraordinary, but more complex realm of '''docking''', our next topic. Just in case you do get off the row of tabs and you see strange icons appearing on the Development Window, don't release the mouse button, just press the <code>ESC</code> key to cancel the dragging action.
|
||||
|
||||
|
||||
==Docking==
|
||||
|
||||
The docking ability within EiffelStudio is arguably the most powerful tool at your disposal for tailoring the tools layout to your liking. Docking can be a little daunting at first, but once you understand a few concepts, you will likely find it both easy to use and helpful.
|
||||
|
||||
Maybe the first thing to know about docking is that EiffelStudio gives you the option of locking elements of the interface against inadvertent changes in docking. Following the menu path:
|
||||
<code lang="text">
|
||||
View --> Docking Lock
|
||||
</code>
|
||||
you can choose to lock (or leave docking enabled) on toolbars, tool panes, and/or editing panes. So, if you get things just the way you want them, in addition to save your tool layout, you may want to lock the elements against additional docking changes.
|
||||
|
||||
Perhaps the second thing to understand, if you haven't already guessed, is that, for docking purposes, the EiffelStudio interface supports toolbars and two different types of panes. One type of pane is the one in which the Editing tools reside, which we'll call an '''editing pane'''. The other is the type of pane is the '''tools pane''' where other tools can be docked.
|
||||
|
||||
So, with this in mind, we can take another look at the EiffelStudio layout.
|
||||
|
||||
|
||||
[[Image:es gt a development window 02|Default tools layout]]
|
||||
|
||||
Figure 4
|
||||
|
||||
|
||||
Here we see the editing pane with one editing tool targeted to the class <code>LIST</code>.
|
||||
|
||||
There are two tools panes. Docked in one are the Class, Feature, Outputs, and Error List tools. In the other are the Groups, Features, and AutoTest tools ... and to the right of the AutoTest tab we see the icon ([[Image:continued-icon]]) and a number indicating that there are more tabs, but no room to display them. In this case there is only one more tab; it is for the Favorites tool. Of course, if the that tools pane were a little wider, we would see the tab for the Favorites tool and the "continued" icon and the number would disappear.
|
||||
|
||||
It turns out that there are actually two more tools panes in this layout. One contains the Diagrams tool and the other contains the Dependency, Metrics, and Info tools. These two panes are Auto Hidden so we only see the minimum evidence that they exist ... just their tabs. You can tell that these are two different panes by how the tabs are distributed. Diagram is somewhat "off by itself" whereas Dependency, Metrics and Info are grouped closely together.
|
||||
|
||||
As we learned in [[Viewing Classes]] you can make one of these tool panes visible by moving your cursor over it, or clicking on one its tabs. The pane will expose itself for the length of time that the cursor remains over it, then recede into hiding again when the cursor is moved away.
|
||||
|
||||
Try this now with the Diagram tool. The pane housing the diagram tool appears from the bottom of the screen. Notice also that it has occluded the pane containing Class, Feature, Outputs, and Error List tools, and about half of the pane containing the Groups, Features, AutoTest, and Favorites tools.
|
||||
|
||||
|
||||
[[Image:es gt development window diagram tool unhidden|Diagram tool unhidden]]
|
||||
|
||||
Figure 5
|
||||
|
||||
|
||||
So, Auto Hide works well to keep panes that we might not use very often out of the way ... but still pretty handy.
|
||||
|
||||
===Floating a pane===
|
||||
|
||||
Let's dive into our first docking (or maybe undocking) experience. Suppose, though, that you were in the analysis and design phase of a project and you wanted the Diagram tool to be open and available at all times. Of course, you could move your cursor over it to "un-hide" it, then pin it open. But then it would be covering the other tool panes which we use often.
|
||||
|
||||
One great capability of the docking mechanisms in EiffelStudio is that you can disconnect, or '''float''', a pane away from the rest of the EiffelStudio development window. Let's float the hidden pane that now contains just the Diagram tool out to the right of the entire Development Window.
|
||||
|
||||
In order to float this tool pane, we first have to set Auto Hide off.
|
||||
|
||||
|
||||
{{note|In versions of EiffelStudio starting with version 6.6, it will no longer be necessary to set Auto Hide off before moving a pane. }}
|
||||
|
||||
|
||||
So move your cursor over the Diagram tab and the pane should expand (if it does not make it self visible, then click on the tab). Then move to the upper right and click the horizontal pushpin icon ([[Image:auto-hide-off-icon]]) to turn off Auto Hide and pin the pane open.
|
||||
|
||||
|
||||
[[Image:es gt diagram tool pane pinned 01|With Auto Hide off, occluded panes become visible.]]
|
||||
|
||||
Figure 6
|
||||
|
||||
|
||||
You may notice that a pane that is auto hidden may, when it expands, occlude other panes. However, when you turn of Auto Hide by pinning the pane open, any panes that it had occluded will become at least minimally visible. In the case of this example, the pane containing the Class tool was temporarily covered by the expanded Diagram pane, as was the row of tabs on the pane containing Groups. When you pin the Diagram pane open, the title bar for the pane with the Class tool becomes visible, and the pane with the Groups tool gets shortened to fit above the Diagram tool's pane.
|
||||
|
||||
It is at this point that new EiffelStudio sometimes have problems understanding what's happening. So read the following description of what's going on before you actually try to move the pane ... and don't forget that you can always reset the tools layout if things don't go the way you intended.
|
||||
|
||||
Now that we've turned off Auto Hide for Diagram's pane, we can move the pane and either re-dock it somewhere else in the development window or, as is our intention, "float" it as a window separate from the Development Window.
|
||||
|
||||
To undock and re-dock or float a pane, you drag the pane by its title bar (but don't do this quite yet). As soon as you begin to drag the pane, you will see the look of the Development window change:
|
||||
|
||||
|
||||
[[Image:es gt docking in progress 01|Dragging a pane to dock]]
|
||||
|
||||
Figure 7
|
||||
|
||||
|
||||
In the figure you can see the cursor arrow on the title bar of the pane. The pane has been dragged very slightly and EiffelStudio has sensed that we want to move the pane from its current position. In response, EiffelStudio has overlaid the Development Window with a set of icons that represent valid docking targets for the pane being moved. We'll look closer at those in a moment.
|
||||
|
||||
But for now, notice the large dark, semi-transparent '''docking feedback''' area at the bottom left of the image above. This represents what will happen to your pane if you release the mouse button at the current time. So in the case of the figure above, releasing the mouse button immediately will '''float''' the pane on top of the Development Window. This is nearly our intent, although we want to move the floating pane out to the right of the Development Window. So, without releasing we drag the pane off the top and to the right of the Development Window, then release it.
|
||||
|
||||
|
||||
[[Image:es gt diagram tool pane floating 01|800px|Diagram tool floating]]
|
||||
|
||||
Figure 8
|
||||
|
||||
|
||||
So go ahead and try it now. If you've pinned the pane with the Diagram tool open, then drag the pane by its title bar out to the right and off the Development Window and release it.
|
||||
|
||||
===Docking a pane===
|
||||
|
||||
The problem that some users have when first trying to adjust the tool layout using docking (without the benefit of this Guided Tour) is that once they move a pane, it's not obvious to them what to do next to get the effect that they want. As a consequence, they attempt to put things back the way that they were when they first dragged the pane ... and usually they aren't successful. Remember that you can always press the <code>ESC</code> key to cancel the drag while still holding the mouse button down.
|
||||
|
||||
Now let's take a look at the target graphics and what they mean, and we'll do an exercise in which we put the pane with the Diagram tool back where it was originally.
|
||||
|
||||
In Figure 7 above, you can see the docking target graphics. You see this figure:
|
||||
|
||||
|
||||
[[Image:docking-target|Docking target]]
|
||||
|
||||
Figure 9
|
||||
|
||||
|
||||
in two places, and four smaller figures:
|
||||
|
||||
[[Image:docking-target-top|Top]] [[Image:docking-target-left|Left]] [[Image:docking-target-right|Right]] [[Image:docking-target-bottom|Bottom]]
|
||||
|
||||
Figure 10
|
||||
|
||||
|
||||
one near each border of the Development Window.
|
||||
|
||||
The graphic in Figure 9, shaped like a "plus" sign or cross, will appear in any pane which is a valid docking target for the pane you are moving. So, in Figure 7, those panes are the pane housing the Groups tool and the one housing the Class tool.
|
||||
|
||||
The center of the graphic represents the target pane itself. So, if you drag your pane over the center of the graphic and release it, your pane will now become a new tab in the target pane. You can see the docking feedback area hinting to this effect. In the figure below, the pane with the Diagram tool was dragged over the center of the target graphic on the tool with the Class pane. Notice that the whole pane is covered with the docking feedback area, which even shows the hint of a new tab.
|
||||
|
||||
|
||||
[[Image:es gt add tab to pane|Hovering over center target will add a pane as a new tab]]
|
||||
|
||||
Figure 11
|
||||
|
||||
|
||||
If we were to release the pane at this point, it would dock as a new tab along side Class, Feature, Outputs, and Error List. In this case, the pane we are moving contains only one tool, Diagram, but if it contained multiple tools, each of those tools would become a new tab in the target pane.
|
||||
|
||||
But remember that our goal in this exercise is to restore the pane holding the Diagram tool back to its original position. So, making it a tab in the pane with Class, won't achieve that goal. Let's look at some other possibilities.
|
||||
|
||||
What happens if we drag our pane over one of the tips of the cross shaped target graphic? These targets will allow us to split the target pane into two panes, one containing the original content and the other containing the content of the pane we are moving. The original pane will be split according to which tip of the cross you drop your pane onto. For example dropping on the right tip will split the target pane into left and right panes an put your pane on the right. Again you can see this depicted in a preview when you hover over one of these, as shown below.
|
||||
|
||||
|
||||
[[Image:es gt split pane right|Hovering over the tip of a cross causes the target pane to be split and the new pane added adjacent]]
|
||||
|
||||
Figure 12
|
||||
|
||||
|
||||
It's pretty obvious that this will not get Diagram back to its original location. The only options left unexplained are the four graphics shown in Figure 10. These each look like a detached version of one of the tips of the cross shaped graphic, but they are located along the four edges of the Development Window. If you drop your pane on one of these it will add it as a new pane along the corresponding margin of the Development Window.
|
||||
|
||||
We know that originally our pane with Diagram was in Auto Hide mode at the bottom of the Development Window.
|
||||
|
||||
So, drag the pane from its floating position and drop it at the bottom of the Development window on this graphic:
|
||||
|
||||
[[Image:docking-target-bottom|Bottom]]
|
||||
|
||||
|
||||
The effect is that now your pane has been docked back into the Development Window at the bottom. The only thing left to do now is turn Auto Hide back on by clicking the push-pin icon. Now the pane that houses the Diagram tool is back in its original place in the layout.
|
||||
|
||||
|
||||
===Docking and the Editing pane===
|
||||
|
||||
As we learned earlier in [[#Minimizing, maximizing, restoring, and closing tools|Minimizing, maximizing, restoring, and closing tools]], the pane in which the Editing tools reside has special properties and restrictions not present for panes housing other tools. It's the same for docking. Just as you can't close the Editing pane, you can't re-dock it in any other location. You can't dock other tools, the Feature tool for example, in the Editing pane (notice that you don't get a targeting cross in the Editing pane when you drag a pane).
|
||||
|
||||
Although the Editing pane can house only Editing tools, you ''can'' re-order the tabs for Editing tools and you ''can'' re-dock Editing tools by splitting the Editing pane. For example you might want to look at two classes side by side in two different panes. In the image below, after opening tabs for classes <code>LIST</code> and <code>CHAIN</code>, we dragged the tab for <code>CHAIN</code> and dropped over the right tip of the cross shaped graphic that appeared in the Editing pane. Then we put the pane Groups and the one with Class in Auto Hide to enlarge the size of the Editing tools. This allows us to view <code>LIST</code> and <code>CHAIN</code> side by side.
|
||||
|
||||
|
||||
[[Image:es gt side by side editing|Viewing two classes side by side in the Editing pane]]
|
||||
|
||||
Figure 13
|
||||
|
||||
|
||||
===Docking and toolbars===
|
||||
|
||||
You can drag toolbars and re-dock them in different places. You can float toolbars in the same way you would do a tool pane. In the figure below, the Project toolbar has been dragged away from its default home to the right of the Standard Buttons toolbar. Now it's over undockable space, so if released here it will float, just as we saw with tool panes.
|
||||
|
||||
|
||||
[[Image:es gt redocking project toolbar|Dragging the Project toolbar around]]
|
||||
|
||||
Figure 14
|
||||
|
||||
|
||||
When you move a toolbar, drag it by its "head". The head is indicated by an icon ([[Image:toolbar-head-icon]]) that looks like a vertical row of dots at the left end of each toolbar.
|
||||
|
||||
The figure above shows that there are two "rows" available for placing toolbars. This is the way it is in the default layout. But the number of rows can be expanded if needed. So, if you drag a toolbar toward the bottom of the toolbar area, you will see that a new row will become available in which you can dock the toolbar that you are moving.
|
||||
|
||||
|
||||
[[Image:es gt redocking project toolbar new row|Dragging a toolbar to a new toolbar row]]
|
||||
|
||||
Figure 15
|
||||
|
||||
|
||||
In the figure above, the Project toolbar has been dragged near the bottom of the toolbar area, and a new toolbar row has opened up to allow the Project toolbar to be docked there.
|
||||
|
||||
|
||||
==Customizing toolbars==
|
||||
|
||||
In addition to using the docking facilities to move toolbars around to suit your work style, you can also customize each toolbar by adding, removing, or re-ordering the buttons on that toolbar. See more about this on the page [[Toolbar customization]].
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,127 @@
|
||||
[[Property:title|Debugging and Run-time Monitoring]]
|
||||
[[Property:weight|-2]]
|
||||
[[Property:uuid|a53f6a74-7145-35ab-ed5e-2905aeb88774]]
|
||||
|
||||
The next set of EiffelStudio capabilities enables you to control and monitor the execution of your systems. The obvious immediate application is to debugging; but the more general goal is to let you follow the execution of your systems, explore the object structures, and gain a better understanding of the software.
|
||||
|
||||
|
||||
==A reminder about debugging in Eiffel==
|
||||
|
||||
Before looking at debugging facilities don't forget that debugging in Eiffel is different. The presence of Design by Contract mechanisms gives the debugging process a clear sense of direction. The speed of the recompilation process makes it easy to recompile after a change; after getting rid of syntax and validity errors, you run the system again, and remaining errors are often caught as violations of contract clauses -- routine preconditions, routine postconditions, class invariants.
|
||||
|
||||
The facilities to be described now are also useful when you find such an error, as they will help you study its execution context. In fact, one of the characteristics of the debugging mechanism is that there is no "debugger" proper, no more than there is a "browser"; you have instead a set of facilities supporting controlled execution and debugging. This means for example that:
|
||||
* While debugging, you can access all the browsing capabilities to explore the features and classes surrounding the cause of an error.
|
||||
* While browsing, you can launch or resume execution, and follow its progress through the debugging facilities.
|
||||
* If execution stops on an exception -- for example, an assertion violation or arithmetic overflow -- you have all the environment's facilities at your disposal to understand what happened.
|
||||
|
||||
|
||||
==Setting breakpoints==
|
||||
|
||||
To control the execution you will set breakpoints, indicating places where you want to interrupt the execution. You may set a breakpoint on an individual instruction of a routine, on the routine's precondition or postcondition, or on the routine as a whole, meaning its first operation (precondition or instruction).
|
||||
|
||||
A group of icons on the Project Toolbar help control breakpoints. They are known in EiffelStudio terminology as "''buttonholes''", meaning that they can serve both as buttons (you can click them to get some functions) and holes (you can pick-and-drop into them to get some other functions).
|
||||
|
||||
[[Image:es gt debug buttons|Run and debug buttons]]
|
||||
|
||||
The labels correspond to the icons' use as buttons: enable all set breakpoints ([[Image:16x16--breakpoints-enable-icon]]), disable them all ([[Image:16x16--breakpoints-disable-icon]]), remove them all ([[Image:breakpoints-delete-icon]]), and display information on current breakpoints using the Breakpoints tool ([[Image:debug-show-breakpoints-tool]]). The difference between "disabling" and "removing" is that disabling turns off breakpoints until further notice but remembers them, so that you can later re-enable them, whereas "removing" clears them for good.
|
||||
|
||||
Here you also see icons for controlling execution: '''run''' ([[Image:debug-run-icon]]), '''step-by-step''' ([[Image:debug-step-over-icon]]), '''step into routine''' ([[Image:debug-step-into-icon]]), '''step out of routine''' ([[Image:debug-step-out-icon]]).
|
||||
|
||||
Target a Development Window to the class <code>TESTROOT</code> and pick-and-drop the name of the procedure <code>make</code> (the first routine, after the declaration of the two attributes <code>o1</code> and <code>o2</code>) to the '''Enable all''' icon, used here as a hole. This sets and enables a breakpoint on the routine. Click the button labeled '''Show information about breakpoints''' ([[Image:debug-show-breakpoints-tool]]). This will invoke the '''Breakpoints tool''', as shown in the next figure.
|
||||
|
||||
[[Image:es gt breakpoints tool 01|The Breakpoints tool]]
|
||||
|
||||
This shows that so far you have enabled only one breakpoint. For a finer degree of control, let's look at the feature's flat form. Close the Breakpoints tool, then pick-and-drop <code>make</code> from the Editing Tool to the Feature tool (anywhere in the lower left pane should do; this sets the pane's context to the <code lang=text>Feature</code> Tool. Select the '''Flat''' view if that wasn't the last one used:
|
||||
|
||||
[[Image:es gt development window breakpoints 01|Breakpoint set in "make"]]
|
||||
|
||||
The small circles on the left side of the Flat form indicate breakpoint positions. Empty ones are not set; enabled breakpoints are marked by a circle filled with red. At the moment only one is enabled, corresponding to the first instruction of the routine since, as noted, setting a breakpoint on a routine as a whole means setting it on its first operation.
|
||||
|
||||
By (left) clicking on a breakpoint mark, you toggle it between enabled and not set. You can also right-click on a mark to get a [[Breakpoint menu|menu]] of possibilities:
|
||||
|
||||
[[Image:es gt breakpoint context menu 01|Breakpoint context menu]]
|
||||
|
||||
Try enabling and unsetting a few of these marks; you might get something like this:
|
||||
|
||||
[[Image:es gt development window breakpoints 02|Multiple breakpoints: not set; enabled; set but disabled]]
|
||||
|
||||
The breakpoint mark for the routine's third instruction, <code>create o2</code>, is filled but not red ([[Image:bp-disabled-icon]]); this means it is set but not enabled. You can obtain this by right-clicking on the mark and choosing '''Disable breakpoint''' on the menu that comes up. Any potential breakpoint will be in one of three states: '''not set''' ([[Image:bp-slot-icon]]); '''set and enabled''' ([[Image:bp-enabled-icon]]); '''set but not enabled''' ([[Image:bp-disabled-icon]]).
|
||||
|
||||
Remember, you can see the complete list of enabled and disabled breakpoints by making the Breakpoints tool visible ... which you do by clicking the '''Show information about breakpoints''' ([[Image:debug-show-breakpoints-tool]]) button in the Project Toolbar.
|
||||
|
||||
For the remainder of this chapter it doesn't matter which exact breakpoints of <code>make</code> you've set, as long as the one on its first instruction is set and enabled (red-filled circle) as above. Please make sure this is the case before proceeding.
|
||||
|
||||
|
||||
==Executing with breakpoints==
|
||||
|
||||
To execute, you will use the following Run buttons in the Project toolbar, or the corresponding entries in the '''Execution menu''':
|
||||
|
||||
[[Image:es gt debug buttons|Run and debug buttons]]
|
||||
|
||||
Most of the buttons shown here are enabled, but at different times some of them will be disabled (grayed out.)
|
||||
|
||||
The '''Execution menu''' entries will also remind you of shortcuts: F10 for '''Step-by-step''', F11 for '''Step into routine''', Shift-F11 for '''Step out of routine''', <code>CTRL-F5</code> for '''Run ignoring breakpoints''', F5 for '''Run with breakpoints''', <code>CTRL-Shift-F5</code> for '''Interrupt execution''', Shift-F5 for '''Stop execution'''.
|
||||
|
||||
[[Image:es gt execution menu 01|Execution menu]]
|
||||
|
||||
Start execution of the compiled system by clicking the '''Run''' button ([[Image:debug-run-icon]]). Run actually means "Run and stop at enabled breakpoints." EiffelStudio automatically switches to '''Execution mode''' to accommodate supplementary tools providing debugging information. Execution stops on the breakpoint that you have enabled on the first instruction of procedure <code>make</code>:
|
||||
|
||||
[[Image:es gt debug breakpoint reached 01|Stopped at first breakpoint in "make"]]
|
||||
|
||||
By default, in Execution mode, EiffelStudio looks a little different. Specifically, the Feature tool now occupies the space that was previously held by the Editing tool. The '''Call Stack''' is in the tall pane on the right, and the '''Object tool''' and '''Watch tool''' are on the bottom, under the Feature tool.
|
||||
|
||||
The Call Stack indicates that execution has stopped in <code>make</code>. The Feature tool shows the flat form of that routine, with an icon ([[Image:debug-stopped-on-breakpoint-icon|Stopped on enabled breakpoint]]) to indicate the stop point which execution has reached. The Object tool, which shows the content of current object and (later) related objects. At the moment you can see that:
|
||||
* The current object is an instance of class <code>TESTROOT</code>.
|
||||
* The class (as you could also see from its text in a Development Window) has two attributes <code>o1</code> and <code>o2</code>, both declared as type <code>PARENT</code>, for which the corresponding fields in the current object are both void; this is as expected since you haven't yet executed the two creation instructions <code> create {HEIR} o1</code> and <code>create o2</code>, as they come after the breakpoint.
|
||||
* Along with attributes, an Eiffel class may have '''once functions''', executed at most once -- the first time they are called -- in a given session, and from then on always returning the same value. You can see the status of these by expanding the entry "Once routines" in the Object tool. Here the once function <code>io</code> has not yet been called, but after it has it will return an object of type <code>STD_FILES</code>.
|
||||
|
||||
The execution-time objects that you may display in the Object tool are our latest kind of EiffelStudio "development object", along with classes, features, explanations, clusters; notice the distinctive icon ([[Image:debugger-object-eiffel-icon]]), a rectangular mesh shape suggestive of an object's division into fields. It appears colored for actual objects and gray ([[Image:debugger-object-void-icon]]) for Void references such as <code>operating_environment.</code>
|
||||
|
||||
|
||||
==Monitoring progress==
|
||||
|
||||
Click twice on '''Step-by-step''' ([[Image:debug-step-over-icon]]), or press the function key F10 twice. Monitor, in the flat form of <code>make</code>, the marker that shows execution progress; note that the marker always points to the ''next'' operation to be executed. After the two steps, the Feature and Object tools look like this:
|
||||
|
||||
[[Image:es gt debug step by step 01]]
|
||||
|
||||
The last instruction that you executed is <code>create {HEIR} o1</code>, meaning create an object and attach it to <code>o1</code>, but instead of using the declared type <code>PARENT</code> of <code>o1</code> use its proper descendant <code>HEIR</code>. As a result, the entry for <code>o1</code> in the Object tool no longer shows <code>Void</code> but an object of type <code>HEIR</code>. Note that all objects are identified by their addresses in hexadecimal; such an address is by itself meaningless, but enables you to see quickly whether two object references are attached to the same object. The addresses you see as you run the Guided Tour will -- except for some unlikely coincidence -- be different from the ones appearing here.
|
||||
|
||||
Note that since the garbage collector compacts memory and hence may move objects around, the address of a given object is not guaranteed to remain the same throughout a session.
|
||||
|
||||
To see the details of the object, expand its entry in the Object tool.
|
||||
|
||||
|
||||
==From the instance to the class==
|
||||
|
||||
Now notice what happens if you pick the type name (<code>HEIR</code>) from the entry for object <code>o1</code> in the Object tool, and then drop it in the Feature tool above. The context changes from the Feature tool to the Class tool and is retargeted on <code>HEIR</code>. The Class tool has switched to the default format for classes, '''Ancestors''', and is showing the ancestors of <code>HEIR</code>. Click the Feature tab to get back to feature information for the continuation of our debugging session.
|
||||
|
||||
|
||||
==Stepping into and out of a routine==
|
||||
|
||||
Click '''Step-by-step''' once more to advance just before the call <code>o1.display</code>.
|
||||
|
||||
Choosing '''Step-by-step''' again would execute the next step in the current routine, the call <code>o1.display</code>, treating the entire execution of <code>display</code> from class <code>HEIR</code> as a single operation. Assume instead that you want to go ''into'' that routine and follow the details of its execution. For one thing, you might not know that it's a routine of class <code>HEIR</code>, since <code>o1</code> is declared of type <code>PARENT</code> and it's only through polymorphism, that is, <code>o1</code> being dynamically of type <code>HEIR</code> at this point, and through dynamic binding, that the execution ends up calling a routine from <code>HEIR</code>. Of course here it's obvious because of the wording of the <code>create</code> a few lines up, but in many cases, especially all those for which polymorphism and dynamic binding are ''really'' interesting, the exact type won't be immediately clear from the neighboring software text.
|
||||
|
||||
Click the '''Step into routine''' button (or press F11). This brings execution to the beginning of the appropriate <code>display</code> routine in class <code>HEIR</code>.
|
||||
|
||||
[[Image:es gt debug step into 01]]
|
||||
|
||||
While you're here notice the Call Stack tool. It shows that we are currently executing feature <code>display</code> of class <code>HEIR</code>, which, as can be seen on the second line of the stack, was called from feature <code>make</code> of class <code>TESTROOT</code>.
|
||||
|
||||
Now click '''Step out of routine''' ([[Image:debug-step-out-icon]]), or press Shift-F11 to finish the execution of <code>display</code>. This brings you back to the next instruction of the calling routine, <code>make</code> of <code>TESTROOT</code>.
|
||||
|
||||
|
||||
==Terminating==
|
||||
|
||||
You may now click the '''Stop execution''' button ([[Image:debug-stop-icon]]), or press Shift-F5, to end execution. The execution-specific tools go away and the display returns to what it was before execution.
|
||||
|
||||
|
||||
==Other debugging capabilities==
|
||||
|
||||
In this little application nothing runs long enough to give you the time to interrupt it. In a longer-running application you may want to interrupt execution, <span>without</span> necessarily terminating it, while it's running (not stopped on a breakpoint). This is the purpose of the '''Interrupt execution''' button ([[Image:debug-pause-icon]]), which can also be triggered by pressing <code>CTRL-Shift-F5</code>. It will interrupt execution at the closest potential breakpoint position, letting you -- as when execution stops because of an exception -- take advantage of all the debugging and browsing facilities to see what's going on inside your running system. You may then restart execution -- with or without breakpoints, single-stepping, out of the current routine, into the next routine -- by choosing the appropriate Run button
|
||||
|
||||
In debugging sessions for more advanced applications, you will also find self-explanatory mechanisms enabling you, in addition to what we have seen, to examine all the objects on the "call stack": arguments and local entities of the current routine, its caller, caller's caller and so on.
|
||||
|
||||
The combination of these facilities provides you with a level of ''dynamic'' information on the execution of your system that matches the ''static'' information that the browsing mechanisms studied in preceding sections provide about the system's structure.
|
||||
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
[[Property:title|Executing a System Within and Without EiffelStudio]]
|
||||
[[Property:weight|5]]
|
||||
[[Property:uuid|8256398e-d1a9-0471-664a-3225c7dfb306]]
|
||||
To complete this study of the compilation process let's see a few more properties of how you can <span>execute</span> an Eiffel system, both in EiffelStudio and as a compiled system that you deliver to its users, who may need to run it without EiffelStudio.
|
||||
|
||||
==Arguments==
|
||||
|
||||
Our example system is very simple and has no need for execution arguments. In more advanced cases you may want to pass values to the execution, such as a numeric parameter or a file name, so that you can have different executions without changing and recompiling the software.
|
||||
|
||||
In the Eiffel text, you can access such run-time arguments through the Kernel Library class <code>ARGUMENTS</code>. There is another technique -- using the arguments to the root creation procedure -- but using <code>ARGUMENTS</code> is the most general way. Any class of your system can inherit from <code>ARGUMENTS</code> and use queries <code>argument_count</code> to know the number of arguments passed to the execution, and <code>argument (i)</code>, for <code>i</code> between 1 and <code>argument_count</code> to access the <code>i</code>-th element. Class <code>ARGUMENTS</code> has more features; since you have Eiffelstudio up, you can check the details if you wish (use the contract form).
|
||||
|
||||
There are 2 ways to specify execution arguments from within EiffelStudio. The first is through the menu path <code lang=text>Execution --> Execution Parameters</code> .
|
||||
The second is through the argument dialog which can be opened by right-clicking on any of the debugging or program execution buttons on the main toolbar. The latter is more convenient for quick and easy access to execution arguments.
|
||||
|
||||
==Executing from EiffelStudio==
|
||||
|
||||
We have seen how to execute a compiled system from within EiffelStudio: choose one of the appropriate execution buttons, with or without breakpoints.
|
||||
|
||||
==Executing a finalized system outside of EiffelStudio==
|
||||
|
||||
A finalized system can be executed on any computer of the appropriate platform; it doesn't need EiffelStudio. The executable version is in the directory `project_directory/EIFGENs/target_name/F_code` where `project_directory` is the project's directory and `target_name` is the name of the target. The name of the executable file is `system_name` (or `system_name.exe` on Windows) where `system_name` is the name that you have assigned to your system in the project settings (reflected in the ECF file).
|
||||
|
||||
The target of the Guided Tour system is `classic` and the name is `simple`, so you can locate `simple.exe` (or `simple.exe` on Windows) in `EIFGENs/classic/F_code` for your project, and run it stand-alone if you like.
|
||||
|
||||
If you run the system from a command line, and it requires arguments (`simple` doesn't), you will provide the appropriate arguments after the command name: `system_name ... arg ...` .
|
||||
|
||||
Because various platforms have different conventions, "relative paths" referenced in your system will mean something different under Unix/Linux, where they relate to the directory from which the command is launched, and under Windows, where they relate to the application's directory.
|
||||
|
||||
==Executing a frozen or melted system outside of EiffelStudio==
|
||||
|
||||
A system compiled in "Workbench mode" -- frozen or melted -- is normally meant for execution within EiffelStudio, not for outside delivery, since it is not optimized. If you need to execute it outside of EiffelStudio, make sure that you have access to the <code>system_name.melted</code> file in <code>project_directory</code> <code lang=text>/EIFGENs/target_name/W_code</code>.
|
||||
|
||||
==Moving on==
|
||||
|
||||
With this discussion of compilation and execution we have finished our review of the key capabilities of EiffelStudio. Not everything has been covered, but you are now familiar with the essentials and ready to discover the rest by yourself, both by trying out various capabilities -- most of which should be self-explanatory -- and examining the extensive online documentation that accompanies the product.
|
||||
|
||||
|
||||
@@ -0,0 +1,298 @@
|
||||
[[Property:title|Graphics-based Design]]
|
||||
[[Property:weight|1]]
|
||||
[[Property:uuid|78239225-67a7-8718-857d-f2c8fb70ef18]]
|
||||
So far the project modifications that we have made used the text editor in the Editing Tool. Now let's look at EiffelStudio's ability to provide a graphical depiction of our software system.
|
||||
|
||||
In line with the principles of seamlessness and reversibility recalled at the beginning of this Tour, EiffelStudio's interaction between text and diagram access to software is bi-directional. When you make a textual modification, the next incremental recompilation will update the diagram; but you can also work directly from the diagram, and the text will be generated or updated after each graphical operation.
|
||||
|
||||
Many people like to use the graphical mechanisms at the beginning of a project, to draft the overall structure of a system in "bubbles-and-arrows" style, then concentrate on text as they get closer to implementation. But there is really no such obligation. At any point in the development, just use the form that is more suited to your taste and to your needs of the moment.
|
||||
|
||||
|
||||
==Displaying a cluster view==
|
||||
|
||||
We are going to play with the root cluster. So, we can work from EiffelStudio's default tools layout. Remember that you can reset the tools layout to the default by following the menu path:
|
||||
<code lang="text">
|
||||
View --> Tools Layout --> Reset Tools Layout
|
||||
</code>
|
||||
Now target an Editing tool to the class <code>TESTROOT</code>. So to start out, your Development window should look about like this:
|
||||
|
||||
|
||||
[[Image:es gt graphics based design starting point|A starting point]]
|
||||
|
||||
|
||||
Before getting started, another thing we want to do is to make sure that the the [[Making the context tool independent from the editor|tools are in "Unlinked" mode]]; you can see this by going to the <code>View</code> menu you will see either a menu item '''Unlink Context Tool''' (if tools are currently "Linked") or an item '''Link Context Tool''' (if tools are currently "Unlinked"). So if you see '''Link Context Tool''', you don't have to do anything. But if you see '''Unlink Context Tool''', then select that item to unlink the tools.
|
||||
|
||||
Let's start working with '''cluster views''', showing the content of a cluster. Make the Diagram tool visible: move your cursor over (or click on) [[Image:diagram-tool-tab|Diagram tool]] at the bottom of the Development Window. You may want to float the tool away from the Development Window or "pin" it open (as we learned in the section on [[Customizing the tools layout and toolbars#Docking|docking]], and then maybe enlarge the tool some. You should see a graphical rendition of the <code>root_cluster</code> in the Diagram tool, something like the figure below. In the case that <code>root_cluster</code> is not visible, click the '''Target to class or cluster''' button ([[Image:diagram-target-cluster-or-class-icon]]) on the Diagram tool's toolbar.
|
||||
|
||||
|
||||
[[Image:es gt testroot cluster diagram|root_cluster diagram]]
|
||||
|
||||
|
||||
|
||||
|
||||
==Hiding a class==
|
||||
|
||||
First we might decide that we don't want to be bothered with class <code>INVALID</code>. We could delete it altogether from the system by a pick-and-drop of its bubble to the Delete ([[Image:16x16--general-delete-icon|Delete]]) hole. This is not what we want, but try this now to see the confirmation request:
|
||||
|
||||
|
||||
[[Image:es gt diagram delete confirmation]]
|
||||
|
||||
|
||||
Make sure to answer '''No''' to that confirmation request (you want to keep the class even though it wouldn't be a catastrophe to lose it). Instead pick-and-drop the <code>INVALID</code> bubble into the Hide figure ([[Image:general-reset-icon|Hide figure]]) hole. This time there is no confirmation request, since the operation is reversible -- it just affects what's displayed in the cluster view -- and the class is removed from the display:
|
||||
|
||||
|
||||
[[Image:es gt class invalid is hidden|Class INVALID is hidden]]
|
||||
|
||||
|
||||
You can try '''undoing''' this change ([[Image:general-undo-icon]]), then '''redoing''' it ([[Image:general-redo-icon]]).
|
||||
|
||||
You can also click the '''History''' icon ([[Image:general-undo-history-icon]]) which, during the rest of the session, will display the list of executed operations, and let you undo or redo many operations at once by clicking the oldest to be kept or the youngest to be redone.
|
||||
|
||||
For the rest of this discussion we assume <code>INVALID</code> is hidden.
|
||||
|
||||
|
||||
==Adding a class==
|
||||
|
||||
We are now going to add a class graphically to our system. This means you don't have to worry about creating and initializing a file; EiffelStudio will take care of the details.
|
||||
|
||||
The useful button here is '''Create new class''':
|
||||
|
||||
[[Image:es gt create new class button|Create a new class]]
|
||||
|
||||
When you click this button you'll see the '''Add New Class''' dialog box:
|
||||
|
||||
|
||||
[[Image:es gt new class dialog]]
|
||||
|
||||
|
||||
Overwrite the default class name being proposed by the name <code>HEIR2</code>, as we are going to create a new heir of <code>PARENT</code>. Now click the button labeled '''Create'''.
|
||||
|
||||
The new class is created and added to the diagram as part of <code>root_cluster</code>:
|
||||
|
||||
|
||||
[[Image:es gt class heir2 created|Class HEIR2 created]]
|
||||
|
||||
|
||||
Using conventional drag-and-drop (not pick-and-drop), move the class bubbles for <code>HEIR2</code>, <code>TESTROOT</code> and <code>PARENT</code> so that the display looks approximately like the following. The double circle around <code>TESTROOT</code> is the [[Notation|BON]] (Business Object Notation) convention to identify a system's root class.
|
||||
|
||||
|
||||
[[Image:es gt class heir2 relocated|Classes rearranged]]
|
||||
|
||||
|
||||
==Adding an inheritance link==
|
||||
|
||||
Now we are going to make <code>HEIR2</code> an heir of <code>PARENT</code>. To create relationship links between classes you pick-and-drop from the source class, but don't do that yet. First we have to specify that we want an inheritance relationship.
|
||||
|
||||
By default, the new relationship '''Creation Mode''' will be client/supplier ([[Image:diagram-new-supplier-link-icon]]). To change the creation mode to inheritance, click on the selection triangle next to the new client/supplier link icon, and choose '''Conforming inheritance Creation Mode ...''' from the drop-down menu, as shown below.
|
||||
|
||||
|
||||
[[Image:es gt select conforming inheritance link creation mode|Selecting Conforming Inheritance Creation Mode]]
|
||||
|
||||
|
||||
Notice that the current Creation Mode icon has changed to indicate conforming inheritance ([[Image:diagram-new-conforming-inheritance-link-icon]]).
|
||||
|
||||
Now pick-and-drop from the <code>HEIR2</code> bubble to the <code>PARENT</code> bubble. (Now you see why conventional drag-and-drop is used to move bubbles: pick-and-drop on the diagram serves to add links between classes).
|
||||
|
||||
[[Image:es gt class heir2 inheriting parent|HEIR2 now inherits from PARENT]]
|
||||
|
||||
To convince yourself that the new class has been made an heir of <code>PARENT</code>, not just in the diagram, but in its text as well, you can look at the class in an Editing tool. Unless you are so fortunate as to have plenty of monitor space, you may have to un-pin the Diagram tool to be able to see the Editing pane. Pick-and-drop <code>HEIR2</code> bubble to the Editing tool to see its text.
|
||||
|
||||
|
||||
[[Image:es gt class heir2 text|Class HEIR2 in an Editing tool]]
|
||||
|
||||
|
||||
The code for a minimal class <code>HEIR2</code> has been generated from your graphical operations: creating the class produced a class template, and the creation of the new inheritance link made <code>HEIR2</code> inherit from <code>PARENT</code>.
|
||||
|
||||
In a moment we'll use this Editing Tool to see how, conversely, EiffelStudio will automatically reflect in the diagram a change made to the text.
|
||||
|
||||
For now, make sure the Diagram tool is visible again.
|
||||
|
||||
|
||||
==Adding a client link==
|
||||
|
||||
Next let's make <code>TESTROOT</code> a client of <code>HEIR2</code>.
|
||||
|
||||
First, re-select ''Client-Supplier''' as the Creation Mode for new links.
|
||||
|
||||
Pick-and-drop from the <code>TESTROOT</code> bubble to the <code>HEIR2</code> bubble. This causes the '''New Feature''' dialog box to appear:
|
||||
|
||||
|
||||
[[Image:es gt new feature dialog|The New Feature dialog box]]
|
||||
|
||||
|
||||
This technique gives you many option and in fact is a convenient way to build your classes, whether at the analysis, design or implementation level. Here, fill the fields as follows. For the top choice, keep the default, <code lang=text>Attribute</code>; we'll give class <code>TESTROOT</code> an attribute of type <code>HEIR2</code>. For its feature category, keep the choice currently displayed, <code>Access</code>. For its name, replace the default, by the name <code>o3</code>. In the '''invariant''' box, choose
|
||||
<code>
|
||||
o3_not_void: o3 /= Void
|
||||
</code>
|
||||
|
||||
from the list to specify the invariant property that this attribute should never be void. Finally, to see how EiffelStudio can generate the full accompaniment to an attribute, in the box '''Setter?''' choose
|
||||
<code>
|
||||
set_o3
|
||||
</code>
|
||||
|
||||
This will create a routine with this name which clients can use to set the value of <code>o3</code>.
|
||||
|
||||
You may have noticed that the checkbox labeled '''Assigner?''' became enabled when you chose a name for the '''Setter'''. This will make the setter routine be called if a client uses an assignment of the form:
|
||||
<code>
|
||||
my_testroot.o3 := some_value
|
||||
</code>
|
||||
|
||||
The assigner makes this is a syntactical shortcut for writing:
|
||||
<code>
|
||||
my_testroot.set_o3 (some_value)
|
||||
</code>
|
||||
|
||||
Without the assigner, the direct assignment by a client would result in a syntax error, because in Eiffel clients are prohibited from assigning directly to their suppliers' attributes.
|
||||
|
||||
So, check the '''Assigner?''' box.
|
||||
|
||||
Now, click '''OK'''.
|
||||
|
||||
The diagram now shows that <code>TESTROOT</code> is a client of <code>HEIR2</code>.
|
||||
|
||||
|
||||
[[Image:es gt testroot is client of heir2|TESTROOT is now a client of HEIR2]]
|
||||
|
||||
|
||||
Now, if you'd like, you can check the text of <code>TESTROOT</code> as we did earlier with <code>HEIR2</code>, but here are the highlights:
|
||||
|
||||
You'll notice that the attribute <code>o3</code> has been added under the feature category "Access":
|
||||
|
||||
<code>
|
||||
feature -- Access
|
||||
|
||||
o3: HEIR2 assign set_o3
|
||||
-- `o3'
|
||||
attribute Result := ({like o3}).default end --| Remove line when attached attribute is correctly assigned
|
||||
</code>
|
||||
|
||||
After the attribute declaration the keyword <code>assign</code> declares that the feature <code>set_o3</code> is to be called when assignments are made to <code>o3</code> by clients.
|
||||
|
||||
You see that the header comment is trivial ( <code>-- `o3'</code> ), simply echoing the feature name. This is because we failed in our duty to fill in a reasonable header comment in the New Feature dialog. Every feature should have a meaningful header comment.
|
||||
|
||||
Now notice the last line, beginning with the keyword <code>attribute</code>. This line is intended to be temporary. It makes your new attribute <code>o3</code> a [[Void-safety: Background, definition, and tools#Self-initializing attributes|self-initializing attribute]], which just allows you to avoid certain errors until you insert code to initialize <code>o3</code> properly.
|
||||
|
||||
The "setter" routine for <code>o3</code> is generated and categorized as "Element change":
|
||||
|
||||
<code>
|
||||
feature -- Element change
|
||||
|
||||
set_o3 (an_o3: like o3)
|
||||
-- Assign `o3' with `an_o3'.
|
||||
require
|
||||
an_o3_not_void: an_o3 /= Void
|
||||
do
|
||||
o3 := an_o3
|
||||
ensure
|
||||
o3_assigned: o3 = an_o3
|
||||
end
|
||||
</code>
|
||||
|
||||
Notice that EiffelStudio has included both a precondition and postcondition for <code>set_o3</code>.
|
||||
|
||||
Also, a clause has been added to the class invariant to ensure that <code>set_o3</code> is not void:
|
||||
|
||||
<code>
|
||||
o3_not_void: o3 /= Void
|
||||
</code>
|
||||
|
||||
The situation here is different from what we saw earlier with <code>HEIR2</code>, which had been generated from scratch by the diagram. Here <code>TESTROOT</code> existed before, in text form; so the diagram mechanisms have had to preserve the existing feature and feature clauses, and add the elements corresponding to what you have specified through the diagram mechanisms. The unlabeled Feature clause of the existing class has been kept; the new features have been entered into clauses labeled <code>Access</code> and <code>Element change</code>, observing the Eiffel standard for common feature clauses in libraries.
|
||||
|
||||
|
||||
==Updating the diagram from the text==
|
||||
|
||||
In this tour of the diagram facilities we have, so far, worked on the diagram and seen the text updated immediately. Of course we want full reversibility. So let's make a change in the text and check the diagram.
|
||||
|
||||
The change will be very simple. We'll make <code>TESTROOT</code> a client of <code>HEIR</code>. In the Editing tool, add an attribute declaration
|
||||
<code>
|
||||
other: HEIR
|
||||
</code>
|
||||
|
||||
Now save the file by clicking the [[Image:16x16--general-save-icon|save]] icon.
|
||||
|
||||
Nothing happens yet to the diagram. This is normal: EiffelStudio doesn't update the diagram every time you type some text (which, for one thing, might be syntactically incorrect, or invalid). You need to recompile first. Click the [[Image:compile-button]] button. Then the new relation appears:
|
||||
|
||||
|
||||
[[Image:es gt testroot is client of heir|Now TESTROOT is a client of HEIR]]
|
||||
|
||||
|
||||
If the label <code>other</code> of that relation doesn't appear in the exact place shown here, try moving it using conventional drag-and-drop. You can only move such a link label within a small area on either side of the link.
|
||||
|
||||
|
||||
==Creating a cluster==
|
||||
|
||||
Earlier on, we saw how to create a class from the EiffelStudio diagram, letting EiffelStudio take care of creating and initializing the file. Similarly, you can create a new cluster graphically, and let EiffelStudio create the corresponding directory.
|
||||
|
||||
To create a cluster, you can go through [[EiffelStudio: Project settings window|Project settings]], or you can do so directly from the Groups tool. Let's use the Groups tool. On the title bar of the Groups tool, you'll find the '''Add a cluster''' button ([[Image:new-cluster-icon]]). (You may have to expand the titlebar menu through its double chevron placeholder >>).
|
||||
|
||||
The resulting dialog asks you for the cluster name, and the existing cluster (non-precompiled) of which you want to make it a subcluster, here leaving only one choice:
|
||||
|
||||
[[Image:es gt add cluster dialog]]
|
||||
|
||||
Instead of the default name, type <code>my_cluster</code>; select the only possible supercluster, <code>root_cluster</code>, and click '''Create''' at the bottom of the dialog.
|
||||
|
||||
Now the diagram shows the new subcluster:
|
||||
|
||||
|
||||
[[Image:es gt new cluster added|A new cluster has been added]]
|
||||
|
||||
|
||||
Try to make your display look approximately like the above; you will probably have to move (drag from the center) and/or resize (drag from a corner) either or both clusters.
|
||||
|
||||
|
||||
==Moving a class to a different cluster==
|
||||
|
||||
Among the many operations you can do graphically is to move a class from one cluster to another. Pick-and-drop the <code>HEIR2</code> class bubble to the rounded rectangle for <code>MY_CLUSTER</code>.
|
||||
|
||||
This graphical manipulation has caused a structural change: class <code>HEIR2</code> is now part of <code>MY_CLUSTER</code>. Check this by expanding the Cluster Tree on the left:
|
||||
|
||||
[[Image:es gt class HEIR2 moved to new cluster|Class HEIR2 has been moved to my_cluster.]]
|
||||
|
||||
If you like, you can also look into the project directory -- using the Windows Explorer, or <code>cd</code> and <code>ls</code> on Unix/Linux -- and check that it now has a subdirectory <code>my_cluster</code> with a file <code>heir2.e</code> containing the text of class <code>HEIR2</code>.
|
||||
|
||||
Clearly, it's much more convenient to use EiffelStudio for such manipulations than to move files around manually.
|
||||
|
||||
|
||||
==Adjusting the display==
|
||||
|
||||
A number of buttons enable you to customize the display. So far all class bubbles had the same default color. Try pick-and-dropping a bubble into the '''Color hole''' ([[Image:diagram-choose-color-icon]]) to get a color palette that enables you to select a different color. This is useful if you want to highlight classes possessing certain properties, for example classes that are part of a certain Design Pattern.
|
||||
|
||||
'''Relation depth''' ([[Image:diagram-depth-of-relations-icon]]) enables you to select the depth at which inter-class relations will be displayed. (Don't change this setting now.) '''Include all classes of cluster''' ([[Image:diagram-fill-cluster-icon]]) is more useful for class diagrams than for the cluster diagram we have now, which by default included all classes of the cluster; if you click it here it will add the class <code>INVALID</code> that you removed earlier. There is no need to do this now.
|
||||
|
||||
|
||||
==Views==
|
||||
|
||||
So far the top-right '''View''' field has always shown '''DEFAULT:BON'''. You can define any number of views in your project, and apply them to various class and cluster diagrams.
|
||||
|
||||
For example, using the buttons to show and hide links of various kinds you can produce diagrams that only show the inheritance links, and others that only show the client links. If you want to keep both kinds of diagram, simply define views by typing view names -- such as '''Inheritance''', '''Client''', '''All_links''' -- into the '''View''' field.
|
||||
|
||||
You can also use views to retain some of the choices seen just before, such as different colors and depths.
|
||||
|
||||
To load a previously defined view, just use the menu associated with the '''View''' field.
|
||||
|
||||
You may remember that when we generated HTML documentation, the dialog asked you to select a view among the available ones. You can choose a different view for each cluster.
|
||||
|
||||
You may have guessed that the '''BON''' in '''DEFAULT:BON''' means that the diagram view is in Business Object Notation. You can also view diagrams in UML-style notation. To do this you would click the '''Show UML''' button ([[Image:diagram-view-uml-icon]]). Click it again to return to the BON view.
|
||||
|
||||
|
||||
==Class diagrams, cluster diagrams==
|
||||
|
||||
In the present discussion we have used cluster diagrams. Both are interesting. To obtain a class diagram, you will target a Class tool to a class, and select the Diagram tool. By default, this shows the parents of the class. Do this now for <code>TESTROOT</code>.
|
||||
|
||||
{{note|Because at the beginning of this page, we put the EiffelStudio context tools in "unlinked" mode, it may be necessary to synchronize the context to see the class diagram. You can do this by clicking '''Synchronize context''' ([[Image:context-sync-icon]]) in the main toolbar. }}
|
||||
|
||||
|
||||
[[Image:es gt testroot class diagram]]
|
||||
|
||||
|
||||
It's for class diagrams that the '''Relation depth''' ([[Image:diagram-depth-of-relations-icon]]) button is most interesting. It will let you select the exact depth that you wish displayed for each relation type:
|
||||
|
||||
|
||||
[[Image:es gt relation depth dialog]]
|
||||
|
||||
|
||||
|
||||
This will conclude our review of the Diagram facilities of EiffelStudio, although you'll surely discover some further riches by yourself and through the rest of the documentation. We hope the complete seamlessness between text and pictures will enable you to increase the effectiveness of your analysis work, or your design work, or your programming -- whatever level of system development you need to tackle.
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
[[Property:title|Handling Syntax and Validity Errors]]
|
||||
[[Property:weight|-3]]
|
||||
[[Property:uuid|c2be8123-b793-f8ce-e082-d4fdacc6bbe6]]
|
||||
So far we have tried to make sure that everything went smoothly. But in actual software development you may encounter error situations, and it is useful to know what can happen then.
|
||||
|
||||
|
||||
==Levels of language description==
|
||||
|
||||
Let's remind ourselves first of how the language is specified. The [[ECMA Standard 367|ISO/ECMA Eiffel standard]] and the book [[Eiffel: The Language]] carefully distinguish between three levels of description: '''syntax''', '''validity''' and '''semantics'''. Their roles are clearly distinct:
|
||||
* <span>Syntax</span> defines the structure of software texts. A typical syntax rule states that an assignment starts with a <code>Writable</code> entity, continues with the symbol <code>:=</code>, and ends with an <code>Expression</code>. This is a purely structural specification, saying nothing for example about the types of the <code>Writable</code> and the <code>Expression</code>.
|
||||
* <span>Validity</span>, applicable only to syntactically legal texts, defines required consistency conditions. A typical validity rule states that in an assignment the right-hand-side <code>Expression</code> must <span>conform</span> -- a property of its type, defined rigorously on the basis of inheritance -- to the left-hand-side <code>Writable</code>. Eiffel has about 75 validity rules; part of the language's originality is that these rules are of the "<span>if and only if</span>" form, not only telling you individual error cases ("this is valid <span>only if</span> <span>...</span> ") but also reassuring you that your text will in fact be valid <span>if</span> it satisfies the conditions listed exhaustively.
|
||||
* Semantics, applicable only to valid texts, defines the software's expected run-time behavior. A typical semantic rule states that an assignment replaces the value of its left-hand-side <code>Writable</code> by the value of the right-hand-side <code>Expression</code> at the time the assignment is executed, with precise rules on the different possible cases involving references, objects and simple values.
|
||||
|
||||
You may make an error at any of these levels:
|
||||
* Writing <code>=</code> instead of <code>:=</code> for the assignment symbol is a syntax error.
|
||||
* Writing <code>your_integer := your_real</code>, with the types suggested by the names, is a validity error.
|
||||
* Violating a precondition, causing a division by zero, are semantic errors.
|
||||
|
||||
Syntax and validity errors will be detected by the compilation process. For semantic errors, you will rely on contract checking and on the debugging tools described later. Let's look now at examples of the first two cases.
|
||||
|
||||
|
||||
==A syntax error==
|
||||
|
||||
To see what happens for a syntax error, replace the keyword <code>do</code> by <code>dont</code> in the routine <code>display</code> of class <code>PARENT</code> (click the position immediately after the <code>o</code> and type <code>nt</code>.). Save the file by clicking the Save button or using <code>CTRL-S</code> and then compile the system.
|
||||
|
||||
[[Image:es gt development window syntax error 01|Purposely injected syntax error]]
|
||||
|
||||
The error shows up in the [[Error List Tool|Error List tool]]. You can expand the entry to show the point at which the error was recognized by the compiler.
|
||||
|
||||
To correct the error, just bring the mouse back to its location, remove the spurious <code>nt</code>, and click Save again; also click Compile to make sure that the project is recompiled up-to-date.
|
||||
|
||||
You may wonder why the syntax error messages are not a little more verbose than just <code>Syntax error</code>. The reason is merely that Eiffel's syntax, being simple and regular, does not require sophisticated error messages; syntax errors usually result from trivial oversights. If you make a syntax error and the reason is not immediately clear, check the syntax summary in the [[Quick reference to the Eiffel programming language]] or the [[ECMA Standard 367|ISO/ECMA Eiffel Standard]].
|
||||
|
||||
|
||||
==A validity error==
|
||||
|
||||
A validity error is a violation of one of the validity constraints given in [[ECMA Standard 367|ISO/ECMA Eiffel Standard]]. Every such constraint is identified by a four-letter code of the form <code>VXXX</code> (the first letter is always <code>V</code>).
|
||||
|
||||
A validity error will produce a precise error message, which includes the validity code. Although short, the error message is usually sufficient to find out what the error is. If not, you can get the complete rule, straight from the book.
|
||||
|
||||
To see this mechanism at work, let us introduce a validity error. There is in fact one ready for you in class <code>TESTROOT</code>. Target a Development Window to this class; at the end of its text, just before the final <code>end</code>, you will find the following comment line:
|
||||
<code>
|
||||
-- inv: INVALID;</code>
|
||||
|
||||
If uncommented, this is a declaration of a feature of type <code>INVALID</code>. A class called <code>INVALID</code> indeed exists in file <code>invalid.e</code> of the root cluster, but it contains a validity error. To see what it is, remove the initial double-hyphen <code>--</code> in the above line from class <code>TESTROOT</code> so that it is not a comment any more.
|
||||
|
||||
[[Image:es gt development window validity error 01|inv: INVALID uncommented]]
|
||||
|
||||
Click <code>Save</code>, then <code>Compile</code>. Compilation starts but after a few degrees it stops with an error message that appears in the Error List tool. Expand the entry and perhaps do some resizing to see it in its entirety:
|
||||
|
||||
[[Image:es gt development window validity error 02|Validity error]]
|
||||
|
||||
As the error message indicates, you have (shame on you) violated the validity rule <code>VUAR</code>, which requires the number and types of actual arguments in a routine call to match the number and types of formal arguments declared in the routine.
|
||||
|
||||
One of the interesting properties of the error message is that everything in color is '''clickable''': class name, feature name, but also the error code. This means that you can start a Pick-and-Drop on any of these elements to find out more.
|
||||
|
||||
For example, to see the exact context of the error, pick-and-drop the name of the affected feature, <code>display</code> -- appearing in green on the fifth non-blank line -- and pick-and-drop it to the Editing tool. This displays the erroneous feature:
|
||||
|
||||
[[Image:es gt development window validity error 03|Validity error exposed]]
|
||||
|
||||
Note on this display a special property of Pick-and-Drop when its source is a feature name appearing in a validity error message: the instruction that causes the error is highlighted.
|
||||
|
||||
In the error message in the Error List tool, the error code itself, <code>VUAR</code>, is also clickable. Assuming the message was not sufficient to understand the error, you can use it to start a Pick-and-Drop. Do this now, by picking that code and starting to move the mouse, but not dropping yet. The pebble shape for such information elements is a question mark <code>?</code> enclosed in a small gold talk bubble ([[Image:error-cursor]]). Like other picked objects, when it is not over a droppable target, the pebble will be crossed in red ([[Image:error-cursor-disabled]]). The place to drop is the Explanation hole ([[Image:error-info]]) in the Error List toolbar:
|
||||
|
||||
[[Image:es gt error list tool pnd validity error|Dropping a validity error pebble]]
|
||||
|
||||
When you drop the pebble, you'll see the Compilation Error Wizard appear:
|
||||
|
||||
[[Image:es gt compilation error wizard 01]]
|
||||
|
||||
The wizard displays the complete text of the violated rule. Depending upon the particular violation, the rule will come straight from the pages of either [[Eiffel: The Language]] or the [[ECMA Standard 367|ISO/ECMA Eiffel standard]]. In this case, the <code>VUAR</code> rule definition used comes from Chapter 22, page 369 of [[Eiffel: The Language]]. An rule cited from the ISO/ECMA Eiffel standard will be state as such and will include the specific edition of the standard and the section number, for example:
|
||||
<code lang="text">
|
||||
VEVI, ECMA-367, 2nd edition, section 8.19.17
|
||||
</code>
|
||||
|
||||
The <code>VUAR</code> rule that we violated has two clauses, numbered. Since the error message showed the error code as <code lang=text>VUAR(1)</code>, the violated clause is the first; this convention of showing the clause number in parentheses applies to all multi-clause validity constraints.
|
||||
|
||||
To correct the error the easiest is to go back to class <code>TESTROOT</code> and reinstate the comment symbol <code>--</code> (two consecutive hyphens) on the erroneous line. Save and compile to continue with a valid system.
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,214 @@
|
||||
[[Property:title|How EiffelStudio Compiles]]
|
||||
[[Property:weight|3]]
|
||||
[[Property:uuid|6fc86303-8afe-78af-6ca7-2853e8bfcbc3]]
|
||||
So far we have relied on the compiling capabilities of EiffelStudio without exploring them in any detail. We must now understand the principles behind EiffelStudio's compiling strategy, in particular how it reconciles fast turnaround, efficient generated code, and strong typing.
|
||||
|
||||
|
||||
==Compilation is automatic==
|
||||
|
||||
Any speed issue aside, the most important property of the compilation process is that it is entirely automatic.
|
||||
|
||||
You've seen it from the beginning of this Tour: all the information the compiler has -- obtained from a configuration file, as here, or generated automatically by the other options -- is the name of the root class and the list of directories holding Eiffel clusters. In fact it only needs these directories for non-precompiled clusters; here, because we are using precompiled EiffelBase, and because we've started EiffelStudio from the Tour's own root cluster directory, EiffelStudio has all the information it needs.
|
||||
|
||||
The compiler takes care of finding all the classes that must be compiled.
|
||||
|
||||
There is never any need, when compiling Eiffel systems, to supply "Make files", "include files", or other manual descriptions of inter-module dependencies.
|
||||
|
||||
|
||||
==Compilation modes==
|
||||
|
||||
EiffelStudio offers several forms of compilation, which you can see in the entries of the <code>Compile</code> menu (don't trigger any of them right now) as well as keyboard shortcuts and, in some cases, buttons:
|
||||
* '''Melt''': quick incremental recompilation, doesn't optimize code for changed parts.
|
||||
* '''Freeze''': incremental recompilation, not as fast as Melt, but generates more efficient code for changed parts.
|
||||
* '''Finalize''': recompile entire system, generating highly optimized code.
|
||||
* '''Precompile''' (available both in the <code>Project</code> menu and through <code lang=text>Tools --> Precompilation wizard</code>), to process an entire library, on which many systems can then rely without having to compile it.
|
||||
|
||||
You'll quickly learn to use each of these modes to suit your needs.
|
||||
|
||||
|
||||
==Criteria==
|
||||
|
||||
EiffelStudio's '''Melting Ice Technology''' reconciles the following goals:
|
||||
* ''Security and efficiency of the generated code'': compiling techniques for the strongly typed Eiffel programming language ensure that compilers can catch many errors before it is too late, and generate more efficient code. The "validity constraints" of the language, whose violations are caught as compilation errors, are particularly useful here, playing the role of enforceable design rules.
|
||||
* ''Quick turnaround '': you should experience an almost immediate transition from the time you write or (more commonly) modify software to the time you can execute it.
|
||||
* ''C code generation'': for portability, it is useful to take advantage of C in its proper role, that of a portable assembly language. C's closeness to machine concepts -- one of the very properties making it less suitable for human programming except in the case of short routines to access low-level mechanisms --, its almost universal availability, and its good level of standardization, make it an excellent target language for a code generator. This also enables the environment to benefit from the often extensive optimizations performed by good C compilers, and facilitates interfacing new software with the large body of existing C-based systems, tools and libraries. As the final output of Eiffel compilation, you can obtain a complete C package that you can either C-compile on the same machine or port to other platforms, making EiffelStudio a tool of choice for '''cross-platform development''': develop on one platform, deploy on one or more others.
|
||||
|
||||
|
||||
==The Melting Ice Principle==
|
||||
|
||||
The idea of the melting ice is based on the observation that, for the practicing software developer, the crucial day-to-day compilation problem is not how to process an entire system but how best to process a '''changed system''', of which an earlier state had previously been processed.
|
||||
|
||||
The change may be big or small; the system may be big or small. ("Small system" here means up to a few tens of thousands of lines.) This gives four possible cases, of which only one is really critical:
|
||||
|
||||
|
||||
{| border="1"
|
||||
|-
|
||||
|
|
||||
| '''Small System'''
|
||||
| '''Large System'''
|
||||
|-
|
||||
| Small Change
|
||||
|
|
||||
| xxx
|
||||
|-
|
||||
| Big Change
|
||||
|
|
||||
|
|
||||
|}
|
||||
|
||||
|
||||
If the system is small, as in both of the left column entries, speed of recompilation with a good compiler will be acceptable.
|
||||
|
||||
In the bottom-right box, the developers have spent days or weeks changing many classes in a large system, so they will not resent having to wait a little to see the results of the recompilation, as long as the time remains reasonable. In EiffelStudio this corresponds, as we'll see shortly, to ''finalization'', which is in fact fairly fast anyway, but not as fast as the incremental modes.
|
||||
|
||||
In the day-to-day, minute-by-minute practice of building and modifying software, the case that recurs by far the most often -- and can cause most frustration -- is the one marked xxx: you change only a small share of a big system. Then the result should come quickly enough. More precisely:
|
||||
|
||||
{{definition|Melting Ice Principle|The time to re-process a system after a change should be a function of the logical size of the change, not of the size of the system. }}
|
||||
|
||||
''The "logical size" of a change may be different from its physical size because a small physical change in a class may have consequences in many others. Imagine for example that you add a feature to class '' <code>ANY</code>'', although this is an extreme case and won't normally happen. Since every class is a descendant of '' <code>ANY</code>'', the logical change may affect the entire system.''
|
||||
|
||||
''In practice, however, most small physical changes will also be small logical changes and will only cause minimal recompilation. In particular, EiffelStudio will detect that a change does not affect the interface of a class -- for example if it's only a change to non-exported features -- avoiding the need to re-process its clients.''
|
||||
|
||||
Processing such incremental changes, in time proportional to the logical size of the changes, is known in EiffelStudio as '''melting'''. The reason for this terminology is the metaphor illustrated on the following figure. Think of a compiled system as a block of ice; it may have taken some time to "freeze" -- compile. Now you start working on it again; the changes are like melted drops of water, dripping from the ice as a result of the heat generated by your work.
|
||||
|
||||
[[Image:index-140]]
|
||||
|
||||
The Melting Ice Technology ensures that incremental compilation will only process the "melted" part, usually small, leaving alone the "frozen" part, which may be large. This is crucial to the incrementality of the mechanism.
|
||||
|
||||
The roles of the four compilation modes follow from this analysis:
|
||||
* '''Melting''' is the fastest mode: it processes the melted part without affecting the frozen part. With EiffelStudio, the melted elements will be ''interpreted'' while the rest is compiled.
|
||||
* '''Freezing''' is the process of putting back the melted parts into the "freezer": bringing them to the same compiled state as the parts that have not been modified.
|
||||
* '''Finalizing''' is the non-incremental process of producing a stand-alone C package and the resulting executable, extensively optimized, from the current system.
|
||||
* '''Precompiling''' is the process of compiling an entire set of reusable classes, once and for all, so that it can be shared by many systems and many users without duplicating the code or compiling it again for each project.
|
||||
|
||||
|
||||
==Properties of the compilation modes==
|
||||
|
||||
The following table summarizes the differences between the four compilation modes:
|
||||
|
||||
|
||||
{| border="1"
|
||||
|-
|
||||
|
|
||||
| '''Regenerate C Code?'''
|
||||
| '''Incremental?'''
|
||||
| '''Compilation result shared between projects?'''
|
||||
|-
|
||||
| '''Melt'''
|
||||
| No
|
||||
| Yes (fast)
|
||||
| No
|
||||
|-
|
||||
| '''Freeze'''
|
||||
| Yes
|
||||
| Yes (but requires C compilation of changes and linking)
|
||||
| No
|
||||
|-
|
||||
| '''Finalize'''
|
||||
| Yes
|
||||
| No
|
||||
| No
|
||||
|-
|
||||
|
||||
|
||||
| '''Precompile'''
|
||||
|
||||
|
||||
| Yes
|
||||
| No
|
||||
| Yes
|
||||
|}
|
||||
|
||||
|
||||
During the production and modification of your software, you will usually alternate between melting and freezing, since both of these modes are incremental. Most of the time, you will simply '''melt''', since melting satisfies the Melting Ice Principle: the time to get back to a working system is very short -- proportional to the size of the changes. Note in particular that the unit of melting is the smallest possible one: each feature of a class -- attribute or routine -- may be melted separately.
|
||||
|
||||
The main difference between melting and '''freezing''' is that freezing implies re-generating C code for the changed elements, and hence relinking the system as well. In contrast, when you melt changes, you do not change any C code: it remains frozen.
|
||||
|
||||
As a consequence, melting can only process changes to Eiffel code. If you add new external code (in C, C++ or other languages whose modules will require linking), you must freeze. This is also true if you add new Eiffel agents. If you ask for a Melt in such cases, the operation will trigger a freeze anyway. More generally, the <code>Compile</code> button, which you have used a number of times to recompile the system in this Tour, triggers a Melt by default, and a Freeze when it has to.
|
||||
|
||||
EiffelStudio knows how to hide the differences and present you with a uniform view of the frozen parts (the C code) and the melted parts. Here indeed is the full view of the picture that was previously given in part:
|
||||
|
||||
[[Image:index-141]]
|
||||
|
||||
When you examine a component of the system -- to edit a class, produce a view such as Contract or Interface, enable a breakpoint on a routine, run the system, inspect a run-time object -- EiffelStudio automatically knows where to look for the corresponding information: melted or frozen part. If one of your actions requires melting or freezing more elements, EiffelStudio will also handle this automatically.
|
||||
|
||||
As suggested by the lower red arrow, successive melting operations "pour water into the bowl", corresponding to the elements that you have changed since the last freeze. Freezing, represented by the top red arrow, updates the C code so that it integrates all the latest changes, emptying the bowl in the process.
|
||||
|
||||
Because the difference between melted and frozen code is largely invisible to users of the environment, the term '''workbench code''' will cover both kinds; workbench code is code resulting from a succession of freezing and melting operations. As long as you are working within EiffelStudio, you are using workbench code.
|
||||
|
||||
When you are happy with the results of your development, you will normally finalize the system, thereby generating '''final code'''. Although not strictly required, this step is in most cases appropriate since final code is significantly more efficient than workbench code in both time and space: finalization performs a number of optimizations -- dead code removal, replacement of dynamic by static binding -- that wouldn't be justified in incremental development where, for example, some code element that is "dead" one minute may be resurrected the next moment through the addition of just one line of text. In addition, because finalized code is more efficient than frozen code, it is the natural choice if, using EiffelStudio for cross-platform development, you wish to port the resulting C-package to other architectures.
|
||||
|
||||
If you have a set of reusable classes that may be useful to many applications, you can '''precompile them''' into a library. This set of classes must be ''self-contained'' in the sense that all the classes needed by any of them must be either in the library itself or in another library that you will include in the precompilation.
|
||||
|
||||
|
||||
==Bytecode==
|
||||
|
||||
The result of melting operations -- the contents of the "bowl" -- is an internal software representation known as melted code or (for no particularly good reason) as ''bytecode''. EiffelStudio generated bytecode serves two complementary purposes:
|
||||
* It can be executed directly. This is what happens during melting: while the rest of your system, the frozen part, is executed in the form produced by Eiffel compilation generation and C-compilation of the result, the melted part is interpreted "as is" without further translation.
|
||||
* It can be compiled into C for further processing.
|
||||
|
||||
Internally, the melted code is in a file <code>simple</code>.<code>melted</code> (where <code>simple</code> is our project's name) in the subdirectory <code>EIFGENs/simple/W_CODE</code> of the project directory. The file is not human-readable, but as you add elements to your software and melt you watch its size grow. Whenever you freeze, it's emptied.
|
||||
|
||||
{{note|For systems targeted to Microsoft .Net, bytecode is replaced by that platform's own internal code, MSIL.}}
|
||||
|
||||
|
||||
==Degrees==
|
||||
|
||||
You can now see the reason behind the terminology used to describe compilation steps, called '''degrees''' on the messages that flash on the screen when you do a compilation. The names are inspired by the international temperature scale -- Celsius, also known as centigrade -- where water freezes at 0 (and boils at 100, but Eiffel software never reaches that). For EiffelStudio:
|
||||
* Compilation starts at degree 6, which examines the clusters of your system to determine what classes may have changed. In many cases the compilation can safely skip part of this degree.
|
||||
* Degree 5 parses modified classes. It's executed not only when you explicitly request a compilation, but also when you save a class from the EiffelStudio editor, or exit from an external editor, so that you can see and fix syntax errors without delay.
|
||||
* Degrees 4 down to 1 take care of melting.
|
||||
* Negative degrees only take place when you freeze or finalize.
|
||||
* After negative degrees comes C-compilation if needed.
|
||||
|
||||
|
||||
==Using melting and freezing==
|
||||
|
||||
When should you melt, freeze, finalize or precompile? The answers are simple and follow directly from the preceding overview; they provide the key to getting the environment to work for you in the most effective way possible.
|
||||
|
||||
Melting is the bread and butter of the Eiffel developer. As you build your software, either from scratch or by modifying an existing system, you will regularly melt to benefit from the various checks that compilation performs and, of course, to generate executable code that you can test and debug immediately. During this process, there is no need to refreeze, since this operation (although still incremental) takes significantly more time than melting.
|
||||
|
||||
Only two operations, noted above, ''require'' freezing: the addition of external (non-Eiffel) routines, such as C functions or C++ classes, and the addition of agents. The reason is easy to understand: the EiffelStudio compiler knows how to melt Eiffel software, but not software written in C or other languages; agents similarly require special code generation.
|
||||
|
||||
''For the first compilation of a system that does not use precompiled EiffelBase, a Freeze is needed since class '' <code>ANY</code>'', from which all other classes inherit, uses some external routines. In this case the environment automatically starts a freeze even if you just click Melt. This does not apply if you have access to precompiled EiffelBase.''
|
||||
|
||||
Except for the addition of external routines or agents, freezing is never strictly necessary. It is indeed possible to use melting throughout a development, never requesting a freeze after the first compilation. But as the melted-to-frozen ratio grows, you may detect a certain degradation in the performance of the system (determined by how big a share of your system is melted, not how many times you melt it). After a while, then, you may want to refreeze. Like melting, freezing is incremental: only those parts of a system that have been logically changed will be recompiled; as with melting, the determination of what needs to be recompiled is entirely performed by the environment, without any manual intervention on the developer's part.
|
||||
|
||||
The principal difference is that freezing takes longer than melting. Because of this you are requested to confirm the first time you freeze. Freeze the example system by choosing the menu entry
|
||||
<code lang=text>
|
||||
Project --> Freeze</code>
|
||||
You get the following dialog:
|
||||
|
||||
[[Image:es gt freeze warning|Freezing requires external compilation]]
|
||||
|
||||
Note the <code>No</code> option: by default, freezing will start a C compilation, but you can stop after C generation if you wish. This is useful for example if you want to generate a C package for cross-development, C-compiling the result on a different platform.
|
||||
|
||||
Click <code>Yes</code> to confirm freeze and C-compilation. Once the Eiffel compilation is complete, a message in the Development Window ( <code>C compilation launched in background</code>) tells you when that C-compilation has started. C-compilation does not block EiffelStudio: at this point you can continue working with the environment. Any messages from C compiler will appear in the [[External compilation pane]] of the [[Outputs Tool|Outputs tool]].
|
||||
|
||||
You will be able to execute the frozen system as soon as the C compilation finishes.
|
||||
|
||||
You will note that freezing, although it takes more time than melting, is actually quite fast, both due to the speed of Eiffel compilation and to the structure of the generated C code, designed to optimize the operation of the C compiler.
|
||||
|
||||
{{note|When you freeze a system targeted to Microsoft .NET, the external compilation of your system is not necessary. The intermediate language generated by EiffelStudio and other .Net compatible compilers will be converted to machine code at runtime by .Net's just-in-time (JIT) translator.}}
|
||||
|
||||
|
||||
==Using finalizing==
|
||||
|
||||
The main reason for finalizing a system is run-time performance of the generated system. Finalization enables you to generate the high-performance executables that are among the hallmarks of ISE Eiffel. As a consequence, finalized code is the best vehicle for cross-development: you can port the resulting C package to various target platforms and C-compile them on these platforms.
|
||||
|
||||
The '''optimizations''' performed by finalization affect both space and time:
|
||||
* ''Dead code removal'' strips the executable module of all the routines in the system that are not actually called, directly or indirectly, by the root's creation procedure. In a large system relying on many general-purpose classes, dead code removal can easily reduce an executable's size by one third or more.
|
||||
* Finalization also applies ''static binding'' to non-polymorphic calls, and ''inlines'' some routine calls.
|
||||
|
||||
As long as you continue changing, melting and freezing your system, the workbench compiling mechanisms cannot perform such optimizations: if a routine is "dead" today you may resurrect it tomorrow by adding a new call to it somewhere; and if a call is non-polymorphic a single additional assignment may require dynamic binding. Compilation can only generate optimal code by working on a full, stable system. This is the task of finalization.
|
||||
|
||||
'''Cross-development''', the second reason for finalizing, is important if you are taking advantage of the portability of ISE Eiffel to develop your system on a certain platform and then run the result on target computers with possibly different architectures. A target machine may lack an ISE Eiffel compiler (unmistakably signaling its owner's backwardness) but include a C compiler. If the development and target platforms are of different architectures you will need to obtain a copy of the run-time system for the target architecture. The run-time system is also ANSI-C-based, so porting it is usually a straightforward matter.
|
||||
|
||||
Note that cross-development does not ''require'' finalization, since you can cross-compile a frozen version. In practice, however, the finalized version is usually the preferred form for porting a C package because of the performance advantage.
|
||||
|
||||
Finalize the example system now by selecting the menu entry
|
||||
<code lang=text>
|
||||
Project --> Finalize</code>
|
||||
Here too you will be asked to confirm, although the dialog enables you to suppress that confirmation for later attempts, and you may skip C compilation. You will note that finalization is longer than freezing, but still remains quite reasonable thanks to the extensive optimization of the Eiffel compilation process and the structure of the generated C code.
|
||||
|
||||
|
||||
6
documentation/18.11/eiffelstudio/Tutorials/index.wiki
Normal file
6
documentation/18.11/eiffelstudio/Tutorials/index.wiki
Normal file
@@ -0,0 +1,6 @@
|
||||
[[Property:title|EiffelStudio tutorials]]
|
||||
[[Property:link_title|Tutorials]]
|
||||
[[Property:weight|2]]
|
||||
[[Property:uuid|4d68a136-f7c2-ddd3-d30d-e16ee7692302]]
|
||||
This is a guided tour of Eiffel Software's EiffelStudio interactive software development environment.
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
[[Property:title|A Look at the Project Directory]]
|
||||
[[Property:weight|-11]]
|
||||
[[Property:uuid|d82eae3f-fe0d-3e27-008e-61afd05f8cb0]]
|
||||
Before we proceed with the facilities of the environment, let's take a look at the way EiffelStudio organizes project files.
|
||||
|
||||
With EiffelStudio, you build projects. Most projects yield an executable system, although you can also build a project just to define a library for use by such systems.
|
||||
|
||||
Every session is relative to a project; you can start a new project from within EiffelStudio by following the menu path:
|
||||
<code lang="text">
|
||||
File --> New Project
|
||||
</code>
|
||||
... but please '''don't select that menu entry now''' as we have many more things to do with our current project first.
|
||||
|
||||
Every project has a '''project directory''' which will contain the files generated and managed by EiffelStudio. The project directory may also host some of the source files containing your Eiffel classes, the ECF (eiffel configurationl file), and external software written in other languages. However, it is not required that everything be stored together; the source files and ecf may reside anywhere. Some users, in fact, like to put nothing other than the EiffelStudio-generated files in the project directory; this separates user-managed and system-managed files, and can facilitate configuration management, backups and porting.
|
||||
|
||||
In this simple Tour, things have been set up so that all the files of interest, source texts as well as generated ones, will appear in the project directory <code>YOURDIR</code> (either <code>$ISE_EIFFEL\examples\studio\tour</code> or the copy that you have made). Go to that project directory using the Windows explorer or a <code>cd</code> command, and look at its contents (using <code>ls</code> on Unix/Linux):
|
||||
|
||||
[[Image:es gt project directory 01]]
|
||||
|
||||
The contents of this <code>YOURDIR</code> directory includes the following:
|
||||
* First you see a number of files with the extension <code>.e</code> , for "Eiffel": <code>heir.e </code>, <code> invalid.e </code> and others. These are the Eiffel source files, each containing one class. The recommended convention is to store a class of name <code>CLASS_NAME</code> into a file of name <code>class_name.e </code>, where <code>class_name</code> is the lower-case version of <code>CLASS_NAME</code> ; here, file <code>heir.e</code> contains the class <code>HEIR</code> and so on. As you may remember, Eiffel is case-insensitive, but the standard convention for class names is to write them in all upper case. Calling the file <code>class_name.e</code> is only a recommendation, not an obligation; but you <span>are</span> required to store one class per file. This keeps things simple and facilitates project and configuration management.
|
||||
* You also notice a file with an <code>ecf</code> extension. This is the configuration file that specifies this project. As you remember, the ECF file for this example was available as part of the delivery; we used it to compile the project. In most practical cases, however, you won't need to build an ECF; if you use the "Create project" option of EiffelStudio, EiffelStudio will build the ECF for you; if you change the Project Settings during a session, EiffelStudio will update the ECF. ECF files are written in a XML notation.
|
||||
* You will notice a subdirectory called <code>EIFGENs</code>, for "<code>EIF</code>''fel'' <code>GEN</code>''eration''<code>s</code>". <code>EIFGENs</code> is created and maintained by the compiler to store information about your project, including generated code for execution. EiffelStudio manages your project in such a way that <code>EIFGENs</code> can always be re-generated if need be; this means in particular that if things go wrong for any reason and you want to make a fresh start you can always delete this directory and recompile your system. This also means that you should not add any files into this directory, or modify any of its files, since a later compilation is free to change or regenerate whatever it chooses in <code>EIFGENs</code>.
|
||||
* Because the demonstration system for the Tour is a Microsoft Windows system, there is a file named <code>simple.rc</code> in the folder. This is a Windows resource file that was created automatically by EiffelStudio.
|
||||
|
||||
Later on, we will see that EiffelStudio may generate three more subdirectories of the project directory: <code>Diagrams</code>, if you produce graphical system diagrams; <code>Documentation</code>, if you request system documentation, for example HTML; and <code>Metrics</code>, if you perform measurements on your system. Other than these directories, <code>EIFGENs</code> EiffelStudio will not touch anything in the project directory, so you may safely add and change whatever files and subdirectories you like.
|
||||
|
||||
You seldom need to look into <code>EIFGENs</code>, although you should know that it's there. Right now if you check the contents of the project directory <code>YOURDIR</code> (using the Windows Explorer on Windows, the <code>ls</code> command on Unix, or some equivalent mechanism), you will see that <code>EIFGENs</code> has been created, itself with a subdirectory called <code>classic</code> which is the name of the target and which has some subdirectories, including <code>W_Code</code> which contains the generated code ( <code>W</code> for "Workbench" -- we'll see the reason later). Feel free to browse through it if you like, but don't change anything.
|
||||
|
||||
By the way, we are now done with any platform-specific instructions. Everything in the rest of this Tour, other than the graphical look-and-feel, will work the same across all EiffelStudio platforms.
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
[[Property:title|Manual identification and copyright]]
|
||||
[[Property:weight|7]]
|
||||
[[Property:uuid|c581a81b-fc9b-99bd-e73a-f290f6051a45]]
|
||||
Title: ''EiffelStudio: A Guided Tour'', Eiffel Software Technical Report TR-EI-68/GT. (Replaces TR-EI-38/EB.)
|
||||
|
||||
===Publication history===
|
||||
|
||||
First published 1993 as ''First Steps with EiffelBench'' (TR-EI-38/EB) and revised as a chapter of ''Eiffel: The Environment'' [http://www.eiffel.com/doc/ (TR-EI-39/IE), also available as] <span>An Object-Oriented Environment</span> (Prentice Hall, 1994, ISBN 0-13-245-507-2.
|
||||
|
||||
Version 3.3.8, 1995.
|
||||
|
||||
Version 4.1, 1997
|
||||
|
||||
This version: July 2001. Corresponds to release 5.0 of the EiffelStudio environment.
|
||||
|
||||
===Author===
|
||||
''Bertrand Meyer''
|
||||
===Software credits===
|
||||
|
||||
Emmanuel Stapf, Arnaud Pichery, Xavier Rousselot, Raphael Simon; Etienne Amodeo, Jrome Bou Aziz, Vincent Brendel, Gauthier Brillaud, Paul Colin de Verdiere, Jocelyn Fiat, Pascal Freund, Savrak Sar, Patrick Schonbach, Zoran Simic, Jacques Sireude, Tanit Talbi, Emmanuel Texier, Guillaume Wong-So; EiffelVision 2: Leila Ait-Kaci, Sylvain Baron, Sami Kallio, Ian King, Sam O'Connor, Julian Rogers. See also acknowledgments for earlier versions in ''Eiffel: The Environment''(TR-EI-39/IE)
|
||||
|
||||
Non-Eiffel Software: special thanks to Thomas Beale, Eric Bezault, Paul Cohen, Paul-Georges Crismer, Michael Gacsaly, Dave Hollenberg, Mark Howard, Randy John, Eirik Mangseth, Glenn Maughan, Jacques Silberstein.
|
||||
|
||||
===Cover design===
|
||||
|
||||
Rich Ayling.
|
||||
|
||||
===Copyright notice and proprietary information===
|
||||
|
||||
Copyright Interactive Software Engineering Inc. (Eiffel Software), 2001. May not be reproduced in any form (including electronic storage) without the written permission of Eiffel Software. "Eiffel Power" and the Eiffel Power logo are trademarks of Eiffel Software.
|
||||
|
||||
All uses of the product documented here are subject to the terms and conditions of the Eiffel Software user license. Any other use or duplication is a violation of the applicable laws on copyright, trade secrets and intellectual property.
|
||||
|
||||
Any third-party products mentioned in this document are hereby acknowledged as trademarks of their respective owners.
|
||||
|
||||
===Special duplication permission for educational institutions===
|
||||
|
||||
Degree-granting educational institutions using EiffelStudio teaching purposes as part of the <span> [http://www.eiffel.com/educators/resources.html Eiffel University Partnership Program] </span> may be permitted under certain conditions to copy specific parts of this book. Contact Eiffel Software for details.
|
||||
{|
|
||||
|-
|
||||
| <center>'''About Eiffel Software ''' </center>
|
||||
|-
|
||||
|
|
||||
Eiffel Software (Interactive Software Engineering) helps you produce software better, faster and cheaper.
|
||||
|
||||
Eiffel Software provides a wide range of products and services based on object technology, including EiffelStudio, a complete development environment for the full system lifecycle. Eiffel Software's training courses, available worldwide, cover key management and technical topics. Eiffel Software's consultants are available to address your project needs at all levels.
|
||||
|
||||
Eiffel Software's TOOLS (Technology of Object-Oriented Languages and Systems) conferences, [http://www.tools-conferences.com http://www.tools-conferences.com] , are the meeting point for anyone interested in the software technologies of the future.
|
||||
|
||||
Eiffel Software originated one of the earliest .NET products and offers a full range of .NET services and training at [http://www.dotnetexperts.com http://www.dotnetexperts.com] .
|
||||
|
||||
For more information <br/>
|
||||
<br/>
|
||||
Interactive Software Engineering Inc.<br/>
|
||||
Eiffel Software Building, 360 Storke Road<br/>
|
||||
Goleta, CA 93117 USA<br/>
|
||||
Telephone 805-685-1006, Fax 805-685-6869 <br/>
|
||||
<br/>
|
||||
Internet and e-mail
|
||||
|
||||
Eiffel Software maintains a rich source of information at [http://www.eiffel.com http://www.eiffel.com] , with more than 1200 Web pages including online documentation, downloadable files, product descriptions, links to Eiffel Software partners, University Partnership program, mailing list archives, announcements, press coverage, Frequently Asked Questions, Support pages, and much more.
|
||||
|
||||
Visit [http://www.eiffel.com/general/contact_details.html http://www.eiffel.com/general/contact_details.html] to request information about products and services. To subscribe to the Eiffel Software user list, go to[http://groups.eiffel.com/join http://groups.eiffel.com/join] .
|
||||
|
||||
Support programs
|
||||
|
||||
Eiffel Software offers a variety of support options tailored to the diverse needs of its customers. See [http://support.eiffel.com http://support.eiffel.com] for details.
|
||||
|
||||
|}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,161 @@
|
||||
[[Property:title|Producing and Exporting Documentation]]
|
||||
[[Property:weight|-7]]
|
||||
[[Property:uuid|ca43a3c2-9e1a-a69f-81cf-55d0b12294ea]]
|
||||
Software development is, most of the time, cooperative work. You must tell the rest of the team what you're up to, and find out what they can offer you. Bring in distributed development -- increasingly common these days, with some people working at headquarters, others at home, others traveling, an offshore team half a world away <span>...</span> -- and the problem becomes even more critical.
|
||||
|
||||
EiffelStudio provides unique facilities to make such distributed development possible in a safe, effective, harmonious way. Some of the key criteria are:
|
||||
* You must be able to export the information easily to the World-Wide Web, the most general and widely available interaction mechanism.
|
||||
* The documentation must be <span>faithful</span> to the software. Because of the ever-changing nature of software, this goal is impossible to satisfy unless the documentation is <span>extracted</span> from the software -- as opposed to the traditional approach, still perpetuated by many CASE tools, of treating the two as separate.
|
||||
* The task of updating the documentation after a software change must be straightforward and automatic.
|
||||
* It's not enough to support HTML; many other formats are useful too.
|
||||
* Users must have the ability to adapt the mechanism to support <span>new</span> formats.
|
||||
* For existing formats, they must have a way to tune the output easily to any specific style standards, company policies, local variants.
|
||||
|
||||
EiffelStudio's documentation generation satisfies all these requirements.
|
||||
|
||||
==Documentation filters==
|
||||
|
||||
Let's see how documentation works by starting to generate it for our Guided Tour system -- which really means for EiffelBase, since that's what it mostly consists of. The HTML result is available as part of the present documentation (we'll tell you where in just a minute), so you don't have to regenerate it unless you want to. Indeed we'll show you when to click <code>Cancel</code> if you are happy with the pre-generated version. But let's get started anyway to understand the principles and possibilities.
|
||||
|
||||
Click the following menu entry, used to generate documentation:
|
||||
<code lang="text">
|
||||
Project --> Generate documentation...
|
||||
</code>
|
||||
|
||||
This is the next-to-last entry in the <code>Project</code> menu. The last one, by the way, <code lang=text>XMI Export</code> <span>...</span>, is directly relevant too: it will make it possible to export information in the standard XML representation for UML, for consumption by third-party products such as Rational Rose. But for the moment we choose the <code>Documentation</code> entry to start the Eiffel Documentation Wizard.
|
||||
|
||||
The Wizard starts with a list of available output formats, also called <span>filters</span>:
|
||||
|
||||
[[Image:index-37]]
|
||||
|
||||
The filter names correspond to major documentation formats which EiffelStudio supports by default. Among the most important, listed here in rough order of appearance in the list:
|
||||
* <code lang=text>ASCII</code> : plain text, no formatting codes.
|
||||
* <code>eiffel</code> : essentially the same as ASCII; useful if you want EiffelStudio to pretty-print your class texts and replace the originals, as explained below.
|
||||
* <code>MML</code> : internal format for Adobe FrameMaker.
|
||||
* <code>Postscript</code> : to generate Adobe Postscript output, suitable for printing on a Postscript printer, display on a Postscript previewer such as Ghostscript, or distilling to Adobe PDF.
|
||||
* <code>COM</code> : to generate class specifications in the form of an Interface Description Language (IDL) interface for Microsoft's COM component model.
|
||||
* <code>RTF</code> : Microsoft's Rich Text Format, used in particular for Windows "Help" files.
|
||||
* <code>TeX1</code>, <code>TeX2</code> : two variants for Donald Knuth's TEX processing format.
|
||||
* <code>troff</code> : if you already know what this is, congratulations (or condolences), you've been around the industry for a while. This is a traditional text-processing format available on Unix systems. Also works for the <span>gtroff</span> variant.
|
||||
* <code>html-classic</code> : HTML, no style sheets. The next variant, <span>with</span> style sheets, is strongly recommended unless your colleagues will be reading your documentation with Mosaic 1, vintage 1993, or Netscape 2, Vintage 1995.
|
||||
* <code>html-stylesheet</code> : HTML with style sheets. This is particularly attractive for Web publishing not only because the output makes full use of style sheet capabilities (fonts, colors, layout, formatting) but also because it becomes trivial to change the look-and-feel to support any style you or your users like, even <span>after</span> generation, simply by editing the style sheet file.
|
||||
|
||||
Not only do these predefined filters provide support for a number of important industry formats; better yet, if you want <span>another</span> format not represented on the list, or would like to adapt an existing format to your own style preferences, it's easy to define a new filter. The list that EiffelStudio displays comes from the files with a <code>.fil</code> extension that it finds in a subdirectory of the installation:
|
||||
<code>$ISE_EIFFEL/studio/filters</code>
|
||||
|
||||
To define a new filter, simply add a file to this directory. Filters are expressed in a simple notation called EFF ( <span>Eiffel Filter Format</span> ), general enough to support a wide variety of tools for text processing, project management, Web publishing etc. The best way to define a new filter is usually to start from an existing one and adapt it. You will find the specification of EFF at the end of this manual, [[APPENDIX: WRITING DOCUMENTATION FILTERS WITH EFF, THE EIFFEL FILTER FORMAT|here]] .
|
||||
|
||||
==Generating an HTML record of your project==
|
||||
|
||||
Let's select the most obviously attractive of the predefined filters: HTML with stylesheets. Click the line <code>html-stylesheet</code> in the list to make it active, then click <code>Next</code> at the bottom of the Documentation Wizard window. The next window appears:
|
||||
|
||||
[[Image:index-38]]
|
||||
|
||||
In this pane you select which parts of your system you want to be included in the documentation. By default, all library and cluster names are checked. You should uncheck any that you do not want included.
|
||||
|
||||
Note that each library or cluster name must be checked or unchecked individually. For example, unchecking "base" will not automatically deselect "elks" and "ise" which appear under "base".
|
||||
|
||||
For this Tour we'll want to generate everything, including EiffelBase, so make sure that in the end all library and cluster names are checked, as in the figure. Then click <code>Next</code>.
|
||||
|
||||
==Generating Metatags from Note entries==
|
||||
|
||||
The next step of the documentation wizard asks you to select Note entries:
|
||||
|
||||
[[Image:index-39]]
|
||||
|
||||
Eiffel classes, as you know, may start with an <code>note</code> entry that enables class authors to include documentary information in any category they like. It is standard (and part of the official style guidelines) to include at the very least an entry of the form <code>description:</code> <code>Descriptive text</code> in every class. The earlier displays of class <code>LIST</code> showed that entry, which read " <code>Sequential lists, without commitment to a particular representation</code>".
|
||||
|
||||
You may have noted that the purpose of Eiffel's <code>note</code> clauses is, conceptually, similar to that of '''metatags''' in HTML. Metatags carry information which Web page visitors do not normally see in the browser; this information is available, however, to search engines and other tools that explore and classify Web pages. So it seems quite appropriate to generate metatags from <code>note</code> entries.
|
||||
|
||||
The dialog illustrated in the last figure lets you select the entries you wish to transform into metatags. It appears only if you have selected an HTML filter. It lists all the <code>note</code> tags found anywhere in the system; those that are checked will be retained for metatags. Initially unchecked are three tags ("date", "revision", and "status") conventionally used -- at Eiffel Software and other Eiffel sites -- for interfacing with configuration management tools, and hence of internal interest only.
|
||||
|
||||
There is no need to change the default selection, so just click <code>Next</code>.
|
||||
|
||||
==Choosing a level of detail==
|
||||
|
||||
The next step of the Documentation Wizard lets you specify what kinds of documents you want to generate:
|
||||
|
||||
[[Image:index-40]]
|
||||
|
||||
This is a very important facility since it gives you control over how much you want to publish about the properties of the software:
|
||||
* You may want to publish <span>everything</span>, source included, for example on your Intranet for a group of developers working closely together on the same classes, or on the Internet for open-source software.
|
||||
* You may want to publish only the <span>interfaces</span> (Contract or Flat-Contract views). This is not necessarily to protect proprietary information; even if you don't care about showing your source code, it is usually too detailed for client programmers, especially in the case of libraries. If various teams work on separate parts of a project, what each releases to the other should usually be the specification, not the implementation.
|
||||
* You may of course want to publish <span>both</span> the text and the interface, and let the recipients use the version that best suits their needs for each use.
|
||||
* You may want to publish the <span>diagrams</span>, showing the structure in graphical form. Note the warning -- which we are about to ignore -- telling us this may take a while.
|
||||
* The class list, cluster list, cluster hierarchy view, cluster chart (following the conventions of BON) are also optional.
|
||||
|
||||
The dialog shown on the last figure lets you specify the exact combination you wish. The figure indicates the default options.
|
||||
|
||||
This time, if we generate anything, we'll generate everything. Please check '''all''' the boxes (the generation won't occur until the last step) and click <code>Next</code> to move to the next dialog of the Documentation Wizard.
|
||||
|
||||
==Specifying cluster views==
|
||||
|
||||
The next dialog only appears when you have asked to generate diagrams:
|
||||
|
||||
[[Image:index-41]]
|
||||
|
||||
Although we didn't use this possibility yet, the Diagram view lets you define different subviews of any cluster. One view might show inheritance only, the other client links only; one might include all classes, the other hide some library classes. The last dialog shown will allow you, for any cluster, to select a subview other than the default for the generated diagram.
|
||||
|
||||
Here we only have the default view, so just click <code>Next</code>.
|
||||
|
||||
==Generating==
|
||||
|
||||
The last dialog simply asks you where you want to generate the result:
|
||||
|
||||
[[Image:index-42]]
|
||||
|
||||
By default, as shown, EiffelStudio will produce the documentation in a subdirectory -- created for the occasion, if it doesn't exist yet -- of the project directory:
|
||||
<code>
|
||||
.../your_project_directory/Documentation</code>
|
||||
|
||||
You may, however, select any other location you like. In the case of HTML generation, as here, EiffelStudio takes great care to use only '''relative hyperlinks''' so that you can move the <code>Documentation</code> directory around, for use either on a file system or on your Web site, with the guarantee that the hyperlinks will work -- as long as you move the entire directory together.
|
||||
|
||||
To continue the Guided Tour, you do '''not''' need to complete the generation now unless you want to. If you are happy to continue without generating the documentation at the moment then click <code>Cancel</code> on the last dialog.
|
||||
|
||||
{{note|If you do prefer to produce your own local version of the full documentation for the guided tour system, click "Finish". The process takes 7 minutes on the Thinkpad configuration mentioned earlier, and generates a documentation directory of about 220 megabytes. }}
|
||||
|
||||
==Browsing generated documentation==
|
||||
|
||||
Let's take a look at the generated documentation. We start with the root of the generated documentation, <code>Documentation/index.html</code> :
|
||||
|
||||
[[Image:index-43]]
|
||||
|
||||
This root page shows overall information about the system. The top set of links, repeated at the bottom, enables you to browse the system from its list of classes, its list of clusters, or the cluster hierarchy; note the box labeled <code>to Go</code>, which provides a built-in search engine, enabling you to type any class list and go directly to the corresponding page. Let's look at the class list: click the box <code>Classes</code> at the top left.
|
||||
|
||||
[[Image:index-44]]
|
||||
|
||||
This shows the beginning of the list of classes, alphabetically sorted. You could click any class to get the corresponding information, but wait; we'll look at individual classes in a moment. Instead, click <code>Cluster hierarchy</code> to see the overall organization of the system into clusters:
|
||||
|
||||
[[Image:index-45]]
|
||||
|
||||
Click <code>BASE</code> to see details of the EiffelBase library where (under EiffelStudio) we had found the class <code>LIST</code> used as example in the preceding sections:
|
||||
|
||||
[[Image:index-46]]
|
||||
|
||||
This indicates the relations of the cluster to others in the hierarchy, and its list of classes. Again you could click any class name but instead note the link <code>(diagram)</code> next to the cluster name near the top. Remember that when generating the documentation we elected to generate everything, diagrams included. Hadn't we checked the corresponding check box, the <code>(diagram)</code> link wouldn't be there. Click it now to get the diagram that has been generated for <code>BASE</code>:
|
||||
|
||||
[[Image:index-47]]
|
||||
|
||||
The output is a diagram showing graphically the classes of the cluster and their inheritance relations. All EiffelStudio-generated HTML diagrams use the PNG graphics format ( <span>Portable Network Graphics</span> ), supported by all recent browsers.
|
||||
|
||||
The class bubbles in a diagram are all hyperlinks. To see the HTML documentation for our old friend the class <code>LIST</code> you could just click its bubble. But because this diagram includes the whole library and is automatically generated, you'd have to look around a bit for the <code>LIST</code> bubble. Go ahead and do that if you wish, or just type the class name <code>LIST</code> into the <code>Go to</code> field and press return:
|
||||
|
||||
[[Image:index-48]]
|
||||
|
||||
The display shows key information on the class, in a form called the "Chart format" listing the ancestors and then the features, divided into <code>Queries</code> (shown in part on the figure) and <code>Commands</code>. Note that all class names and feature names are hyperlinks, which would lead you to the appropriate place in a class text.
|
||||
|
||||
The top row of hyperlinks now includes class formats corresponding to those we discovered in [[Viewing Classes]] in EiffelStudio: <code>Relations</code> (covering ancestors, descendants, clients, suppliers, ), full <code>Text</code>, <code>Contracts</code>, <code>Flat contracts</code>. Click <code>Flat contracts</code> to see the full interface of the class:
|
||||
|
||||
[[Image:index-49]]
|
||||
|
||||
We'll stop this brief review here but you may continue browsing through the HTML pages if you like. Note how closely the appearance of the class texts, flat forms, contract forms, diagrams and other forms of documentation matches the corresponding formats under EiffelStudio.
|
||||
|
||||
Although we suggest staying with the standard, you can easily change any convention that doesn't match your own preferences:
|
||||
* For the EiffelStudio appearance, use <code lang=text>Tools --> Preferences</code>.
|
||||
* For the HTML appearance, if you know about Cascading Style Sheets (CSS) for HTML, edit the style sheet <code>default.css</code>. You will find this file in the generated documentation directory; alternatively, to ensure the changes are applicable to the generated documentation of all future projects, edit <code>defaults.css</code> in the directory after backing it up. For more profound changes in the structure of the generated HTML, you may also backup and edit the Eiffel Filter Format file <code>html-stylesheet.fil</code> in the same directory. EFF is described in the [[APPENDIX: WRITING DOCUMENTATION FILTERS WITH EFF, THE EIFFEL FILTER FORMAT|Appendix]] .
|
||||
<code>
|
||||
$ISE_EIFFEL/studio/filters</code>
|
||||
|
||||
|
||||
The documentation generation mechanisms, using HTML or other formats, let you publish your designs, at the level of detail you desire, on an Intranet, the Internet, or as part of documents you release. They are an important part of the power of EiffelStudio for quality software development.
|
||||
|
||||
@@ -0,0 +1,173 @@
|
||||
[[Property:title|Recompiling and Editing]]
|
||||
[[Property:weight|-4]]
|
||||
[[Property:uuid|6574a573-48b9-6088-aa98-53d7119d7c5c]]
|
||||
|
||||
So far we have relied on existing class texts. Fascinating as it may be to explore excellent software such as EiffelBase, you probably want to write your own too (with the help of the reusable components in the Eiffel libraries). EiffelStudio provides a built-in editor -- as well as the ability to use some other editor if you prefer -- and sophisticated compilation mechanisms.
|
||||
|
||||
==Recompiling==
|
||||
|
||||
When we started, we compiled the example system. Let's recompile it, just to see. We'll see compilation entries in the <code>Project</code> menu, but the easiest for the moment is to use the compilation button ([[Image:compile-button]]) in the Project toolbar. Click this button. You haven't changed anything in the project since it was compiled (at least you were not supposed to!), so EiffelStudio will very quickly detect this and finish compilation. On our test platform this takes less than a second. Now of course we should see what happens if you do change something.
|
||||
|
||||
|
||||
==Editing==
|
||||
|
||||
We don't want to touch EiffelBase classes (and in fact can't, since it is used in precompiled form), so let's focus on classes of our small root cluster. In the Groups tool, expand cluster <code>root_cluster</code> and click class <code>PARENT</code> to retarget the Development Window to it.
|
||||
|
||||
Make sure that the Editing Tool is big enough to display the text of the class:
|
||||
|
||||
[[Image:es gt development window targeted to parent 01|Class PARENT in Editing tool]]
|
||||
|
||||
The Editing Tool hosts a text editor which you can use to change the class text. Here the routine <code>display</code> starts by outputting a simple message; let's precede it by another line of display to check that we affected the outcome. We'll want to add the following two lines just after the <code>do</code>, before the first two instructions of the routine:
|
||||
<code>
|
||||
io.put_string ("THIS IS SOME ADDED TEXT")
|
||||
io.new_line
|
||||
</code>
|
||||
|
||||
You can just use copy-paste from the example above: select the two lines with the mouse, copy them using <code>CTRL-C</code> (or <code>Copy</code> from the <code>Edit</code> menu), then paste them just after the <code>do</code> using <code>CTRL-V</code> (or <code>Paste</code> from the <code>Edit</code> menu). Add or remove tabs to align with the rest of the routine, so that the result will look like what's shown on the next figure. Please check the result and be careful not to introduce any mistakes; in the next section we'll study how EiffelStudio will report syntax and other errors, but right now we want to see what happens when everything is right!
|
||||
|
||||
[[Image:es gt development window targeted to parent 02|Class PARENT with changes]]
|
||||
|
||||
Now save your changes; you may indifferently use <code>CTRL-S</code>, the <code>Save</code> entry from the <code>Edit</code> menu, or the Save button ([[Image:save-button]]), at the cursor location on the figure. (If you forget to save, the next compilation will tell you so, and ask you if from now on you want all non-saved class edits to be saved automatically.)
|
||||
|
||||
|
||||
==Recompiling and executing after a change==
|
||||
|
||||
Next compile again, using the Compilation button. Some "degree" messages appear quickly; EiffelStudio has found out what class has changed and deduced what exactly to recompile -- only a subset of the whole system. So this again will proceed very quickly.
|
||||
|
||||
Execute the system again now, using one of the execution buttons, with or without breakpoints, on the right in the bottom Project toolbar. You will see that the message output by the execution has changed to include the added string.
|
||||
|
||||
|
||||
==Views in the Editing Tool==
|
||||
|
||||
In studying the Class tool we discovered a number of views of a class text. For convenience, you can also display a number of these views in the Editing Tool, although only the basic Text view is editable. A row of buttons next to the Class and Feature fields lets you choose between them.
|
||||
|
||||
[[Image:view-buttons]]
|
||||
|
||||
You can try some of these view now, although there is nothing exciting to show about class <code>PARENT</code>. Make sure to come back to the <code>Text</code> view -- through the leftmost of these buttons -- so that we can continue exploring the editing facilities.
|
||||
|
||||
|
||||
==Basic editing facilities==
|
||||
|
||||
The editing facilities in the Editing Tool are provided by the EiffelStudio Editor, a specialized tool supporting the development and update of Eiffel texts. As we'll see next, if you have a preferred editor you can use it instead, but the EiffelStudio Editor is worth knowing.
|
||||
|
||||
The [[EiffelStudio Editor|EiffelStudio Reference section]] on the Editor provides many more details about editing functions. Here are the essentials.
|
||||
|
||||
First, the key property of any interactive system: '''Undo'''. You can cancel the latest editing command, or any earlier one performed during the current session, by choosing <code>Undo</code> from the <code>Edit</code> menu, or typing <code>CTRL-Z</code>. To cancel more than one command, apply <code>Undo</code> repetitively; there is no limit to the number of undoable commands within a session. (When you exit EiffelStudio, however, the editing history is lost.) To redo an undone command, use <code>Redo</code> from the <code>Edit</code> menu or <code>CTRL-Y</code>.
|
||||
|
||||
{{note|Since right now we don't need to do any actual editing to continue this Guided Tour, we suggest that you don't change the text of class <code>PARENT</code> but simply look up the menu entries described next, without actually selecting them. If you do make a change, voluntary or not, you should at the end of this editor discussion perform enough Undo commands to get the text of class <code>PARENT</code> back to its original state. }}
|
||||
|
||||
To '''copy''', '''cut''' and '''paste''' use the corresponding entries in the <code>Edit</code> menu or the familiar keyboard shortcuts <code>CTRL-C</code>, <code>CTRL-X</code> and <code>CTRL-V</code>.
|
||||
|
||||
When you edit text, it will be automatically '''indented''' according to standard Eiffel style rules. If you prefer to remain in charge of your own indenting, you can disable this facility through
|
||||
<code lang=text>
|
||||
Tools --> Preferences --> Editor</code>
|
||||
|
||||
To indent a sequence of lines, select the lines, then use
|
||||
<code lang=text>
|
||||
Edit --> Advanced --> Indent selection</code>
|
||||
You can also use the Tab key, but only if the selection consists of one or more entire lines; otherwise typing Tab will simply replace the selected text with a Tab character. Shift-Tab will similarly decrease indentation by one step.
|
||||
|
||||
To '''comment out''' a sequence of lines, select them and use
|
||||
<code lang=text>
|
||||
Edit --> Advanced --> Comment</code>
|
||||
or <code>CTRL-K</code>. Conversely, <code>CTRL-Shift-K</code> will uncomment. Also in the <code lang=text>Edit --> Advanced</code> menu are "set to upper case", with the keyboard shortcut <code>CTRL-U</code>, and to lower case, <code>CTRL-Shift-U</code>.
|
||||
|
||||
Other useful facilities of the <code lang=text>Edit --> Advanced</code> menu are:
|
||||
* <code>Embed in "if"</code>, or <code>CTRL-I</code>, which will create a conditional instruction and include the selected instructions in it.
|
||||
* <code>Embed in "debug"</code>, <code>CTRL-D</code>, which will include the selected instructions in a <code>debug</code> <span>...</span> <code>end</code> instruction, so that their execution becomes conditional on a Debug compilation option.
|
||||
|
||||
|
||||
== Search and replace ==
|
||||
|
||||
The editor lets you search for text and replace occurrences, individually or globally. We assume you have seen a text search facility before, so we'll just emphasize some of the less obvious features.
|
||||
|
||||
To start a search, make sure the [[Search Tool]] is active by clicking the Search button in the top toolbar (this one we'll let you find) or using the
|
||||
<code lang="text">
|
||||
Edit --> Find
|
||||
</code>
|
||||
menu entry.
|
||||
|
||||
{{note|If you press <code>CTRL-F</code> in a tool you will get a quick search bar that quickly allows you to search for something in the current text.}}
|
||||
|
||||
The [[Search Tool]] presents a number of self-explanatory options:
|
||||
|
||||
|
||||
|
||||
[[Image:search-tool]]
|
||||
|
||||
You can enter a term to replace your search term in the <code>Replace with</code> box.
|
||||
|
||||
Having filled the two fields, you can elect to replace the last found occurrence, or all occurrences at once.
|
||||
|
||||
The <code>Search for</code> field has an associated drop-down list, so that you can reuse a recently entered search string without retyping it.
|
||||
|
||||
|
||||
==Let the editor do the typing==
|
||||
|
||||
Particularly interesting are the editor's '''automatic completion''' facilities (often, we shorten the name to '''auto-completion'''). Well, particularly interesting for ''most'' people: maybe you like your editor to do the grunt work for you, or maybe you don't. In the latter case -- if you prefer to be in control of all the details -- don't worry: through
|
||||
<code lang=text>
|
||||
Tools --> Preferences --> Editor</code>
|
||||
you can easily disable any facility that you don't like. The behavior described here is the default.
|
||||
|
||||
The EiffelStudio Editor knows about Eiffel syntax and will recognize syntactic elements as you type them. It will color them according to standard conventions: basic elements in black, keywords in blue, comments in dark red. You can change these conventions through Preferences.
|
||||
|
||||
If you start typing a control structure through its opening keyword, such as <code>if</code>, or <code>from</code> for a loop, the editor will automatically display the structure of the whole construct. Here for example is the result if you type the <code>from</code> followed by Return/Enter at the beginning of our example routine:
|
||||
|
||||
[[Image:es gt auto complete from 01]]
|
||||
|
||||
This has produced the structure of an Eiffel loop: <code>from</code> <span>...</span> <code>until</code> <span>...</span> <code>loop</code> <span>...</span> <code>end</code>. You can then fill in the blanks with the appropriate expression and instructions. The generated lines start with the appropriate number of Tab characters to support the standard Eiffel indenting conventions. If you want a more compact style, follow the <code>from</code> with a space rather than Return. Typing <code>if</code> followed by Return or a space will similarly produce the outline of a conditional instruction.
|
||||
|
||||
Also interesting is '''feature completion'''. Feature completion is activated by default, and it works at two levels:
|
||||
* You can type the beginning of the name of a feature of the current class, then <code>CTRL-SPACE</code> to get possible completions.
|
||||
* Once you have typed the name of a query (attribute or function), either all by yourself or aided by the previous completion technique, you can type a period to get the list of possible features to be applied, deduced from the list of features in the corresponding class (the type of the query).
|
||||
|
||||
In both cases, if more than one completion is possible, you will get a menu of the possibilities. You can scroll through it with the up and down arrow keys, or the mouse, and select one through Enter or double-click. You can also or give up through the Escape key.
|
||||
|
||||
Here for example is the menu you will see in the body of our example routine if you type <code>io.</code> , where <code>io</code> is the feature, coming from class <code>ANY</code>, that provides access to standard input and output facilities:
|
||||
|
||||
[[Image:es gt auto complete feature 01|Feature auto-completion]]
|
||||
|
||||
If only one completion is possible, no menu appears; the completion is selected.
|
||||
|
||||
When a menu of possible completions is displayed, you can use the arrow keys to traverse the list.
|
||||
|
||||
If you select a routine with arguments, auto-complete will show the arguments and their types, allowing you to provide your value for each argument. The figure below shows auto-completion of a routine with only one argument.
|
||||
|
||||
[[Image:es gt auto complete argument 01|Auto-completion of arguments]]
|
||||
|
||||
You can see that the argument is pre-selected and is of type <code>STRING_8</code>. As soon as you begin to type your substitution for the argument, the pre-selected argument definition is replaced with what you type. When you complete an argument, the <code>Tab</code> key will either pre-select the next argument (in the case of routines with multiple arguments), or place the cursor to the right of the right parenthesis that terminates the routine call (in the case of the last argument).
|
||||
|
||||
Auto-completion will only work for queries that were present at the time of the last successful compilation. So if you add an attribute, say <code>attr</code>, to the current class, and do not recompile, typing <code>a</code> then <code>CTRL-SPACE</code> will not display <code>attr</code>. To make sure that it's included in completion proposals, save and recompile. (Remember, incremental compilation is fast in EiffelStudio, so there is nothing wrong in compiling early and often.) The same rule holds for features of ''other'' classes, those that will appear in proposed completions after a period.
|
||||
|
||||
The features proposed for auto-completion include all features of the class: those declared in the class itself, or ''immediate'' features, and those ''inherited'' from proper ancestors, direct or indirect, with one exception: by default the list will not include features from the universal class <code>ANY</code>, which serves as ancestor to all classes and provides many features for comparison, copying, input-output, reflection etc. Including <code>ANY's</code> features would clutter all menus with too many features. So for example typing <code>i</code> followed by <code>CTRL-SPACE</code> will not suggest <code>io</code> among the possible completions. You can change this policy through Preferences. The policy does not apply to remote feature completion for an entity <code>x</code> declared of type <code>ANY</code>. In the case that you type <code>x.</code>, auto-completion will produce the list of <code>ANY</code>'s features.
|
||||
|
||||
|
||||
==Using your own editor==
|
||||
|
||||
You may have a favorite editor and prefer to use it, at least in some cases. The EiffelStudio incremental compilation mechanism, to be studied shortly, recognizes that files have been modified outside of EiffelStudio (by checking their time stamps) and will without any fuss take their modified versions into account.
|
||||
|
||||
You can also call an outside editor on a class from within EiffelStudio. Just use
|
||||
<code lang=text>
|
||||
File --> External editor</code>
|
||||
or the corresponding button in the top toolbar.
|
||||
|
||||
This will call the editor of your choice. The default is Notepad on Windows and Vi on Unix and Linux. You can easily change this to any editor by entering the desired editor command in
|
||||
<code lang=text>
|
||||
Tools --> Preferences --> General --> External editor command
|
||||
</code>
|
||||
|
||||
In this command text you can use the two special notations <code>$target</code> and <code>$line</code> ; when EiffelStudio calls the selected command, it will replace any occurrence of <code>$target</code> by the name of the file where the current class resides, and <code>$line</code> by the line number at which the Editing Tool is currently scrolled. If you include one or both of these markers at the appropriate argument positions for the command, this will enable you -- assuming the editor supports the appropriate options -- to make sure it starts at exactly the right place. For example the default editor command under Unix is
|
||||
<code>
|
||||
vi +$line $target</code>
|
||||
|
||||
meaning: start the Vi editor on the <code>$target</code> file, initially positioned at line <code>$line</code> (the <code>+</code> <code>line_number</code> command-line option of Vi directs it to start at line <code>line_number</code> ).
|
||||
|
||||
If you start an external editor on a class, then exit the editor after possibly making changes, EiffelStudio will immediately update the class text in the Editing Tool. More generally, note that EiffelStudio will detect changes made separately on the same class, and warn you of possible conflicts.
|
||||
|
||||
Several important text editors from various providers have '''Eiffel modes''', which support the syntax-directed editing of Eiffel texts. They include:
|
||||
* '''Vim''', for Vi iMproved, an extension of Vi available on both Unix/Linux and Windows -- see www.vim.org
|
||||
* '''Emacs''' -- see www.emacs.org.
|
||||
* '''Editeur''', a Windows syntax highlighting editor -- see www.studioware.com.
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,164 @@
|
||||
[[Property:title|Retargeting Through Pick-and-Drop]]
|
||||
[[Property:weight|-5]]
|
||||
[[Property:uuid|a3789781-153b-7f4d-bb94-4bdf8923fb56]]
|
||||
|
||||
You now know quite a few ways of re-targeting a Development Window to a "development object" -- a class or a feature -- but haven't yet seen one of the most important: "Pick-and-Drop", which lets you pick a development object that you have spotted anywhere in the display, and retarget the current tool, or another, to it.
|
||||
|
||||
|
||||
==Trying Pick-and-Drop==
|
||||
|
||||
We restart from the last state, with a Development Window target to feature <code>forth</code> of class <code>LIST</code>. The next figure shows the whole window; it should look like what you see as a result of the last operations. We'll use the <code>Descendant versions</code> view of the <code lang=text>Feature </code>Tab.
|
||||
|
||||
If for some reason the window doesn't look like the next figure, it's easy to reconstruct it: make sure both the Cluster tree and the Feature tree are visible (if not, make visible using the instructions given in [[Viewing Classes#Making some room|Viewing Classes]]); target the tool to class <code>LIST</code>; target further to its feature <code>forth</code> by clicking that feature name in the Features tool's roll of the features of <code>LIST</code>; make sure both the top-left Editing tool and the bottom-left Feature tool are visible; in the Feature tool, select the <code>Descendant versions</code> format.
|
||||
|
||||
[[Image:es gt development window feature descendants 01|Descendant versions of forth]]
|
||||
|
||||
In the Feature tool near the bottom, there is an entry that reads
|
||||
<code>
|
||||
MULTI_ARRAY_LIST [G] forth
|
||||
</code>
|
||||
|
||||
referring to the version of feature <code>forth</code> in class <code>MULTI_ARRAY_LIST</code>. Let's assume you want to see what that version actually is. It suffices to retarget the tool to it. Of course you could type or copy-paste the class name <code>MULTI_ARRAY_LIST</code> in the Class field at the top of the window, and the feature name <code>forth</code> in the adjacent Feature field. But there is an easier way; after all, you have just seen a reference to the feature, through its name as it appears in the Descendant version format, so it's natural to use it directly from the graphical interface.
|
||||
|
||||
As we've seen before, you could control-right-click on the feature name at the place where it appears; this would create a new tab and retarget the Development Window to <code>forth</code> from <code>MULTI_ARRAY_LIST</code>. But you might not necessarily want a new tab. Instead you can use Pick-and-Drop to retarget the current window.
|
||||
|
||||
Here is how it works. Position the cursor on the desired feature reference: the word <code>forth</code> in the line <code>forth MULTI_ARRAY_LIST</code>. Right-click, that is to say click the rightmost mouse button and then release it. You will see a context menu that looks like the figure below.
|
||||
|
||||
|
||||
[[Image:es gt pnd context menu 01]]
|
||||
|
||||
|
||||
The item we want to choose from this menu is "Pick Feature 'forth'". So do that now, by left-clicking over the item.
|
||||
|
||||
Now move the mouse around some, but ''without pressing any button'':
|
||||
|
||||
|
||||
[[Image:es gt picked forth 01]]
|
||||
|
||||
|
||||
The cursor has changed into a new shape, a cross representing the type of development object that you have picked, a feature. For a class, as you may have guessed, it would be a small ellipse ("bubble"). Each kind of development object that you may create and manipulate during your work with EiffelStudio has its distinctive icon. When you '''pick''' an item, you'll notice that the item's icon stays connected to its origin by a dotted line that stretches or shrinks as you move the icon around.
|
||||
|
||||
So, now you have '''picked''' the feature <code>forth</code>. You can '''drop''' it at any appropriate place to retarget the corresponding tool. Move your cursor (and the feature icon for <code>forth</code>) over the Editing tool now.
|
||||
|
||||
To '''drop''', just '''right-click''' again. (That is to say, as before, press the rightmost mouse button and release it immediately.) Drop the icon representing <code>{MULTI_ARRAY_LIST}.forth</code> in the Editing tool.
|
||||
|
||||
This retargets the Development Window to the chosen feature, <code>forth</code> from the class <code>MULTI_ARRAY_LIST</code>. The Feature tool (assuming the Link Context tool option is selected), keeps its current view ( <code>Descendant versions</code> in the <code lang=text>Feature</code> tool) and now shows descendants of <code>{MULTI_ARRAY_LIST}.forth</code>.
|
||||
|
||||
|
||||
[[Image:es gt development window multi array list forth 01|Retargeted to {MULTI_ARRAY_LIST}.forth]]
|
||||
|
||||
|
||||
==Bypassing the context menu==
|
||||
|
||||
In the example above, when you right-clicked over an item, you were presented with a "context" menu, containing choices applicable for the item you clicked. We chose to pick the item. It's possible that if you use pick-and-drop quite a bit that you might rather not see the context menu each time you right click. You can make this happen in a couple of ways. First, if you use the context menu most of the time, but you want to pick directly at other times, you can '''shift-right-click''' to bypass the context menu and pick the item immediately.
|
||||
|
||||
The other option is used if you want a right-click to pick by default, and only use the context menu occasionally. To make this happen, you need to change the '''Pick and drop (pnd) mode''' [[EiffelStudio Preferences|EiffelStudio preference]]. You can change this preference by following the menu path:
|
||||
<code lang="text">
|
||||
Tools --> Preferences...
|
||||
</code>
|
||||
When the preferences window opens, expand the '''General''' preferences folder. You'll see '''Pick and drop (pnd) mode''' is set to '''False''' by default. If you wish to change the behavior, then check the box and the value will change to '''True'''. Then you can exit the preferences window.
|
||||
|
||||
With '''Pick and drop (pnd) mode''' set to '''True''', you will always get a pick when you right-click over an development object. If you occasionally wish to use the context menu, then you would shift-right-click, which would cause the context menu to appear.
|
||||
|
||||
|
||||
==How Pick-and-Drop works==
|
||||
|
||||
|
||||
The Pick-and-Drop mechanism is very simple. It consists of three steps:
|
||||
* '''Pick''' step: find the development object and pick it: either through the context menu, or by shift-right-click, or by right-click, depending upon EiffelStudio's Pick and Drop Mode.
|
||||
* '''Move''' step: move the mouse to the desired drop point, <span>without pressing any button</span>.
|
||||
* '''Drop''' step: right-click (again releasing the button immediately) at the drop position.
|
||||
|
||||
During the Move step, you can at any time '''cancel the whole operation''' simply through a '''left-click'''.
|
||||
|
||||
The Move step is actually optional: if the current position is a valid drop target, as explained next, you can drop immediately after the pick without moving the mouse.
|
||||
|
||||
|
||||
==Pebbles, holes, drop targets and type compatibility==
|
||||
|
||||
The Pick-and-Drop mechanism relies on the metaphor of '''pebbles and holes'''. When you pick a development object, the cursor changes into a '''pebble''' whose shape represents the type of the development object: cluster, class, feature, run-time object ... You may then drop it into a '''hole''', which can be a window, a tree view entry, or a hole-shaped icon. This performs the appropriate action such as retargeting a tool.
|
||||
|
||||
In the same way that Eiffel is a typed object-oriented language, the Pick-and-Drop mechanism is typed: you can only drop a pebble into a compatible hole. For example you may drop a class pebble into a Development Window, to retarget it to the chosen class. If you have picked a development object and have moved its pebble over an area which is an unacceptable place to drop it, you will notice that the pebble takes on its "disabled" form. An enabled class pebble ([[Image:context-class-cursor]]), for example, would become a disabled class pebble ([[Image:context-disabled-class-cursor]]) for the time that it's hovering over unfriendly territory.
|
||||
|
||||
In Eiffel, type compatibility is not necessarily type identity, but is governed by ''conformance'', based on inheritance and polymorphism: to an entity of type <code>POLYGON</code>, you may assign not only an expression of that same type, but also one of type <code>RECTANGLE</code>, if class <code>RECTANGLE</code> inherits from -- conforms to -- class <code>POLYGON</code>. Similarly, EiffelStudio considers that the development type "feature" conforms to "class"; this means you may drop a feature into a Development Window targeted to a class; this will retarget the tool to the feature's class and the feature itself, with the text of the class scrolled to the position of the feature.
|
||||
|
||||
|
||||
==Clickable formats==
|
||||
|
||||
A good deal of the power of Pick-and-Drop comes from its connection with the various views of the Class and Feature tools ... and the Diagram tool which we will see later. As was mentioned when we saw these views, all the feature and class names or other graphical representations that appear in these views are '''clickable''' ; this means that you can select any of them as the source of a Pick-and-Drop.
|
||||
|
||||
As a result, you can quickly traverse a system and get to its essential properties by displaying the information of a class in any of the many available views -- the contract and flat contract of a class, its routines, its attributes, its clients, its ancestors, the ancestor and descendant versions of a feature, and so on -- then wherever you see a feature or class name follow the corresponding link. This '''proximity-based''' form of browsing, combined with the other techniques seen earlier, provides considerable help when you are dealing with a large, possibly complex system, and want to master its intricacies, be it for development, testing, debugging, maintenance or revision.
|
||||
|
||||
Other places where you can pick development objects include the icons representing classes and features in the Groups tool, Feature tool, and Favorites tool.
|
||||
|
||||
|
||||
==Semantic consistency==
|
||||
|
||||
An important property of the pick-and-drop mechanism, shared by its cousin the right-click mechanism, has already been mentioned in this chapter: semantic consistency, which guarantees that the operations you can perform on a class, such as pick-and-drop, only depend on the ''development object'' to which you are applying the operation. It doesn't matter where you picked the object -- in any development tool under any view -- and in what form: textual, as a class or feature name; graphical representation, as a class bubble in the Diagram tool; or an icon, for example in the Groups tool, Features tool, Favorites tool.
|
||||
|
||||
The pebble that you see during the Move step of Pick-and-Drop represents the underlying development object -- such as a class or a feature -- regardless of how you got to it.
|
||||
|
||||
|
||||
==Behind the Pick-and-Drop conventions==
|
||||
|
||||
Pick-and-Drop works differently from the usual Drag-and-Drop present on many computing platforms. The usual Drag-and-Drop retains a role within EiffelStudio (to move class bubbles around in the Diagram view) and you may of course have to use it for operating system functions such as copying files. But the key EiffelStudio operation is Pick-and-Drop. This technique is motivated by careful consideration of ergonomics and user comfort. In particular:
|
||||
* Pick-and-Drop is much less stressful. Drag-and-Drop requires you to maintain pressure throughout the move, being careful not to drop on the wrong place. With Pick-and-Drop there is no stress: you click and release; get a drop from your coffee cup if you like (optional step); move the cursor with no pressure from your fingers or on your mind; make sure, at your leisure, to find the right drop place; and right-click again on it. At the end of the day, after many such operations, the stress reduction can make a real difference.
|
||||
* With Drag-and-Drop, it's easy to lessen the pressure involuntarily and drop on the wrong place. The consequences can be damaging, especially since in such a case you may well <span>not know</span> where you dropped the element; after all, that wasn't intentional. It is possible, for example, to lose files that way. With Pick-and-Drop this is much less likely to happen.
|
||||
* Pick-and-Drop makes it easy to cancel the operation if you change your mind: just left-click anywhere. With Drag-and-Drop you have to find an invalid place to drop; this may be difficult, or even impossible! (Sometimes pressing the Escape key works, but this is not universal.)
|
||||
|
||||
If you are new to EiffelStudio you may find Pick-and-Drop surprising at first. We trust you will join the ranks of EiffelStudio users who consistently rate it among the most convenient features of the environment.
|
||||
|
||||
|
||||
==Pick-and-Drop miscellany==
|
||||
|
||||
When you start repeatedly retargeting the Class and Feature tools -- especially when set to "unlinked" behavior -- you will notice the following properties:
|
||||
* In most cases, pick-and-dropping a ''class'' into the lower pane where the Class and Feature tools are docked will switch the view to the Class tool, and pick-and-dropping a <span>feature</span> switches to the Feature tool. This is true even if the pane is currently set to the Outputs tool or another unrelated tool.
|
||||
* The view displayed in each case -- for example <code>Ancestors</code> for the ''Class'' tool and <code>Flat</code> for the ''Feature'' tool -- is default view for the corresponding tool.
|
||||
|
||||
You know by now that if you pick an object and drop in into the Editing tool it will retarget the Development Window and will evict the previous occupant of the current Editing tool tab and display the dropped object in that tab. But, you can also use Pick-and-Drop to create new tabs in the Editing tool. Instead of dropping into a tab, drop the pebble instead in the tab bar of the Editing tool next to existing tabs, or on the "New Tab" icon ([[Image:new-document-icon]]) in the Standard buttons toolbar.
|
||||
|
||||
|
||||
==The many paths to retargeting==
|
||||
|
||||
As a conclusion to this review of Pick-and-Drop let's recapitulate the various ways we've seen for retargeting a whole Development Window or a tool to a class:
|
||||
{| border="2"
|
||||
|-
|
||||
| '''How to retarget'''
|
||||
| '''Same window/tab/tool, or new?'''
|
||||
| '''Where described'''
|
||||
|-
|
||||
| Type class name, then Enter, in class field at top-left of tool
|
||||
| Same
|
||||
| [[Starting to Browse#Retargeting by name|"Retargeting by name" in the chapter "Starting To Browse".]]
|
||||
|-
|
||||
| Choose class in Cluster tree
|
||||
| Same
|
||||
| [[Starting to Browse#Retargeting from the Groups tool|"Retargeting from the Groups tool" in the chapter "Starting To Browse". ]]
|
||||
|-
|
||||
| Choose class in Favorites
|
||||
| Same
|
||||
| [[Starting to Browse#Adding to Favorites|"Adding to Favorites" in the chapter "Starting To Browse".]]
|
||||
|-
|
||||
| "Back" button
|
||||
| Same
|
||||
| [[Starting to Browse#Moving back and forth|"Moving back and forth" in the chapter "Starting To Browse".]]
|
||||
|-
|
||||
| "Forth" button
|
||||
| Same
|
||||
| [[Starting to Browse#Moving back and forth|"Moving back and forth" in the chapter "Starting To Browse".]]
|
||||
|-
|
||||
| Pick class from history list
|
||||
| Same
|
||||
| [[Starting to Browse#The Target History|"The Target History" in the chapter "Starting To Browse".]]
|
||||
|-
|
||||
| Pick-and-drop
|
||||
| Existing or new (depending upon drop target)
|
||||
| [[Retargeting Through Pick-and-Drop|Chapter "Retargeting Through Pick-and-Drop".]]
|
||||
|-
|
||||
| Control-right-click on class name or graphical representation found in any tool
|
||||
| New tab
|
||||
| [[Starting to Browse|"Starting a new tool" in the chapter "Starting To Browse".]]
|
||||
|}
|
||||
|
||||
|
||||
|
||||
179
documentation/18.11/eiffelstudio/Tutorials/starting-browse.wiki
Normal file
179
documentation/18.11/eiffelstudio/Tutorials/starting-browse.wiki
Normal file
@@ -0,0 +1,179 @@
|
||||
[[Property:title|Starting To Browse]]
|
||||
[[Property:weight|-10]]
|
||||
[[Property:uuid|cb6c2e52-d238-9b55-0b78-ab3af9568550]]
|
||||
It was important to take a look at how EiffelStudio stores your project, but unless your idea of fun is to poke around directories to look at compiler-generated files that's not really the exciting part yet. Among the most innovative aspects of EiffelStudio is a unique set of facilities to "browse" through a software system.
|
||||
|
||||
|
||||
==Browsing style==
|
||||
|
||||
Browsing -- traversing the structure -- is particularly important in object-oriented development and especially in Eiffel because of the speed at which you can construct sophisticated class structures, making use of inheritance, genericity, the client relation and information hiding, and subjecting features to all kinds of adaptations -- renaming, redefinition, undefinition, effecting -- that are key to the expressive power of the software, but call for smart tools to keep track of what's going on. EiffelStudio's tools are second to none. Among their key properties:
|
||||
* You can choose many different ways of browsing: sometimes you know the ''name'' of a class or feature, and will get to it just by typing it; sometimes you want to traverse the system through its cluster-subcluster ''structure''; often, you see a reference to element (class or feature) in the text of another element, and just want to get to it by following that reference, like a ''hyperlink''. You'll be able to use all these techniques, and alternate freely between them.
|
||||
* The browsing facilities are always available. There is no "browser" in EiffelStudio; you just browse when you want to, by looking at the information you need. You can do this while editing, debugging, or performing any other of the analysis, design, implementation, extension and maintenance tasks of system construction.
|
||||
* Although classes are stored in files and clusters in directories, you can for the most part forget about the file system. Unlike most environments, which let you manipulate files containing software texts, EiffelStudio lets you concentrate on your <span>development objects</span> -- the units that make sense for you: features, classes, clusters, systems. You think in terms of those conceptual units, and don't have to worry about where they are stored. Most of the time, you'll just forget about files and directories.
|
||||
* You can produce many views of the development objects. For a class, you may see the full text, the interface only, the inheritance structure, the clients, the features, and many other views. You can even display <span>graphical</span> views along with textual ones. All these are fully browsable; you can go from one to the other as you please.
|
||||
|
||||
|
||||
==A Development Window==
|
||||
|
||||
Let's see how this works. First, take a look at the EiffelStudio window:
|
||||
|
||||
|
||||
[[Image:es gt a development window 01]]
|
||||
|
||||
|
||||
{{note|If some parts are too small, just resize the window to arrive at something like what's on the figure. As soon as you have resized it, EiffelStudio will remember that size, and start up in the next session with the size you've set.}}
|
||||
|
||||
You can see that the bulk of the Development Window is divided into three primary panes or areas. The [[EiffelStudio Editor|'''Editing''']] tool is the large pane on the top left. The Editing tool supports a tabbed display of the elements in your system ... usually that's class text, and it's in the Editing tool that you make changes to your software. In the image above, it is targeted to the root cluster of our example system. We'll target the Editing tool to a class in a moment. The other two areas support multiple tools, also using a tabbed display. In the area below the Editing tool you see the '''Outputs''' tool currently selected. As you can see there are other tools represented by the tabs at the bottom of the same area. Likewise, the area to the right of the Editing tool shows the '''Groups''' tool selected, but in that area are also tabs for other tools. You will find that the layout of the Development Window is very flexible. Different tools can be made visible or hidden, panes can be removed, new panes created, tools can be docked in these areas or viewed as standalone windows. The appearance of EiffelStudio can be tailored to your needs and preferences.
|
||||
|
||||
So far we have talked about "the EiffelStudio window", but in fact that's not correct. What you see is one '''Development Window''', of which you can have as many as you wish. Some people prefer to use a single development tool, avoiding screen clutter; others don't think twice about having lots of windows, taking the "desktop metaphor" to its full conclusion (some non-computer desktops are quite cluttered). There are many ways to start a new Development Window; for example if you look at the entries in the <code>File</code> menu at the top left -- don't select any of these entries yet, just look -- you'll see, among others, <code>New window</code>, which would create a new Development Window.
|
||||
|
||||
Whether you have one Development Window or many, each may have as its '''target''' an element of the system: system, cluster, class (the most common case), feature, run-time object. This simply means that the tool displays information about that element.
|
||||
|
||||
|
||||
==Retargeting by name==
|
||||
|
||||
In our first look at the Development Window, the Editing tool was empty. To target it to a specific class, you can just type the class name -- if you know it -- into the '''Class field''' at the top left:
|
||||
|
||||
|
||||
[[Image:es gt class field 01]]
|
||||
|
||||
|
||||
Let's use one of the most basic classes, <code>STRING_32</code> from the Kernel Library of EiffelBase. Bring the cursor to the Class Field, click to make it active, type <code>string_32</code> (or <code>STRING_32</code> ) and the Enter key. As shown on the next figure, this causes a new tab to be created in the Editing tool and retargets the Development Window to class <code>STRING_32</code>. Note that you didn't have to worry about where the class resides in the files of your computer. Also, it doesn't matter, when you enter the name into the field, whether you use lower or upper case, or some mix; EiffelStudio will show the name in all upper case because that is the standard Eiffel convention for class names.
|
||||
|
||||
|
||||
[[Image:es gt string 01]]
|
||||
|
||||
|
||||
Retargeting by name is only one way to retarget a Development Window. There are other ways of retargeting that are useful at different times. Let's look at some of them.
|
||||
|
||||
|
||||
==Retargeting from the Groups tool==
|
||||
|
||||
Your first browsing action used a class of which you knew the name, <code>STRING</code>. What if you don't know what's in the system and want to explore it? Among other techniques, you can let the Groups tool, guide you through the classes that are available to your system.
|
||||
|
||||
An Eiffel system, as you know, is organized into clusters and libraries (and assemblies on some .NET systems). Additionally, clusters can be structured hierarchically into subclusters. You can expand the clusters and libraries nodes in the Groups tool (by clicking the little <code>+</code> signs to the left of the node icons) in order to see the classes. Try it, and what you see should look about like the following figure:
|
||||
|
||||
[[Image:es gt groups tool 01]]
|
||||
|
||||
|
||||
You'll see one cluster: <code>root_cluster</code>, containing the few classes specific to our Guided Tour system. Under libraries you'll see <code>base</code> which provides the classes of the EiffelBase library, and <code>base_precompile</code> which does not provide any classes directly (precompiles are present to speed up compilation time by precompiling classes, so <code>base_precompile</code> is just a precompiled version of the contents of the EiffelBase library). Let's go into <code>base</code>, Eiffel Software's open-source library of fundamental reusable mechanisms.
|
||||
|
||||
The most extensive subcluster of the EiffelBase library is <code>structures</code>, which contains implementations of major data structures and algorithms of computing science. Expand <code>structures</code> to see its own subclusters:
|
||||
|
||||
[[Image:es gt groups tool 02]]
|
||||
|
||||
{{note|If you initially don't see as many details as shown on this figure, you may get them by resizing the window, moving the vertical pane boundary, and/or scrolling.}}
|
||||
|
||||
The EiffelBase Data Structure library and its subclusters are described in the book [http://www.eiffel.com/services/training/books.html Reusable Software]. Let's go to one of the most frequently used subclusters, <code>list</code>, containing implementations of list structures. Expand the subcluster <code>list</code>. This time, since list is a terminal cluster, it's not subclusters you'll see, but '''classes''', identified by small ellipses ([[Image:class-normal-icon]]):
|
||||
|
||||
[[Image:es gt groups tool 03]]
|
||||
|
||||
The ellipse, or "bubble", is indeed throughout EiffelStudio, as in the Business Object Notation (BON, the underlying graphical convention), the distinctive symbol for classes. You will notice that instead of the bubble, some classes are represented by what we call the "expanded" icon ([[Image:expanded-normal-icon]] ). These are still Eiffel classes. They are represented this way to show that they are marked as [[I2E: Types|expanded]]. Still other classes have a modified bubble ( [[Image:class-deferred-icon]] ) indicating that they are marked as [[ET: Inheritance#Deferred features and classes|deferred]].
|
||||
|
||||
Our second technique for retargeting a Development Window to a class (other than typing the class name as we did before) is to click the class in the Groups tool. Do this now: click <code>LIST</code> in the tree. It doesn't matter whether you click on the class name or the adjacent bubble. This retargets the tool to class <code>LIST</code>.
|
||||
|
||||
[[Image:es gt Development Window targeted to list 01]]
|
||||
|
||||
|
||||
As the tool is now targeted to <code>LIST</code>, the Class Field at the top left now shows the name of that class, exactly as if we had typed that name, the way we did with <code>STRING_32</code> in the previous method of retargeting.
|
||||
|
||||
|
||||
==Moving back and forth==
|
||||
|
||||
Here now is a third way to retarget. Towards the top-left part of the Development Window there are <code>Back</code> and <code>Forth</code> buttons, which will enable you to revisit classes already seen during the current session:
|
||||
|
||||
[[Image:es gt go back 01]]
|
||||
|
||||
Click the <code>Back</code> button. This retargets the tool to the class you visited previously: <code>STRING_32</code>. The <code>Forth</code> button, immediately to the right of <code>Back</code>, becomes active. Click it to retarget back to <code>LIST</code>.
|
||||
|
||||
Note that all buttons of the interface have a "tooltip" as shown in the figure above. if you move the cursor on a button, '''without clicking''', and wait a second or so, a small message comes up, explaining the purpose of the button. Also, if there is an associated keyboard shortcut, it will be displayed in the tooltip.
|
||||
|
||||
|
||||
==The Target History==
|
||||
|
||||
As a fourth way to retarget -- there are more, and after this one we'll stop counting -- you can also use the Target History menu, which you can bring up through the little arrow to the right of the Class Field:
|
||||
|
||||
[[Image:es gt target history 01]]
|
||||
|
||||
If you click this arrow -- the little black triangle -- you will see a menu of all your recent targets. Doing this now will only show the two classes visited so far, <code>STRING_32</code> and <code>LIST</code>, but later on there will be more entries. By default EiffelStudio remembers 20 history entries; this is one of the settings you can change later if you wish, through the menu path:
|
||||
<code lang=text>
|
||||
Tools --> Preferences
|
||||
</code>
|
||||
But, let's don't do that now.
|
||||
|
||||
|
||||
==Adding to Favorites==
|
||||
|
||||
If you find yourself often needing to examine a particular class, you can add it to your [[Favorites tool|Favorites]], much like adding an interesting page's web link to the bookmarks of a Web browser.
|
||||
|
||||
It's easy to add the current target -- currently, <code>LIST</code> -- to your Favorites. Do it now by following the menu path:
|
||||
<code lang="text">
|
||||
Favorites --> Add to Favorites
|
||||
</code>
|
||||
|
||||
[[Image:es gt add to favorites 01]]
|
||||
|
||||
Now display the favorites; one way is to go back to that same Favorites menu:
|
||||
<code lang="text">
|
||||
Favorites --> Favorites
|
||||
</code>
|
||||
The Favorites tool appears as a tab in the same area as the Groups tool:
|
||||
|
||||
[[Image:es gt favorites 01]]
|
||||
|
||||
This gives us one more way to retarget a Development Window: click a class in the Favorites tool. ''Two'' ways actually, because once you add a class to Favorites, it appears in the Favorites menu and you can select it by choosing its menu item.
|
||||
|
||||
[[Image:es gt list added to favorites 01]]
|
||||
|
||||
Right now we don't need the Favorites tool, so you can get rid of it by clicking the little Close icon at the top right of the Favorites pane:
|
||||
|
||||
[[Image:es gt close favorites 01]]
|
||||
|
||||
|
||||
After you close the Favorites tool, you may see some tool other than the Groups tool that we had been using. If this is the case, click on the Groups tool's tab at the bottom of the pane to make the library classes visible again.
|
||||
|
||||
|
||||
==Using additional Editing tool tabs==
|
||||
|
||||
So far, even though we've targeted to the Development Window to different classes, we've only used one Editor tab. But it is helpful sometimes to have views of several classes handy in multiple editor tabs. Its easy enough to create a new tab at the time that you target the Development Window to a new class. For example, you should see the class <code>CHAIN</code> in the Groups tool's view of the the <code>list</code> subcluster of <code>structures</code> (the same place we found class <code>LIST</code>. Instead of clicking on <code>CHAIN</code> the way we did <code>LIST</code>, this time '''control-right-click''' on <code>CHAIN</code>, that is to say, click with the rightmost button of the mouse while holding the CONTROL key on the keyboard. This creates a new tab for <code>CHAIN</code> and retargets the Development Window to that class, while sliding the existing tab for class <code>LIST</code> to the right a bit.
|
||||
|
||||
|
||||
[[Image:es gt development window multiple tabs 01]]
|
||||
|
||||
|
||||
You can click on any of the tabs and the Development Window will be retargeted to the class associated with the tab. Each tab has a "Close" button on it, so you can close tabs you no longer need.
|
||||
|
||||
So, for now, close the tab with the class <code>CHAIN</code> and leave just the one tab with class <code>LIST</code>.
|
||||
|
||||
==Using additional Development Windows==
|
||||
|
||||
With all the techniques seen so far, you were able to retarget the current the Development Window to a new class. And that may be all you'll ever need. But, as noted earlier, you may also wish to have two or more Development Windows active simultaneously.
|
||||
|
||||
To create a new Development Window, follow the menu path:
|
||||
<code lang="text">
|
||||
File --> New Window
|
||||
</code>
|
||||
This will create a new Development Window with a title bar that reads "<code lang=text>Empty development tool #1</code>" because the window is (as yet) untargeted. You can also create a new Development Window by using the keyboard accelerator: <code>CTRL-N</code>.
|
||||
|
||||
You can close a Development Window either by clicking its close button in the corner of the window, or by following the menu path:
|
||||
<code lang="text">
|
||||
File --> Close Window
|
||||
</code>
|
||||
|
||||
Be careful not to try to use:
|
||||
<code lang="text">
|
||||
File --> Exit
|
||||
</code>
|
||||
to close a single window. This menu command will exit the entire EiffelStudio development environment, closing all windows.
|
||||
|
||||
If, during a session, you end up with a number of windows active and want to see an active index to them, you can invoke the [[Windows tool|active windows tool]] by following the menu path:
|
||||
<code lang="text">
|
||||
View--> Tools--> Active windows
|
||||
</code>
|
||||
|
||||
[[Image:es gt active windows tool 01]]
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
[[Property:title|Starting EiffelStudio and Opening a Project]]
|
||||
[[Property:weight|-13]]
|
||||
[[Property:uuid|676cf329-5640-69c4-d10b-b56fcd3f2ff9]]
|
||||
In the rest of this Tour <code>YOURDIR</code> denotes the directory where the example resides (the original, <code>$ISE_EIFFEL/examples/studio/tour</code> , or a copy). Launching will use the operating system's mechanism for starting a program, so we look separately at Windows and at Unix/OpenVMS.
|
||||
|
||||
|
||||
==Launching EiffelStudio under Window==
|
||||
|
||||
On Windows, you can launch EiffelStudio from the Start Menu by following the path:
|
||||
<code lang="text">
|
||||
Start --> Programs --> EiffelStudio Version --> EiffelStudio
|
||||
</code>
|
||||
|
||||
where <code>Version</code> is the version number, e.g. 6.5. Alternatively, you can double-click the icon that the installation procedure will have added to your desktop (if you have selected that option during installation).
|
||||
|
||||
If this is the first time you are using EiffelStudio, you may get a dialog asking for an unlock code or inviting you to register the product. See [[Software Installation for EiffelStudio|your platform installation instructions]] for registration information.
|
||||
|
||||
|
||||
==Launching EiffelStudio under Unix or OpenVMS==
|
||||
|
||||
To launch EiffelStudio on Unix or OpenVMS, change directory to <code>YOURDIR</code> and, from the command line, type
|
||||
<code lang="text">
|
||||
estudio
|
||||
</code>
|
||||
|
||||
In general you can start EiffelStudio from any directory, but to make things simple for this Tour '''please make sure''' indeed to execute the <code>estudio</code> command from <code>YOURDIR</code>. (This will allow us to use relative rather than absolute names for some of the files involved.)
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,137 @@
|
||||
[[Property:title|Using automatic class licensing]]
|
||||
[[Property:weight|2]]
|
||||
[[Property:uuid|3abb5fc8-b5e5-2d25-fcac-72929abba0a7]]
|
||||
You can use EiffelStudio to include a license text in each of your classes automatically. The automatic class licensing facility is flexible so that you can use various strategies to retrieve the license text used.
|
||||
|
||||
When you save the text of a class file in EiffelStudio, the automatic licensing facility searches for an appropriate license text file to use. If such a file is found, then EiffelStudio includes the contents of that file as an ending <code>note</code> part in your class. Here's the text of a class that includes an Eiffel Software license:
|
||||
|
||||
<code>
|
||||
class
|
||||
APPLICATION
|
||||
|
||||
inherit
|
||||
ARGUMENTS
|
||||
|
||||
create
|
||||
make
|
||||
|
||||
feature {NONE} -- Initialization
|
||||
|
||||
make
|
||||
-- Run application.
|
||||
do
|
||||
print ("Hello Eiffel World!%N")
|
||||
end
|
||||
|
||||
note
|
||||
copyright: "Copyright (c) 1984-2010, Eiffel Software"
|
||||
copying: "[
|
||||
Duplication and distribution prohibited. May be used only with
|
||||
Eiffel Software products, under terms of user license.
|
||||
Contact Eiffel Software for any other use.
|
||||
]"
|
||||
source: "[
|
||||
Eiffel Software
|
||||
5949 Hollister Ave., Goleta, CA 93117 USA
|
||||
Telephone 805-685-1006, Fax 805-685-6869
|
||||
]"
|
||||
end
|
||||
</code>
|
||||
|
||||
|
||||
==License file format==
|
||||
|
||||
License text should appear in a text file with the file type "<code lang="text">.lic</code>". The text should contain the <code>note</code> clause which includes the license text and nothing more. EiffelStudio will parse the text and invalid instances of license text will not be merged into the target class.
|
||||
|
||||
The following text is the content of the license text file which was used to annotate the class shown above:
|
||||
|
||||
<code>
|
||||
${NOTE_KEYWORD}
|
||||
copyright: "Copyright (c) 1984-${YEAR}, Eiffel Software"
|
||||
copying: "[
|
||||
Duplication and distribution prohibited. May be used only with
|
||||
Eiffel Software products, under terms of user license.
|
||||
Contact Eiffel Software for any other use.
|
||||
]"
|
||||
source: "[
|
||||
Eiffel Software
|
||||
5949 Hollister Ave., Goleta, CA 93117 USA
|
||||
Telephone 805-685-1006, Fax 805-685-6869
|
||||
]"
|
||||
</code>
|
||||
|
||||
Notice that a variable is used for the <code>note</code> keyword (to support the language keyword change from <code>indexing</code> to <code>note</code>). Also a variable for the current year is used in the copyright notice.
|
||||
|
||||
|
||||
==Location of license text files==
|
||||
|
||||
Where you keep your license text files depends upon which method you use to have EiffelStudio retrieve the license text from the files. Generally, license text is retrieved from files in one of three places:
|
||||
|
||||
===Your project directory===
|
||||
This is the directory that contains your project configuration file, the "<code lang="text">.ecf</code>" file).
|
||||
|
||||
[[Image:Automatic class license project directory]]
|
||||
|
||||
===The Eiffel Software license template directory===
|
||||
This directory is located at: <code lang="text">$ISE_EIFFEL/studio/templates/licenses</code>
|
||||
|
||||
[[Image:Automatic class license Eiffel Software directory]]
|
||||
|
||||
===The Eiffel user files license template directory===
|
||||
This directory is located at: <code lang="text">$ISE_USER_FILES/studio/templates/licenses</code>
|
||||
|
||||
[[Image:Automatic class license Eiffel user files directory]]
|
||||
|
||||
|
||||
==Methods of retrieval==
|
||||
|
||||
===Designating a license in class source code===
|
||||
|
||||
You can put a note in the source code of a class which will cause EiffelStudio to search for a corresponding license file and then include the license text from that file. Here's what such a note might look like:
|
||||
|
||||
<code>
|
||||
note
|
||||
license_name: "OurLicense"
|
||||
</code>
|
||||
|
||||
The <code lang="text">license_name</code> term should be placed in the top <code>note</code> clause of the class. (If you include in the bottom <code>note</code> clause, the <code>license_name</code> term itself will be removed when the class license gets replaced.)
|
||||
|
||||
In this case, EiffelStudio will search for the file `<code lang="text">OurLicense.lic</code>'. It will look first in the '''Eiffel user files license template directory''', then in the '''Eiffel Software license template directory'''.
|
||||
|
||||
If you look in the '''Eiffel Software license template directory''' (or in the image of that directory shown above), you will see several standard license files that are used by Eiffel Software, for example, <code lang="text">forum2.lic</code> and <code lang="text">eiffelsoftware</code>. Also included is <code lang="text">default.lic</code>, which we'll examine [[#The default license|later]].
|
||||
|
||||
You should create your customized license text files in the '''Eiffel user files license template directory''', or in a local project directory as described below.
|
||||
|
||||
|
||||
===Using a local project license file===
|
||||
|
||||
If you use the same license for a particular project, or set of related projects, you can keep the license file in the project directory along with your project ( <code lang="text">.ecf</code> ) file. In this case EiffelStudio will include the license text from that license file in each class in the project.
|
||||
|
||||
This method has the advantage that it is not necessary to put the <code lang="text">license_name</code> term in the source code of classes.
|
||||
|
||||
The license text file should be named in one of two ways:
|
||||
|
||||
:# The <code lang="text">.lic</code> file name corresponds to the project name (e.g., <code lang="text">my_project.lic</code> for <code lang="text">my_project.ecf</code>)
|
||||
:# The license text file is named <code lang="text">license.lic</code>
|
||||
|
||||
The second option is convenient if you have a project, a library for instance, that has multiple <code lang="text">.ecf</code> files for different purposes.
|
||||
|
||||
Even if the license text you want to use is in one of the license template directories, you can use this local method to retrieve that text without including a <code lang="text">license_name</code> term in the source code for each class. You do this by building a local license text file and include in it only a reference to the appropriate license name.
|
||||
|
||||
For example, suppose that the our license text is in the file <code lang="text">OurLicense.lic</code> in the '''Eiffel user files license template directory'''. To include the license text in the classes of <code lang="text">our_project</code>, the <code lang="text">our_project.lic</code> (or <code lang="text">license.lic</code>) file would contain this reference:
|
||||
|
||||
<code lang="text">
|
||||
reference:OurLicense
|
||||
</code>
|
||||
|
||||
|
||||
===The default license===
|
||||
|
||||
As mentioned earlier, the file <code lang="text">default.lic</code> exists in the '''Eiffel Software license template directory'''. This file is empty ... and you should probably leave it that way.
|
||||
|
||||
The license text in <code lang="text">default.lic</code> is added to a class when no <code lang="text">license_name</code> term is found in the source code and no appropriate license text file exists in the project directory. So, because the <code lang="text">default.lic</code> file is empty, no license text is added to classes by default.
|
||||
|
||||
However, if you would like to set up a different default license text behavior, you can do so. Just create a <code lang="text">default.lic</code> file in the '''Eiffel user files license template directory''', and whenever license text is not found by some other method, the text from your customized <code lang="text">default.lic</code> will be included.
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,323 @@
|
||||
[[Property:title|Create a manual test]]
|
||||
[[Property:weight|2]]
|
||||
[[Property:uuid|32273F6B-AA84-475F-86B8-143F212FB40E]]
|
||||
==A system to test==
|
||||
|
||||
For developing our manual test, let's use a simple system that contains a class modeling bank accounts. Here are two classes that will make up our system. The first, <code>APPLICATION</code> will be the root class of our system. <code>APPLICATION</code> really only serves to declare an attribute of type <code>BANK_ACCOUNT</code>, which is the class we will write a test against. <code>APPLICATION</code> looks like this:
|
||||
|
||||
<code>
|
||||
class
|
||||
APPLICATION
|
||||
|
||||
inherit
|
||||
ARGUMENTS
|
||||
|
||||
create
|
||||
make
|
||||
|
||||
feature {NONE} -- Initialization
|
||||
|
||||
make
|
||||
-- Run application.
|
||||
do
|
||||
create my_account
|
||||
end
|
||||
|
||||
my_account: BANK_ACCOUNT
|
||||
|
||||
end
|
||||
</code>
|
||||
|
||||
|
||||
And here's the class <code>BANK_ACCOUNT</code>:
|
||||
|
||||
<code>
|
||||
class
|
||||
BANK_ACCOUNT
|
||||
inherit
|
||||
ANY
|
||||
redefine
|
||||
default_create
|
||||
end
|
||||
feature
|
||||
default_create
|
||||
do
|
||||
balance := 0
|
||||
end
|
||||
|
||||
balance: INTEGER
|
||||
|
||||
deposit (an_amount: INTEGER)
|
||||
-- Deposit `an_amount'.
|
||||
require
|
||||
amount_large_enough: an_amount > 0
|
||||
do
|
||||
ensure
|
||||
balance_increased: balance > old balance
|
||||
deposited: balance = old balance + an_amount
|
||||
end
|
||||
|
||||
withdraw (an_amount: INTEGER)
|
||||
-- Withdraw `an_amount'.
|
||||
require
|
||||
amount_large_enough: an_amount > 0
|
||||
amount_valid: balance >= an_amount
|
||||
do
|
||||
balance := balance - an_amount
|
||||
ensure
|
||||
balance_decreased: balance < old balance
|
||||
withdrawn: balance = old balance + an_amount
|
||||
end
|
||||
|
||||
invariant
|
||||
balance_not_negative: balance >= 0
|
||||
end
|
||||
</code>
|
||||
|
||||
You shouldn't let it worry you if you've noticed that the class <code>BANK_ACCOUNT</code> contains some flaws. We'll deal with these later.
|
||||
|
||||
If you want to work along with this tutorial, you should be able to copy the text of each these classes from this page and paste it into the EiffelStudio editor pane. Build a system using these two classes, and <code>{APPLICATION}.make</code> as the root.
|
||||
|
||||
|
||||
{{note|If you are using EiffelStudio version 6.3, there two things you will need to do to prepare your system for use with AutoTest. Both of these are done from the [[EiffelStudio: Project settings window]].<br/> 1) Set your project to be a console application in the [[Advanced options]].<br/>2) Set a value of <code>False</code> for the <code>Recursive</code> attribute of your project cluster in [[Group options]].}}
|
||||
|
||||
==Getting to the AutoTest interface==
|
||||
|
||||
If the AutoTest interface is not on a tab next to Clusters, Features, and Favorites, you can invoke it by following the menu path:
|
||||
<code lang=text>
|
||||
View --> Tools --> AutoTest
|
||||
</code>
|
||||
Depending upon your version and platform, the AutoTest interface should look about like this:
|
||||
|
||||
|
||||
[[Image:AutoTest empty tool 01]]
|
||||
|
||||
|
||||
==Creating a new test==
|
||||
|
||||
To begin the process of creating a new test, click the Create New Test button ( [[Image:create new tests]] ) on the interface's tool bar. When you click this button, by default AutoTest will set you up to create a new Manual test. To choose a different test type, click the small triangle to the right of the Create New Test button and you'll be presented with a drop-down menu of choices:
|
||||
|
||||
|
||||
[[Image:AutoTest create new test|Create new test drop-down menu]]
|
||||
|
||||
|
||||
For now, let's select Create Manual Test.
|
||||
|
||||
If this is the first time you've used the testing tool for this project, it is likely that you will be presented with a dialog box asking if you want to add the testing library classes to your project and recompile:
|
||||
|
||||
|
||||
[[Image:AutoTest add testing libraries dialog]]
|
||||
|
||||
You want EiffelStudio to do this before launching the wizard so, click "Yes". In a moment, your system will have recompiled with the testing library classes available. Remember that you won't need to interact much with the testing classes, but AutoTest uses them, so they need to be available. As long as the testing classes stay available, you should not see this dialog again for the current project.
|
||||
|
||||
|
||||
==The Manual Test Pane==
|
||||
|
||||
After the compile completes, then the first pane of the New Eiffel Test Wizard appears. It's the Manual Test pane and should look like this:
|
||||
|
||||
|
||||
[[Image:AutoTest Manual Test pane]]
|
||||
|
||||
|
||||
Here we will name our test. Let's say that we plan to write this test against the feature <code>{BANK_ACCOUNT}.deposit</code>. We'll give this test the name <code>test_deposit_01</code>. The name uses an ad hoc naming convention for tests. You can use this, or develop your own. The prefix <code>test_</code> comes before the feature name it will test, and the suffix <code>_01</code> follows, so that we have a framework for adding more tests against <code>deposit</code>. Again, you can choose any naming scheme that makes sense to you. You may want to try to describe the test in its name. For example, <code>test_deposit_very_large_amount</code>.
|
||||
|
||||
We're ready to click '''Next''', but before we do, let's look at the check boxes on this wizard pane. The two check boxes labeled '''Redefine `on_prepare`''' and '''Redefine `on_clean`''' have to do with the way that tests are run.
|
||||
|
||||
AutoTest runs each test as a three step process:
|
||||
# Preparation
|
||||
# Execution
|
||||
# Clean up
|
||||
|
||||
There are features in class <code>EQA_TEST_SET</code> named <code>prepare</code> and <code>clean</code> which accomplish steps 1 and 3 above. These features are <code>frozen</code>, therefore you cannot redefine them in a test class (i.e., a descendant of <code>EQA_TEST_SET</code>) However the class does provide features that can be redefined so that you can include custom behavior before and/or after the execution of a test. These features are <code>on_prepare</code> and <code>on_clean</code>. So if you check one of these boxes, then the test class that is built for you will include a redefined feature ready for you to implement. In this simple example, we'll leave both boxes unchecked.
|
||||
|
||||
|
||||
{{note|The check box labeled '''System level test''' is displayed here as not sensitive. This box is reserved for future system level testing capability in AutoTest, so for versions including 7.0, you can ignore it. }}
|
||||
|
||||
|
||||
Another thing to notice before we click '''Next''', is that at this point we could click '''Launch'''. '''Launch''' will immediately try to create the test with the information it has available. The idea is that if you are creating several similar tests, you can change the test routine name and leave the rest of the information as you had entered it on a previous test. This keeps you from having to traverse the wizard panes entering the same information repeatedly.
|
||||
|
||||
But in our case, we need to use the subsequent wizard panes, so let's click '''Next''', to go to the next one.
|
||||
|
||||
|
||||
==The Tags Pane==
|
||||
|
||||
|
||||
[[Image:AutoTest Tags pane empty|Tags pane]]
|
||||
|
||||
|
||||
With this pane, you identify tags for your test that allow you to manage your test set more easily in the future. Read more in [[#About Tags|About Tags]] below.
|
||||
|
||||
For this test, we will include only a tag that identifies the class and feature covered by the test. To do this we click '''Add tag for covered class/feature'''. When we do, we are presented with a dialog in which we can choose a class and feature.
|
||||
|
||||
|
||||
[[Image:Autotest test coverage tag dialog|Dialog for coverage tag]]
|
||||
|
||||
|
||||
We'll choose class <code>BANK_ACCOUNT</code> and feature <code>deposit</code>, click '''OK'''.
|
||||
|
||||
Now you should see the coverage tag in the list of '''Tags used in new test'''.
|
||||
|
||||
|
||||
[[Image:AutoTest Tags pane|Tags pane]]
|
||||
|
||||
|
||||
That takes care of adding our coverage tag, so let's click '''Next''' to go to the next wizard pane, the '''General''' pane.
|
||||
|
||||
|
||||
==The General Pane==
|
||||
|
||||
|
||||
[[Image:AutoTest General pane empty|The General Pane]]
|
||||
|
||||
|
||||
We will use this wizard pane to name our test class and let AutoTest know where we want the test class to reside. You can give a test class any name you wish, as long as it doesn't conflict with another class name in your system. If you try to type in a class name that already exists, the wizard will let you know right away by changing the text color to red. There is a convention that has arisen around test class names. If possible, make the test class name the name of the target class, prefixed with <code>TEST_</code>. So in our case, we want to build a test against a feature of the <code>BANK_ACCOUNT</code> class, so we will name our test class <code>TEST_BANK_ACCOUNT</code>.
|
||||
|
||||
Now, for the question of where the tests should be kept.
|
||||
|
||||
By default, tests will be stored in a subdirectory of the EIGENs directory that is generated by the Eiffel compiler. Because it's the default, it's the quickest, easiest way to house tests. But it may not be the best for you in the long run. For example, if you manually delete the EIFGENs directory, which is occasionally necessary, you will lose your tests.
|
||||
|
||||
You could include them in the same cluster as some of your application classes. But there are some advantages to keeping the test classes in a '''test cluster''' separate from your target classes. For example, it will be easier for you to deliver your application or library classes if the testing classes aren't mixed with your domain classes. A '''test cluster''' is just a cluster of classes that EiffelStudio and AutoTest expect to contain test classes. So, in our case, let's create a new testing cluster as a subcluster of the cluster in which the classes <code>APPLICATION</code> and <code>BANK_ACCOUNT</code> reside.
|
||||
|
||||
First, uncheck the box labeled '''Use EIFGENs cluster'''.
|
||||
|
||||
Notice the '''New cluster''' link on the General pane. We click that link to add a new test cluster. The '''Add Cluster''' dialog box appears:
|
||||
|
||||
|
||||
[[Image:AutoTest Add Cluster dialog]]
|
||||
|
||||
|
||||
We can name our test cluster <code>tests</code>, the default, and make it a subcluster to our root cluster <code>accounts</code>. Notice that there is a '''test cluster''' check box on the dialog. It is checked and disabled, so at this point in the wizard you would always create a test cluster. Let's also check the box labeled '''recursive'''. Once the test cluster is created, we're back to the General pane which now looks like this:
|
||||
|
||||
|
||||
[[Image:AutoTest General pane]]
|
||||
|
||||
|
||||
At this point we have provided all the information necessary for AutoTest to create the shell for a manual test on the <code>deposit</code> feature of the <code>BANK_ACCOUNT</code> class.
|
||||
|
||||
So, now we click '''Launch''', and AutoTest creates our test set and test.
|
||||
|
||||
|
||||
|
||||
==Writing a test==
|
||||
|
||||
Let's look at the class <code>TEST_BANK_ACCOUNT</code>:
|
||||
|
||||
<code>
|
||||
note
|
||||
description: "[
|
||||
Eiffel tests that can be executed by testing tool.
|
||||
]"
|
||||
author: "EiffelStudio test wizard"
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
testing: "type/manual"
|
||||
|
||||
class
|
||||
TEST_BANK_ACCOUNT
|
||||
|
||||
inherit
|
||||
EQA_TEST_SET
|
||||
|
||||
feature -- Test routines
|
||||
|
||||
test_deposit_01
|
||||
-- New test routine
|
||||
note
|
||||
testing: "covers/{BANK_ACCOUNT}.deposit"
|
||||
do
|
||||
assert ("not_implemented", False)
|
||||
end
|
||||
|
||||
end
|
||||
</code>
|
||||
|
||||
We can see that the feature <code>test_deposit_01</code> exists, but doesn't really test anything. So, let's change that. We'll alter <code>test_deposit_01</code> so that it creates an instance of <code>BANK_ACCOUNT</code> and then makes a deposit to that account.
|
||||
|
||||
So, <code>test_deposit_01</code> now looks like this:
|
||||
|
||||
<code>
|
||||
test_deposit_01
|
||||
-- New test routine
|
||||
note
|
||||
testing: "covers/{BANK_ACCOUNT}.deposit"
|
||||
local
|
||||
l_ba: BANK_ACCOUNT
|
||||
do
|
||||
create l_ba
|
||||
l_ba.deposit (500)
|
||||
end
|
||||
</code>
|
||||
|
||||
Now we have created and written a manual test using AutoTest.
|
||||
|
||||
Next let's look into the notion of '''Tags''' in a little more detail, then see what it takes to execute a test.
|
||||
|
||||
|
||||
==About Tags==
|
||||
|
||||
The '''Tags''' pane allows us to associate our test with any AutoTest '''tags''' that we feel are appropriate.
|
||||
|
||||
'''Tags''' are simply names or otherwise meaningful strings of characters that are arranged hierarchically and can be associated with a test to help manage, maintain, execute, and monitor its results. Any one test can support many tags. It is quite likely that during the development process, your system may eventually accumulate a great number of tests. And you may want only to execute some selected portion of those tests at any particular time. '''Tags''' allow you do that with the help of AutoTest.
|
||||
|
||||
One of the most common types of tags specifies what class and feature a test covers. In our example, we wrote our test against the <code>deposit</code> procedure of the class <code>BANK_ACCOUNT</code>. The tag that we added to express this is:
|
||||
<code>
|
||||
covers/{BANK_ACCOUNT}.deposit
|
||||
</code>
|
||||
When we look at a tag in this notation, each hierarchical level is delimited by the forward slash. So the tag above specifies a root "covers" and its child "{BANK_ACCOUNT}.deposit". If this same test tested both <code>deposit</code> and <code>withdraw</code>, then its list of tags would be:
|
||||
<code>
|
||||
covers/{BANK_ACCOUNT}.deposit
|
||||
covers/{BANK_ACCOUNT}.withdraw
|
||||
</code>
|
||||
So when ever you ask to view or run all the tests that <code>covers</code> either <code>deposit</code> or <code>withdraw</code>, this test would show up in that set.
|
||||
|
||||
The "covers" tags, as you saw earlier, can be generated by AutoTest's New Eiffel Test Wizard when you create a new test. But you could enter the tag manually, as well. For example if you had written a high-level test that exercised all or most of the functionality of the class <code>BANK_ACCOUNT</code>, you could manually add a tag that expresses that, i.e., a "covers" tag for <code>BANK_ACCOUNT</code> that does not specify a particular routine:
|
||||
<code>
|
||||
covers/{BANK_ACCOUNT}
|
||||
</code>
|
||||
|
||||
Tags can be completely arbitrary, too. So, for example if you were building software that you expected to run on multiple platforms, in the test suite, you might have a test with the following tags:
|
||||
<code>
|
||||
platform/os/linux
|
||||
platform/architecture/i386
|
||||
</code>
|
||||
So this test would be specifically for Linux running on Intel architecture. When you were testing on that platform combination, you could select the appropriate tests to run using tags.
|
||||
|
||||
|
||||
===Associating tags with a new test===
|
||||
|
||||
Looking again at the '''Tags''' pane, you will see that there are two boxes under the label '''Tags used in new test'''. The first is just a display of the list of tags that you have added to the new test. The next box down allows you to add an arbitrary tag sequence like:
|
||||
<code>
|
||||
platform/os/linux
|
||||
</code>
|
||||
Below that box, there are links that allow you to add certain commonly used or predefined tag types. One of these, '''Add tag for covered class/feature''' is the link we used to add the "covers" tag for our test on <code>{BANK_ACCOUNT}.deposit</code>.
|
||||
|
||||
|
||||
===Other predefined tags===
|
||||
|
||||
In addition to '''Add tag for covered class/feature''', choices for other predefined tags are shown as links. For example, '''Add tag to run test in private evaluator''' and '''Add tag to run test serially'''.
|
||||
|
||||
Selecting '''Run test in private evaluator''' will insert the tag:
|
||||
<code>
|
||||
execution/isolated
|
||||
</code>
|
||||
|
||||
When tests are executed, they do so within the context of '''evaluator processes'''. Normally, evaluator processes are reused for multiple test executions. But if you select '''Run in private evaluator''', the tag added to your test guarantees that this test will be run in a fresh evaluator process, that terminates when the test completes. This can be helpful, for example, when you don't want your test to enter or leave the evaluator process with the effects of "once" routines or any other action that might affect the efficacy of other tests. For example, if your test executes external routines which might have a damaging effect on memory, you should run the test in a private evaluator.
|
||||
|
||||
If you select '''Run test serially''', the following tag will be inserted:
|
||||
<code>
|
||||
execution/serial
|
||||
</code>
|
||||
|
||||
Tests tagged with this tag will not run concurrently with any other similarly tagged test is running.
|
||||
|
||||
You can extend the serial execution tag with arbitrary terms that will differentiate groups of tagged tests. For example, if some of your tests are tagged like this:
|
||||
<code>
|
||||
execution/serial/group_1
|
||||
</code>
|
||||
and some are tagged:
|
||||
<code>
|
||||
execution/serial/group_2
|
||||
</code>
|
||||
then AutoTest will not run any <code>group_1</code> tagged test concurrently with any other <code>group_1</code> test, and likewise for tests tagged <code>group_2</code>.
|
||||
|
||||
|
||||
@@ -0,0 +1,110 @@
|
||||
[[Property:title|Execute tests]]
|
||||
[[Property:weight|3]]
|
||||
[[Property:uuid|d0515cb1-0792-3028-2a24-a71b56506959]]
|
||||
In the previous section we coded a manually created test. AutoTest will allow us to execute that test, or, in more practical terms, any set of tests that we select. But before we execute our test, let's take a look at what we will get out of such an execution.
|
||||
|
||||
==About test results==
|
||||
|
||||
It is important to understand that for AutoTest, test results are solely determined by whether an exception occurs during the execution of a test, and, in cases in which an exception does occur, what kind of exception it is. So, with AutoTest, it is not necessary for you to write anything special into a test that propagates the test's results.
|
||||
|
||||
When AutoTest executes a test, the result will be one of only three possibilities:
|
||||
# The test is '''successful'''
|
||||
# The test is '''failing'''
|
||||
# The test result is '''unresolved'''
|
||||
|
||||
These possibilities are defined as follows.
|
||||
|
||||
{{definition|Successful test|A test which has executed without causing and exception to occur. }}
|
||||
|
||||
|
||||
{{definition|Failing test|A test which has caused an exception to occur during its execution, specifically during the execution of a target routine. }}
|
||||
|
||||
|
||||
{{definition|Unresolved test result|A test which has caused an exception to occur during its execution, but exclusive of the execution of a target routine. }}
|
||||
|
||||
|
||||
So, successful tests are easy enough to understand. The test executed with no exception.
|
||||
|
||||
Failing tests and unresolved test results both mean that an exception occurred during the execution of the test. The distinction is made based on the location of the feature that causes the exception.
|
||||
|
||||
When we execute our test <code>{TEST_BANK_ACCOUNT}.test_deposit_01</code>, we know that <code>test_deposit_01</code> will make a call to <code>{BANK_ACCOUNT}.deposit</code>. If the exception occurs during the execution of a target routine (i.e., in <code>{BANK_ACCOUNT}.deposit</code>), then the test is considered failing. If the exception occurs anywhere else in the execution of <code>{TEST_BANK_ACCOUNT}.test_deposit_01</code>, then the test is considered to have an unresolved result.
|
||||
|
||||
|
||||
{{note|Be aware that some early versions of AutoTest reported some unresolved test results as failing tests. }}
|
||||
|
||||
This behavior can be helpful to us as testers. A failing test indicates that there is something amiss in the target routine. The routine has not completed in a state that satisfies its postcondition and class invariant, or is dealing with an unresolved exception from some routine that it has called. An unresolved test result indicates that something is amiss in our test. Something went wrong in the setup or cleanup of the test or perhaps the test called a target routine from a state that did not satisfy the target routine's precondition.
|
||||
|
||||
|
||||
==The AutoTest tool==
|
||||
|
||||
In the last section, we created a manual test. The AutoTest tool shows us the new test in the '''Tests''' column. So, now the tool should look something like this:
|
||||
|
||||
|
||||
[[Image:AutoTest tool with test]]
|
||||
|
||||
|
||||
==Test execution==
|
||||
|
||||
You see under "Tests" the project cluster <code>accounts</code>, the test cluster <code>tests</code>, the test class <code>TEST_BANK_ACCOUNT</code>, and the test <code>test_deposit_01</code>. You might have to expand some of the elements to see everything as shown above.
|
||||
|
||||
You see that the '''Status''' of <code>test_deposit</code> is "not tested", and that the '''Last executed''' date is empty.
|
||||
|
||||
To execute tests we use the "Run" button ( [[Image:debug-run-icon]] ) on the interface toolbar. By default, the Run button will run all tests matching the tags in the '''Filter''' box. However, there is a list of run options that you can access by clicking the black triangle just to the right of Run. You can choose to run all tests, only those with failing status, a filtered set of tests, or only those tests that you have selected in the tree below. We'll cover filtering a little later. For now, life is simple, we have only one test so just selecting '''Run all''' should execute it.
|
||||
|
||||
==Examining test results==
|
||||
|
||||
The test runs in background and the AutoTest interface now looks like this:
|
||||
|
||||
|
||||
[[Image:AutoTest tool with failed test]]
|
||||
|
||||
|
||||
It's pretty clear that our test has failed. Its status is now marked with the Failing icon ( [[Image:general-error-icon]] ) and in the box below the '''Execution''' tab we see that the status also includes a tag: <code>balance_increased</code>. More detail is provided in the Testing pane of the Outputs tool, as shown below.
|
||||
|
||||
|
||||
[[Image:AutoTest Outputs tool after run 01]]
|
||||
|
||||
|
||||
We see that <code>balance_increased</code> is a postcondition tag on the target routine <code>{BANK_ACCOUNT}.deposit</code>. Upon examination of the code:
|
||||
|
||||
<code>
|
||||
deposit (an_amount: INTEGER)
|
||||
-- Deposit `an_amount'.
|
||||
require
|
||||
amount_large_enough: an_amount > 0
|
||||
do
|
||||
ensure
|
||||
balance_increased: balance > old balance
|
||||
deposited: balance = old balance + an_amount
|
||||
end
|
||||
</code>
|
||||
|
||||
we realize that there is no implementation here. So we add the code to implement <code>deposit</code>:
|
||||
|
||||
<code>
|
||||
...
|
||||
do
|
||||
balance := balance + an_amount
|
||||
ensure
|
||||
...
|
||||
</code>
|
||||
|
||||
After compiling, we can execute the test again. We could do this by selecting '''Run all''' as we did last time, or by selecting '''Run failing'''. Once the test executes we see now that it was successful:
|
||||
|
||||
|
||||
[[Image:AutoTest tool with passed test]]
|
||||
|
||||
|
||||
This time we see that the test is successful, as indicated by the Success icon ( [[Image:general-tick-icon]] ) in the Status column.
|
||||
|
||||
==The beginnings of a test suite==
|
||||
|
||||
Of course we would not have had to use AutoTest to find that bug in <code>{BANK_ACCOUNT}.deposit</code>. We could have just written a simple class to exercise instances of <code>BANK_ACCOUNT</code> and truth would have come out.
|
||||
|
||||
The advantage of using AutoTest is that the test that we wrote to cover <code>{BANK_ACCOUNT}.deposit</code> can stay with us throughout the lifecycle of class <code>BANK_ACCOUNT</code>. We can expand the <code>TEST_BANK_ACCOUNT</code> with additional manual tests and run them after every development increment to ensure that all tests that were once successful are still successful.
|
||||
|
||||
==Manual test summary==
|
||||
|
||||
We have seen how to create and execute a manual test. You will find that manual tests form the backbone of your test suite. But there are two other types of tests available in AutoTest. Next let's take a look at these test types and in what ways they can be used.
|
||||
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
[[Property:title|Using AutoTest]]
|
||||
[[Property:weight|-1]]
|
||||
[[Property:uuid|6b900a65-85c6-9cd6-ef57-ccd4b8decbef]]
|
||||
{{note|The following few pages contain the AutoTest tutorial. This tutorial uses a different software example than the bulk of the EiffelStudio Guided Tour. If this is your first time through, you may want to delay the AutoTest tutorial until you have completed the rest of the Guided Tour, then come back to it when you're feeling more familiar with EiffelStudio.}}
|
||||
|
||||
|
||||
{{note| '''To users of V6.6 and later:''' As of V6.6, the New Eiffel test wizard panes have changed somewhat from this documentation. V6.6 introduces the ability to store certain preferred values for creating tests. The advantage is that one need not enter this information on wizard panes each time a test is created. Because preferred values can be stored, the panes containing the values more likely to change between test creations are presented earlier than other panes. In previous versions, these panes were presented later, as shown in this documentation. The documentation will be updated in the future to reflect the newer wizard sequences and pane layouts. }}
|
||||
|
||||
|
||||
==Introduction==
|
||||
|
||||
AutoTest is a tool that helps you to create, manage, and run tests against your software. AutoTest is accessible directly as a part of EiffelStudio, but works to a large extent behind the scenes so that it doesn't get in the way of your development activities. In other words, even though you may be accumulating a substantial collection of test software along with your project software, you can still run and deliver your project software without going to a lot of trouble to separate the two. Tests managed by AutoTest stay handy and can be run any time to help make sure everything always stands up to the scrutiny of testing.
|
||||
|
||||
This tutorial will guide you through the use of AutoTest. A [[AutoTest|reference section]] for AutoTest is also available.
|
||||
|
||||
|
||||
{{Recommended|At least on your first viewing of this tutorial, take the sections in the order in which they are presented. There are three different types of tests supported by AutoTest. Each type of test is discussed on its own page. But to avoid repetition, the pages for the second and third types of tests omit some of the detail in the first and assume a familiarity with the example. }}
|
||||
|
||||
|
||||
{{Caution|<br/> 1) At this time, AutoTest will work '''only''' for project targets in the '''classic Eiffel''' environment. This means that projects targeted to Microsoft .NET will not be able to use AutoTest.<br/> 2) Currently, the use of AutoTest should be '''restricted to projects built without void-safe settings'''.}}
|
||||
|
||||
|
||||
{{Recommended|During the transition to void-safe Eiffel, projects can be built using '''experimental''' mode. This mode is as stable as '''non-experimental''' mode, but includes some facilities that might break existing code in a few circumstances. However, since version 6.5, EiffelStudio itself is built in experimental mode, so '''we recommend that you use AutoTest only on projects also built using experimental mode'''. Experimental mode can be invoked by using the "-experiment" option from the command line, or on Microsoft Windows by following the '''Start''' menu path to EiffelStudio and selecting experimental mode. As of version 6.6, the mode that was '''experimental''' in previous versions, becomes the '''default''' mode.}}
|
||||
|
||||
|
||||
{{SeeAlso|<br />[[AutoTest]] reference }}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,104 @@
|
||||
[[Property:title|Managing tests]]
|
||||
[[Property:weight|9]]
|
||||
[[Property:uuid|f1e7f63a-dc86-fefb-e669-3e3ea178c596]]
|
||||
The previous sections cover the basics of testing and what it takes to create and use each of the test types supported by AutoTest. This section will finish things up with some miscellaneous information about testing strategy and hints on using AutoTest.
|
||||
|
||||
|
||||
|
||||
==Favor manual tests==
|
||||
|
||||
|
||||
It is worth repeating that currently, manual tests should form the majority of your testing suite. As you have seen, extracted and synthesized tests use more complex setup and execution mechanisms. These mechanisms make tests less robust and readable than manual tests. So using extracted and synthesized tests as a guide to produce manual tests with the same coverage is, at this time, the best way to work. You will probably be able to do this easily enough with synthesized tests. Extracted tests attempt to recreate the context at a specific point in time, which may make it more difficult to write a manual test that is equivalent an extracted test.
|
||||
|
||||
Because manual tests are more easily readable than either of the automatically generated test types, you should be able to understand more quickly what has happened when a test produces failing results.
|
||||
|
||||
|
||||
==Deleting uneeded tests==
|
||||
|
||||
|
||||
At some point and for various reasons, you will probably want to delete tests from your test suite. This is easy enough to do. Remember that test sets are actually just classes with certain characteristics, and that tests are actually just specialized routines of test classes.
|
||||
|
||||
If you want to delete a single test, you can delete that feature from its test class.
|
||||
|
||||
If you want to remove a whole test set, then [[Removing a class|delete the class]] that defines that test set.
|
||||
|
||||
|
||||
==Using Filters==
|
||||
|
||||
Filtering is provided to help view, manage, and run the tests in a test suite.
|
||||
|
||||
Filtering controls which tests are visible in the AutoTest interface how the view is organized. You can display tests organized by the test classes that contain them, by the classes they target, by their type, by their most recent results, or by any system you set up using a system of [[Create a manual test#About tags|tags]].
|
||||
|
||||
Filtering helps you manage which tests get run during a give execution. You can select certain tests to be run from those visible in the AutoTest interface, or you can choose to run all tests visible through a filter.
|
||||
|
||||
|
||||
===The Filter box===
|
||||
|
||||
The Filter box in the AutoTest interface can be used to enter filter text which will allow only certain tests to be visible.
|
||||
|
||||
Filter text can be a string of characters occurring in specific test class name or test routine name, or it can be a [[Create a manual test#About tags|tag]] or a portion of a tag hierarchy. The Filter box supports regular expressions, so you can filter with more granularity.
|
||||
|
||||
It is important to bear in mind that the View box works with the system of [[Create a manual test#About tags|tags]] described in the section on creating manual tests. Tags are hierarchically structured names that are applied to tests through the <code>note</code> clause. When you use the View box to display a set of tests, you specify that set by the tags on the tests. Some of the tags are implicit, in the sense that AutoTest accounts for them, and they are not explicitly coded in <code>note</code> clauses. This should become clear when we look at some examples.
|
||||
|
||||
When the filter text is cleared, the AutoTest interface will display tests accessible through all tag roots.
|
||||
|
||||
As of version 6.5 of EiffelStudio, the tag root words used are:
|
||||
|
||||
|
||||
{| border="2"
|
||||
|-
|
||||
| class || Tests organized by test classes
|
||||
|-
|
||||
| covers || Tests organized by target classes/routines
|
||||
|-
|
||||
| result || Tests organized by the results of their most recent execution
|
||||
|-
|
||||
| user || Tests organized by type (manual, extracted, generated) and by user-added tag hierachies
|
||||
|}
|
||||
|
||||
|
||||
{{note|The tag roots will appear only if there are tests that can be categorized under them. For example, if you have not run any tests, then '''result''' will not appear. }}
|
||||
|
||||
|
||||
Notice that the Filter box has a drop-down with a list of options:
|
||||
|
||||
|
||||
[[Image:AutoTest filter drop down]]
|
||||
|
||||
|
||||
These options are shortcuts to the various tag roots listed above:
|
||||
|
||||
#'''Test classes''' displays the sub-tree under the tag root '''class'''
|
||||
#'''Classes under test''' displays the sub-tree under the tag root '''covers'''
|
||||
#'''Results''' displays the sub-tree under the tag root '''result'''
|
||||
#'''User-defined tags''' displays the sub-tree under the tag root '''user'''
|
||||
|
||||
|
||||
Any tagging system that you devise will show up under the '''user''' tag root.
|
||||
|
||||
For example, consider a manual test containing a '''testing:''' note name with a user-defined tag as in the following code.
|
||||
|
||||
<code>
|
||||
test_deposit_01
|
||||
-- New test routine
|
||||
note
|
||||
testing: "covers/{BANK_ACCOUNT}.deposit"
|
||||
testing: "my_tag_root" -- My new tag root
|
||||
local
|
||||
l_ba: BANK_ACCOUNT
|
||||
do
|
||||
create l_ba
|
||||
l_ba.deposit (500)
|
||||
end
|
||||
</code>
|
||||
|
||||
This will cause the new user-defined tag and its associated tests to be visible in the AutoTest interface.
|
||||
|
||||
[[Image:AutoTest user defined tag root]]
|
||||
|
||||
|
||||
{{seealso|The [[The AutoTest Interface#Filtering|Filtering]] section in [[The AutoTest interface]].}}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,149 @@
|
||||
[[Property:modification_date|Tue, 30 Oct 2018 14:59:36 GMT]]
|
||||
[[Property:publication_date|Tue, 30 Oct 2018 14:59:36 GMT]]
|
||||
[[Property:title|Testing: Background and basics]]
|
||||
[[Property:weight|0]]
|
||||
[[Property:uuid|12c2a2d4-9bf2-ba73-6647-cb9900666de1]]
|
||||
==Background and motivation for testing tools==
|
||||
|
||||
Developers test software in the hope that the testing process will expose faults in the software they've developed. Most developers also realize that no amount of testing will ever prove software to be bug free. So while testing is a virtuous activity that we dare not neglect, we are wise to temper our expectation of the practical value of testing.
|
||||
|
||||
A test is designed to exercise a software element given certain inputs and execution state. The state is observed after the test execution to see if the software element has behaved in a manner that is consistent with its specification.
|
||||
|
||||
As a body of software is developed and tested, a large number of tests may accumulate. This large suite of tests can be run at any time in order to ensure that a change or the addition of a new software element does not cause a previously successful test now to fail. Some software development processes call for running a whole suite of tests after every increment of development activity. This type of testing is often referred to as ''regression testing'', because it tends to expose software which had been satisfying its tests at one time, but because of some development activity has regressed to a failing state.
|
||||
|
||||
Creating, managing and running a large number of tests manually can be time-consuming, messy, and error-prone, thus the motivation for automated testing tools. Testing tools help programmers to create, maintain, and execute a suite of tests by automating the activity. During the last few years, both testing methods and tools have become more sophisticated.
|
||||
|
||||
|
||||
==The Eiffel advantage in testing==
|
||||
|
||||
Some of today's development methods require tests to be written before the software elements they test. Then the tests are included as a part of the software specification. But tests can only reflect a very small subset of the possible execution cases. Testing can never replace a comprehensive software specification.
|
||||
|
||||
The great advantage you have with Eiffel, of course, is that the specification for a software element exists in its contract. Like the tests mentioned above, contracts for software are written prior to implementation. So, importantly, tests are ''not'' a part of a software specification in Eiffel.
|
||||
|
||||
With contract checking enabled at run time, the running software's behavior is constantly monitored against the contract's expectations. In other words, for routines, the precondition defines an acceptable state in which the routine can execute, and the postcondition defines an acceptable state after successful execution. The class invariant defines the constraints necessary for instances of a class to be valid.
|
||||
|
||||
A term commonly used in software testing is "oracle". Tests are generally looked at as having two parts, the first part is a mechanism that exercises (runs or calls) a particular software element in a given context. The second part is the "oracle" whose responsibility it is to determine whether the software element passes or fails the test. Not surprisingly, test oracles in other testing frameworks often look a lot like assertions in Eiffel. So the advantage for Eiffel is that the test oracles for all routines are already written as the postconditions on routines and class invariants.
|
||||
|
||||
The presence of preconditions provides another advantage. Preconditions make it possible to automate testing in ways unavailable in other environments. Because of preconditions, we already have information about the limits of valid inputs to routines. So it's possible to generate a call to a routine we want to test automatically and with a context that meets the routine's precondition.
|
||||
|
||||
|
||||
==AutoTest==
|
||||
|
||||
AutoTest attempts to capitalize on the testing advantages inherent in Eiffel due to Design by Contract. AutoTest consists of an interactive interface, and a library of classes which support testing activity.
|
||||
|
||||
The testing support classes are distributed with EiffelStudio and exist in the ''testing'' subfolder of the ''libraries'' folder. With the exception of one class which we will discuss soon, the classes in "testing" are not intended to be used directly by developers. They exist to support the functionality of AutoTest.
|
||||
|
||||
The interface for AutoTest is accessible through the EiffelStudio development environment. You may find it already resident as a tab in the right hand pane next to Clusters, Features, and Favorites. If it's not there, then you can bring it up by following the menu path:
|
||||
|
||||
<code lang=text>
|
||||
View --> Tools --> AutoTest </code>
|
||||
|
||||
|
||||
==Test classes and tests==
|
||||
|
||||
The AutoTest interface helps you to create and execute tests on the software you develop. The interface contains a wizard called the '''New Eiffel Test Wizard''' which helps you create or generate the types of tests you need. We'll learn more about the interface and the wizard as we go along. But first, let's look at what constitutes a ''test''. For AutoTest, we define the term ''test'' in the context of some other testing terminology:
|
||||
|
||||
|
||||
{{definition|Test class|An effective class that inherits from the class EQA_TEST_SET. }}
|
||||
|
||||
|
||||
{{definition|Test|Any procedure of a test class that satisfies all of the following conditions: <br/>1) Is exported to <code>ANY</code><br/>2) Is immediate (i.e., introduced within the text of the test class)<br/>3) Takes no arguments }}
|
||||
|
||||
|
||||
{{definition|Test set|The set of tests in a test class. }}
|
||||
|
||||
|
||||
{{definition|Test suite|A set of test classes (and by implication the tests contained therein) which is designed to test some particular software system or library. }}
|
||||
|
||||
|
||||
Whenever you use AutoTest, it will find your test classes, those classes that inherit from EQA_TEST_SET. When you run tests, it will execute all the tests in those classes, or a subset of tests that you choose. So, you have probably figured out that the one class from the testing library that you may need to know a little about is EQA_TEST_SET. But you don't have to know very much, because AutoTest can help you construct your test classes.
|
||||
|
||||
|
||||
==Types of tests==
|
||||
|
||||
There are three different types of tests supported by AutoTest:
|
||||
* Manual tests
|
||||
* Extracted tests
|
||||
* Generated tests
|
||||
|
||||
Each test of any of these types ultimately is a feature of class that inherits from EQA_TEST_SET. Ordinarily, though, the three types of tests won't be mixed in a test class. That is, any one particular test class will contain only one type of test. But from the point of view of AutoTest, all types of tests are managed and run the same way. We will discuss these types of tests in more detail later, but for right now, let's just establish some definitions.
|
||||
|
||||
|
||||
{{definition|Manual test|A test manually coded within a test class. }}
|
||||
|
||||
|
||||
Manual tests are features, procedures in fact, of classes that inherit from EQA_TEST_SET. In many simple cases, test classes containing manual tests inherit directly from EQA_TEST_SET, but that's not a requirement. Occasionally it can be useful for test classes to inherit from a descendant of EQA_TEST_SET that provides additional functionality.
|
||||
|
||||
A manual test is "manual" in the sense that you code the essential procedural part of the test by hand. But you really don't have to deal with the more mundane business of creating the whole test class and ensuring the proper inheritance. The ''New Eiffel Test Wizard'' helps out by automatically creating the shell of a test class and the shell of a test for you to fill in. Then it's pretty easy to add new tests manually to an existing test class.
|
||||
|
||||
|
||||
{{definition|Extracted test|A test that has been created during the execution of a system as a result of a developer request or a failure of the system. Extracted with the test is the current runtime state. When run, the test will attempt to recreate the runtime context. }}
|
||||
|
||||
|
||||
Extracted tests are convenient because they allow you to accumulate tests that are based on actual failures of your software (good for the software, not so good for your ego!). Once these tests are in your suite of tests, they are available from then on.
|
||||
|
||||
|
||||
{{definition|Generated test|A test that is the product of generating and running a series of randomly generated invocations of target routines. }}
|
||||
|
||||
|
||||
The process of creating generated tests is sometimes known in the community as creating via ''AutoTest''. The randomly generated calls to target routines which were created and run are discarded at the completion of the creation. But from the results of these calls, a set of permanent tests is distilled. These are the generated tests.
|
||||
|
||||
Generated tests are made possible by Design by Contract. Hopefully, you remember that one thing that DbC gives us is the handy ability to assign blame when something goes wrong. When a test makes a call to a routine we want to test, if a contract violation occurs, it may be the fault of the called routine or it may be the fault of the caller ... and that depends upon what type of contract violation has occurred. The contract violations that are interesting to AutoTest in the process of synthesizing tests are only those in which the called routine is at fault. That is, postcondition and invariant violations. AutoTest will then create a generated test for every ''unique'' failure in which the called routine being tested was to blame.
|
||||
|
||||
|
||||
|
||||
==Anatomy of a test==
|
||||
|
||||
Here are two more definitions:
|
||||
|
||||
{{definition|Target routine|A routine that is to be tested by a test. Sometimes called a "routine under test." }}
|
||||
|
||||
|
||||
{{definition|Target class|A class that contains target routines. Sometimes called a "class under test." }}
|
||||
|
||||
|
||||
In its simplest form, a test is a routine that issues a call to some routine you've developed in some class you've developed.
|
||||
|
||||
So the tests and the test classes are in the realm of testing and are used to test the target routines in target classes which are the real product of your software development project.
|
||||
|
||||
AutoTest will manage and run the tests in any test class whether or not they actually test any target routines. Even though the test shown below doesn't test anything, it still qualifies as a test. Naturally, it would seem silly to keep a test around that doesn't test anything, but the important thing to understand is that AutoTest will work with anything that matches the definitions of test and test class above. That is, once tests are created, AutoTest doesn't really have a stake in what you are trying to test.
|
||||
|
||||
|
||||
|
||||
<code>
|
||||
note
|
||||
description: "[
|
||||
Eiffel tests that can be executed by testing tool.
|
||||
|
||||
]"
|
||||
author: "EiffelStudio test wizard"
|
||||
date: "$Date$"
|
||||
revision: "$Revision$"
|
||||
testing: "type/manual"
|
||||
|
||||
class
|
||||
MY_TEST_CLASS
|
||||
|
||||
inherit
|
||||
EQA_TEST_SET
|
||||
|
||||
feature -- Test routines
|
||||
|
||||
my_test
|
||||
-- New test routine
|
||||
do
|
||||
assert ("not_implemented", False)
|
||||
end
|
||||
|
||||
end</code>
|
||||
|
||||
|
||||
This test class was created by AutoTest's New Eiffel Test Wizard. It is about as simple a test class as there can be. Its only value is to illustrate the basic form of AutoTest tests. So, let's look at that form.
|
||||
|
||||
It is clear that <code>MY_TEST_CLASS</code> is an effective class that inherits from <code>EQA_TEST_SET</code>, so that makes it fit the definition of a test class. And, it's also clear the <code>my_test</code> is a feature of <code>MY_TEST_CLASS</code>, specifically a procedure, exported to <code>ANY</code>, requiring no arguments. That qualifies <code>my_test</code> as a test. If <code>MY_TEST_CLASS</code> is located in a test cluster of your project, then AutoTest will find it and be able to run it whenever you request.
|
||||
|
||||
This test would always fail because of the <code>assert</code> that the wizard put in the implementation. So if you asked AutoTest to run your tests, it would tell you that <code>my_test</code> was a failed test, for the reason: "not_implemented". The <code>assert</code> is not a necessary part of a test. The wizard puts it there to remind you that the test has not been implemented. If you removed the <code>assert</code> line from the test, then the test would always succeed, which would be nice, but it would be succeeding at testing nothing! We'll see more later about what it means for tests to succeed and fail.
|
||||
|
||||
But first let's get some exposure to the AutoTest interface, by building a manual test for a routine in a simple class.
|
||||
|
||||
|
||||
@@ -0,0 +1,146 @@
|
||||
[[Property:title|Using extracted tests]]
|
||||
[[Property:weight|5]]
|
||||
[[Property:uuid|bebd4f28-9818-80f0-a69a-e9ce867723f4]]
|
||||
==About extracted tests==
|
||||
|
||||
At any time that you are running a system in EiffelStudio debugger and your system is paused, you can ask AutoTest to extract a new test class and test from the current executable context. Most often you would use this capability in the case in which you experienced an unexpected failure or exception in one of your routines. It is possible, though, to extract at any point at which the system is paused.
|
||||
|
||||
The value of extracted tests is that they provide a kind of a snapshot in testing form that will reproduce the unexpected failure. An extracted test attempts to reproduce the context in which the offending routine executed. So, extracted tests supplement your manual tests. They serve to cover situations which you just may not have written manual tests to cover.
|
||||
|
||||
Extracted tests are intended to supplement the suite of manual tests that you have created to do the bulk of your testing. So, usually when you create an extracted test, it happens as a result of your being surprised. You will notice that each time you create an extracted test, you get a new test class, too. This is in contrast to manual tests, in which you might use the wizard to create a new test class and one new test to cover a particular target class and target routine. Then you might manually create, in that same test class, many additional tests covering the routine behavior of the same or other target routines in the same target class.
|
||||
|
||||
|
||||
==Creating an extracted test==
|
||||
|
||||
Let's use the same test system we used for manual tests to demonstrate the creation of an extracted test. The example will be slightly contrived because it will find a problem that certainly we would already have discovered had we written a comprehensive set of manual tests against the <code>BANK_ACCOUNT</code> class. Still, the simplicity should help keep things clear.
|
||||
|
||||
If you remember, the root class for the example application was not very interesting, just a root procedure with a single instruction and a declaration <code>my_account</code> of type <code>BANK_ACCOUNT</code>:
|
||||
|
||||
|
||||
<code>
|
||||
make
|
||||
-- Run application.
|
||||
do
|
||||
create my_account
|
||||
end
|
||||
|
||||
my_account: BANK_ACCOUNT
|
||||
</code>
|
||||
|
||||
|
||||
Now, let's add some code into the <code>make</code> procedure that will make use of <code>my_account</code>:
|
||||
|
||||
<code>
|
||||
make
|
||||
-- Run application.
|
||||
do
|
||||
create my_account
|
||||
my_account.deposit (500)
|
||||
my_account.withdraw (100)
|
||||
end
|
||||
</code>
|
||||
|
||||
|
||||
If we run the application from EiffelStudio, we see that it stops when it incurs a postcondition violation in <code>{BANK_ACCOUNT}.withdraw</code>:
|
||||
|
||||
|
||||
[[Image:AutoTest extracted 01]]
|
||||
|
||||
|
||||
When we look at the feature pane, it's pretty easy to see where the problem is:
|
||||
|
||||
|
||||
[[Image:AutoTest extracted 02]]
|
||||
|
||||
|
||||
There is an error in the specification for <code>withdraw</code>. In the postcondition tagged <code>withdrawn</code>, the plus sign should have been a minus sign. Therefore, the assertion should read like this:
|
||||
|
||||
<code>
|
||||
withdrawn: balance = old balance - an_amount
|
||||
</code>
|
||||
|
||||
Certainly we will fix this, but AutoTest gives us the opportunity to extract a test based on this particular failure. So, let's do that.
|
||||
|
||||
So, we go to the AutoTest tool and click triangle next to ''Create new tests'' button and select the '''Extract tests from debugger''' from the drop-down menu. Because we are paused in the debugger, the drop-down menu appears with the '''Extract tests from debugger''' choice enabled this time:
|
||||
|
||||
|
||||
[[Image:AutoTest create new test 02]]
|
||||
|
||||
|
||||
When we select '''Extract tests from debugger''', we are presented with the New Eiffel Test Wizard's '''Test Extraction''' pane. This wizard pane shows a depiction of the current call stack and asks us for which feature(s) on the stack we want to create the test:
|
||||
|
||||
|
||||
[[Image:AutoTest test extraction pane|Test extraction pane]]
|
||||
|
||||
|
||||
The choice for <code>withdraw</code> is the selection we want. We can deselect the stack frame for <code>make</code> if it is pre-selected. If we click '''Next''' at this point we would be taken to the '''Tags''' pane, and from there to the '''General''' pane. But we really don't need to do this. AutoTest will sense that we are extracting a test for <code>{BANK_ACCOUNT}.withdraw</code> and tag the test properly. It will use the same test class name from the '''General''' pane, but add a numerical suffix. So, all we need to do now is to click '''Launch''' from the '''Text Extraction''' pane.
|
||||
|
||||
AutoTest creates the new test and returns us to the debugger, where our system is still on hold. We can stop execution and compile to include the new test.
|
||||
|
||||
Now we see the new test class and test in the AutoTest tool windows.
|
||||
|
||||
|
||||
==Run the tests, fix a problem, run the tests==
|
||||
|
||||
We run our tests using '''Run all''', and we see that the test on <code>withdraw</code> is still failing:
|
||||
|
||||
|
||||
[[Image:AutoTest tool after run]]
|
||||
|
||||
|
||||
If we fix the error in the postcondition in <code>withdraw</code>, recompile, and then re-execute the test, we find that it is successful.
|
||||
|
||||
|
||||
==A closer look at an extracted test==
|
||||
|
||||
Look at the code that was generated for the extracted test after the assertion violation occurred:
|
||||
|
||||
<code>
|
||||
note
|
||||
description: "Regression tests reproducing application state of a previous execution."
|
||||
author: "Testing tool"
|
||||
|
||||
class
|
||||
TEST_BANK_ACCOUNT_EXTRACTED_WITHDRAW_01
|
||||
|
||||
inherit
|
||||
EQA_EXTRACTED_TEST_SET
|
||||
|
||||
feature -- Test routines
|
||||
|
||||
test_withdraw
|
||||
note
|
||||
testing: "type/extracted"
|
||||
testing: "covers/{BANK_ACCOUNT}.withdraw"
|
||||
do
|
||||
run_extracted_test (agent {BANK_ACCOUNT}.withdraw, ["#1", {INTEGER_32} 100])
|
||||
end
|
||||
|
||||
feature {NONE} -- Access
|
||||
|
||||
context: !ARRAY [!TUPLE [type: !TYPE [ANY]; attributes: !TUPLE; inv: BOOLEAN]]
|
||||
-- <Precursor>
|
||||
do
|
||||
Result := <<
|
||||
[{BANK_ACCOUNT}, [
|
||||
"balance", {INTEGER_32} 400
|
||||
], False]
|
||||
>>
|
||||
end
|
||||
|
||||
end
|
||||
</code>
|
||||
|
||||
|
||||
You probably noticed immediately that it doesn't look much like the code that we wrote for our manual test in the previous section.
|
||||
|
||||
One reason for the difference is that the class does not inherit directly from <code>EQA_TEST_SET</code> as our manual test did. Instead, it inherits from <code>EQA_EXTRACTED_TEST_SET</code> which itself is a descendant of <code>EQA_TEST_SET</code>. <code>EQA_EXTRACTED_TEST_SET</code> provides additional functionality for extracted tests.
|
||||
|
||||
Notice that the call to the target routine <code>{BANK_ACCOUNT}.withdraw</code> is effected in the routine <code>test_withdraw</code> which passes an agent representing <code>{BANK_ACCOUNT}.withdraw</code> to the procedure <code>run_extracted_test</code>. The second argument to <code>run_extracted_test</code> is a <code>TUPLE</code> with the argument values which were used in the call to <code>withdraw</code> which caused the original assertion violation.
|
||||
|
||||
Another thing worth noting is the function <code>context</code>. This is how AutoTest recreates the state of the instance of <code>BANK_ACCOUNT</code> at the time of the assertion violation.
|
||||
|
||||
{{caution|The extracted test recreates the state at the point at which execution has halted. So, in the case of a postcondition or invariant violation, the values of the attributes will reflect any changes that have been made during the execution of the routine. (In the example, the value of balance is set to 400, rather than 500 as it would have been when routine <code>withdraw</code> began execution.) This could make a difference in whether the test extracted after an exception is a valid recreation of the original failure. One way of dealing with this, at least in simple cases like this, is to change the test class code to reflect the proper value. A safer way would be rather than extracting the test after the exception, restart the system and stop execution as it enters the failing routine, then extract the test at that point. }}
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,142 @@
|
||||
[[Property:title|Using generated tests]]
|
||||
[[Property:weight|7]]
|
||||
[[Property:uuid|c17ebddf-5d35-76c1-4912-d9f1ca3770a5]]
|
||||
==About generated tests==
|
||||
|
||||
Generated tests fill a different role from either extracted or manual tests. The idea behind generated tests is that because we specify software through its contracts, and because compliance of the software to those contracts can be actively monitored at runtime, we can know two things necessary for building tests:
|
||||
#For any routine, what argument values are valid
|
||||
#For the execution of any routine, what resulting states are acceptable
|
||||
|
||||
The first bit of knowledge comes from the ''preconditions'' of target routines. The second comes from ''postconditions'' of target routines and the ''invariants'' of target classes. Armed with this knowledge, we should be able to generate a series of invocations of target routines using random argument values, and evaluate the results. This is what is done by an internal facility of AutoTest that builds generated tests (this facility is often also referred to itself as AutoTest). After many of these randomly generated invocations, AutoTest attempts to synthesize the results of these feature calls into new test classes. The tests in these new test classes contain the calls leading up and including calls that fail. AutoTest will attempt to create only one test from each unique type of failure, so that your test directory doesn't get loaded with lots of duplicate tests.
|
||||
|
||||
You may look at a generated test class and think that it seems to be very long and to contain lots of stuff that you doubt is relevant. This is a fair assessment. The processes that AutoTest uses to build and minimize generated tests are constantly being improved. But for now, generated tests, although useful, retain a certain amount of that randomness that was used in their creation.
|
||||
|
||||
So for the time being, unlike manual and extracted tests, you should not make generated tests a part of your permanent test suite. Rather, you should consider them a disposable means to an end. Use each generated test as a guide for building an effective and readable manual test.
|
||||
|
||||
|
||||
==Creating generated tests==
|
||||
|
||||
|
||||
If you've been through the discussion of the creation of [[Create a manual test|manual]] and [[Using extracted tests|extracted]] tests, then it should come as no surprise to learn that you use the '''New Eiffel test wizard''' to create generated tests. And much of this process will seem familiar now.
|
||||
|
||||
In the drop-down menu for the '''Create new test''' button, choose the item '''Generate tests for custom types'''.
|
||||
|
||||
|
||||
[[Image:AutoTest create new test]]
|
||||
|
||||
|
||||
At this point, you'll see the '''Test Generation''' wizard pane. This pane allows you to specify which classes you want to generate tests for. You can also adjust the values of certain parameters used in the test generation.
|
||||
|
||||
Let's type the class name <code>BANK_ACCOUNT</code> into the box labeled '''Class or type name''' and click the "'''+'''" button to added it to the list. Of course you can remove an item from the list by selecting it and clicking "'''-'''".
|
||||
|
||||
|
||||
[[Image:AutoTest Test Generation pane]]
|
||||
|
||||
|
||||
The rest of the pane is used to configure certain options for the test generation process.
|
||||
|
||||
'''Cutoff (minutes)''' lets you specify a number of minutes for AutoTest to run random invocations of the routines in your target class(es).
|
||||
|
||||
'''Cutoff (invocations)''' lets you control how long AutoTest will run random invocations by declaring a specific number of invocations.
|
||||
|
||||
'''Routine timeout''' sets an upper limit on how long AutoTest will wait for a random feature call to complete.
|
||||
|
||||
'''Random number generation seed''' provides a way for you to control the seeding of the random number generator used by AutoTest. When the value is '''0''', as shown here, the seed is created from the system clock. This is adequate in most cases, but this option is provided because there might be some cases in which you would want to try to reproduce a previous test generation run. And to do that, you would have to set the seed to the same value for multiple runs.
|
||||
|
||||
The two check boxes '''Slice minimization''' and '''DDmin for minimization''' allow you to select the approach that you want to use for minimizing the size of generated tests. Generally, the default value here is adequate. '''Slicing''' and '''ddmin''' are two different ways of doing minimization. Tests are generated after running many randomly generated calls to routines in your target class. Tests are generated for calls that fail. So, there may have been many randomized calls leading up to the failed call. Minimization helps to eliminate the majority of the unrelated randomly generated calls, leaving the test code as short as possible. You will notice that minimization processing is memory and processor intensive.
|
||||
|
||||
The last check box, '''HTML statistics''' gives you the option of having AutoTest record the results of a test generation run in a set of files that you can review with a web browser.
|
||||
|
||||
We can allow all these to remain their default values, with one exception. Let's check the '''HTML statistics''' box.
|
||||
|
||||
|
||||
|
||||
During the test generation you can watch the random invocations of your class's routines being logged in the Testing pane of the Outputs tool. When the generation completes, AutoTest directs you to the location of the results:
|
||||
|
||||
|
||||
[[Image:AutoTest testing pane after generation]]
|
||||
|
||||
|
||||
The file <code>statistics.txt</code> contains a summary of the generation run. If you enabled '''Create HTML output''' you can open the file <code lang="text">index.html</code> with your browser and view formatted summary and detail information.
|
||||
|
||||
|
||||
{{note|The '''result''' directory includes files that summarize the whole generated testing process. Some of these are lengthy because they contain information on test cases used for each target routine. }}
|
||||
|
||||
|
||||
If we try to generate tests on the class <code>BANK_ACCOUNT</code> in which we have already fixed two bugs after the manual and extracted tests, we will see something about like the following results:
|
||||
|
||||
|
||||
[[Image:AutoTest generated results pass]]
|
||||
|
||||
|
||||
The important thing to notice here is the status: '''pass'''. There were no randomly generated cases that failed. So every valid invocation of a routine for class <code>BANK_ACCOUNT</code> completed satisfactorily. Therefore, no generated test class was created.
|
||||
|
||||
If we re-introduce the bug into the <code>deposit</code> procedure of class <code>BANK_ACCOUNT</code> (i.e., Remove this line of code: <code>balance := balance + an_amount</code>), and then request generated tests again, we get different results:
|
||||
|
||||
|
||||
[[Image:AutoTest generated results fail]]
|
||||
|
||||
|
||||
This time, as we expected, failures were encountered. And a generated test class was created.
|
||||
|
||||
|
||||
==A look at a generated test==
|
||||
|
||||
|
||||
The generated test class looks like this:
|
||||
|
||||
|
||||
<code>
|
||||
note
|
||||
description: "Generated test created by AutoTest."
|
||||
author: "Testing tool"
|
||||
|
||||
class
|
||||
TEST_BANK_ACCOUNT_GENERATED_001
|
||||
|
||||
inherit
|
||||
EQA_SYNTHESIZED_TEST_SET
|
||||
|
||||
feature -- Test routines
|
||||
|
||||
generated_test_1
|
||||
note
|
||||
testing: "type/generated"
|
||||
testing: "covers/{BANK_ACCOUNT}.deposit"
|
||||
local
|
||||
v_6: BANK_ACCOUNT
|
||||
v_7: INTEGER_32
|
||||
do
|
||||
execute_safe (agent: BANK_ACCOUNT
|
||||
do
|
||||
create {BANK_ACCOUNT} Result
|
||||
end)
|
||||
if {l_ot1: BANK_ACCOUNT} last_object then
|
||||
v_6 := l_ot1
|
||||
end
|
||||
v_7 := {INTEGER_32} 3
|
||||
|
||||
-- Final routine call
|
||||
set_is_recovery_enabled (False)
|
||||
execute_safe (agent v_6.deposit (v_7))
|
||||
end
|
||||
|
||||
end
|
||||
</code>
|
||||
|
||||
|
||||
{{note|If you've been following along by the doing these examples in EiffelStudio, you may notice that your generated class looks slightly different. }}
|
||||
|
||||
|
||||
This test is written in a way that is a little different from both the manual test we wrote and the extracted test. But it's not too hard to figure out what's going on. An object of type <code>BANK_ACCOUNT</code> will be created (local <code>v_6</code>) and the <code>deposit</code> feature will be applied to it with an argument value of <code>3</code> (local <code>v_7</code>).
|
||||
|
||||
You can see that this test, although it is implemented differently, is about the same as the manual test we wrote covering <code>{BANK_ACCOUNT}.deposit</code>. Because we have re-introduced the bug in <code>BANK_ACCOUNT</code>, if we run all tests, we see that both our manual test and the generated test are failing ... only the extracted test covering <code>{BANK_ACCOUNT}.withdraw</code> is successful:
|
||||
|
||||
|
||||
[[Image:AutoTest interface after run 05]]
|
||||
|
||||
|
||||
If we replace the implementation for <code>{BANK_ACCOUNT}.deposit</code> that we had removed, and then re-execute the tests, all are successful.
|
||||
|
||||
|
||||
|
||||
120
documentation/18.11/eiffelstudio/Tutorials/viewing-classes.wiki
Normal file
120
documentation/18.11/eiffelstudio/Tutorials/viewing-classes.wiki
Normal file
@@ -0,0 +1,120 @@
|
||||
[[Property:title|Viewing Classes]]
|
||||
[[Property:weight|-9]]
|
||||
[[Property:uuid|78136af1-5d7a-f3d2-9619-17f4c0541f1e]]
|
||||
__FORCETOC__
|
||||
We haven't really looked at the text of a class yet. It's important anyway to see how EiffelStudio provides you with numerous, complementary '''views''' of your software. The Class tool and Feature tool are where the bulk of these views will be displayed, although the Editor tool does support some special views. For now we will concentrate on the views available in the Class tool.
|
||||
|
||||
|
||||
==Making some room==
|
||||
|
||||
We'll need just one development window for the moment, the one that was targeted to <code>LIST</code>. You should still have that window available from the previous Tour topic, and it should look about like this:
|
||||
|
||||
[[Image:es gt development window targeted to list 01]]
|
||||
|
||||
{{note| If you don't see a development window targeted to <code>LIST</code>, just retarget one, as you know how to do this now, for example by typing the name followed by Enter in the Class Field at the top left. }}
|
||||
|
||||
First let's give ourselves more space. Right now we don't need the Groups tool or any of the other tools sharing that pane. We could get rid of them by clicking the close buttons on the top right corner of the panes. Then we could get them back later by following the menu path:
|
||||
<code lang="text">
|
||||
View --> Tools --> x
|
||||
</code>
|
||||
where "x" is the name of a tool we want restored. But there is an easier way. Let's just hide them away until later.
|
||||
|
||||
We do this by setting the pane containing the tools to '''Auto Hide'''. On the bar at the top of the pane, you'll see the Auto Hide icon ([[Image:auto-hide-icon]]) which looks like a pushpin.
|
||||
|
||||
[[Image:es gt auto hide 01]]
|
||||
|
||||
Click the icon and you'll see the pane shrink into a set of tabs on the right window margin and the remaining panes will expand to fill the abandoned space. The tools in the pane will temporarily expand back out if you move your mouse cursor over their tabs. Try it with one. When you want the pane back in its original place permanently, you just expand one of the tabs by mousing over it, then click the Disable Auto Hide icon, which is the pushpin again, just horizontal this time.
|
||||
|
||||
Two panes remain, showing the Editor tool and the lower pane containing the Outputs tool and others. You can resize the panes by dragging the border between them. Make sure there's plenty of room in the lower pane.
|
||||
|
||||
|
||||
==The Class tool==
|
||||
|
||||
Before we look at the Class tool, let's make sure that we set [[Change data share mode|linked data share mode]] which will always display information about the current target. Go to the main menu bar and expand the menu item <code>View</code>. If you see a choice marked with the link context icon ([[Image:context-link-icon]]) and labeled <code>Link Context Tool</code>, then select it. After it has been selected, or if it has already been selected, then the label will read: <code>Unlink Context Tool</code>.
|
||||
|
||||
At the bottom of the lower pane you'll find a tab labeled '''Class'''. This gives you access to many forms of information about the current class -- the target of the development window. Click on the Class tab to bring up the Class tool. A set of buttons at the top enables you to display a number of '''views''' of the class. The currently highlighted button indicates the default view: <code>Ancestors</code>. You can see the others' names by moving your cursor over the various view icons, and reading the tooltips.
|
||||
|
||||
The view currently displayed, <code>Ancestors</code>, shows the inheritance structure that leads to the current target, <code>LIST</code> :
|
||||
|
||||
[[Image:es gt class tool 01]]
|
||||
|
||||
This shows that <code>LIST</code> is an heir of <code>CHAIN</code> which itself, as an example of multiple inheritance, is an heir of <code>CURSOR_STRUCTURE</code>, <code>INDEXABLE</code>, and -- twice, as an example of <span>repeated</span> inheritance -- <code>SEQUENCE</code>. If, because of direct or indirect repeated inheritance, a class appears more than once, the display doesn't repeat its ancestry the second and subsequent times; the omitted repetition appears as just three dots, '''...''', as illustrated here for the second occurrences of <code>BAG</code>, <code>ACTIVE</code> and others.
|
||||
|
||||
As you may have guessed, all the class names that appear on this display, by default in blue, can function as hyperlinks: you can use any one of them to retarget the Development Window to the corresponding class. This will be another major retargeting mechanism. But let's not pursue it for the moment and instead continue looking at the documentation views.
|
||||
|
||||
Next to <code>Ancestors</code> button is <code>Descendants,</code> which will give you the descendants of a class in a similar format:
|
||||
|
||||
[[Image:es gt class tool descendants 01]]
|
||||
|
||||
The progeny of <code>LIST</code>, as you can see, is just as impressive as its ancestry.
|
||||
|
||||
Let's now look at the other formats, starting from the left. The first button, <code>Clickable</code>, gives the class text. It's essentially the same information as appears in the top Editing Tool (whose pane was reduced to its bare minimum in the last few pictures, showing only the first three lines or so), but with some differences:
|
||||
* The Text view in the Editor is editable. In fact it's EiffelStudio's primary tool for entering software texts. The Class tool's <code>Clickable</code> view is just a view; you can't change it.
|
||||
* The Text view retains the formatting of the class text the way it was typed in; the <code>Clickable</code> view is automatically formatted -- "pretty-printed" -- according to the standard Eiffel layout rules.
|
||||
* The <code>Clickable</code> view does not include comments inside routine implementations ( <code>do</code> and <code>once</code> clauses), although it does retain features' header comments.
|
||||
* As part of the pretty-printing, the <code>Clickable</code> view uses colors and fonts to distinguish keywords, identifiers, comments and other syntactical elements. You can change the fonts and colors, like many other elements of the interface, through <code lang=text>Tools --> Preferences</code>. (Now is not the time.)
|
||||
|
||||
This view is called "Clickable" because, as we'll see later, every syntactical element on it is a hyperlink, which you can use for browsing.
|
||||
|
||||
After <code>Clickable</code> comes the <code>Flat</code> view button. The layout of the result is similar. The flat form of a class is the reconstructed class text including not only what's declared in the class itself but also everything that it inherits from its ancestors, direct or indirect. This applies to the flat form's features, which include ancestor features, but also to contracts: the flat form's invariant includes all clauses from ancestors' invariants, and the preconditions are expanded to take <code>require else</code> and <code>ensure then</code> clauses into consideration. (The [[An Eiffel Tutorial (ET)|Eiffel Tutorial]] explains these notions in detail.)
|
||||
|
||||
|
||||
[[Image:es gt class tool flat 01]]
|
||||
|
||||
|
||||
As a result, the <code>Flat</code> view shows the class text as it might have come out had inheritance (what a horrible thought even to contemplate!) ''not'' been available to write it.
|
||||
|
||||
The first two features appearing in the above display, <code>cursor</code> and <code>first</code>, are indeed inherited from ancestors, rather than declared in <code>LIST</code> itself. Note how EiffelStudio, when producing the flat form, adds a line of the form
|
||||
<code>
|
||||
-- (from CLASS_OF_ORIGIN)
|
||||
</code>
|
||||
|
||||
to the header comments of inherited routines, to document where they come from.
|
||||
|
||||
The flat form is an important notion of object technology, making it possible to understand a class by itself, regardless of the possibly rich inheritance structure that led to it. Looking at the Flat view of <code>LIST</code>, you may note how few of its properties come from the class itself; most of the interesting work has been done in ancestors, and <code>LIST</code> just adds a few details.
|
||||
|
||||
{{note|If at any time you want to search for a certain pattern in the views displayed, you can type <code>CTRL-F</code>. A Find bar will come up at the bottom of the pane you are using. If you need more searching power, click the Search icon ([[Image:search-icon]]) in the development window's tool bar to invoke EiffelStudio's [[Search tool]]. }}
|
||||
|
||||
Next come two essential documentation views: <code>Contract</code> and <code>Interface</code>. Based on Eiffel's principles of Design by Contract, they document the interface properties of a class. Unlike the previous two, they do not show actual Eiffel texts, but information useful for client classes.
|
||||
|
||||
The contract form (also known as the '''short form''' of a class) is the class text deprived of any internal detail to retain interface information only. It discards any feature that's not exported (available to all clients); for the retained features, it discards the implementation -- <code>do</code> or <code>once</code> clause -- but retains the header (feature name, arguments, results), the header comment, and the contracts (precondition, postcondition, invariant) minus any contract clause that refers to a non-exported feature and hence would be useless to clients.
|
||||
|
||||
As you will know, particularly if you have read the book [[Object-Oriented Software Construction, 2nd Edition]], the contract form is the preferred way of documenting software elements, especially reusable components, as it provides clients with just the right level of abstraction: precise enough thanks to the type signature and the contracts; clear enough thanks to the header comments; and general enough since it omits implementation details that are irrelevant to client programmers (and might lead them to write client code that won't work any more if the implementation changes).
|
||||
|
||||
In practice you will often want to use, instead of the <code>Contract</code> view, the next one, <code>Interface</code>, also known as "flat-short form" and "flat contract form", which applies the same rules to the flat form rather than to the original class. This means it shows information on all the features of the class, immediate (defined in the class itself) as well as inherited, whereas the short form, non-flat, only considers immediate features. The <code>Interface</code> view provides the complete interface information for the class. Try it now on class <code>LIST</code>.
|
||||
|
||||
The next two buttons are for the <code>Ancestors</code> and <code>Descendants</code> views, which we have already seen, showing classes connected with the target through one of the two inter-class relations, inheritance. After them come <code>Clients</code> and <code>Suppliers</code>, to list the classes connected through the other relation, client. Clicking the <code>Clients</code> button shows the list of clients of <code>LIST</code>.
|
||||
|
||||
Now click the next button to see the <code>Suppliers</code> of <code>LIST</code>.
|
||||
|
||||
The only two classes that <code>LIST</code> needs for its own algorithms are basic types from the Kernel Library, <code>BOOLEAN</code> and <code>INTEGER_32</code>. In Eiffel, as you may remember, all types are defined by classes, even those describing such elementary values as integers and booleans.
|
||||
|
||||
|
||||
==Feature information in the Class View==
|
||||
|
||||
Let's resist the natural urge to go see now what the classes <code>INTEGER_32</code> and <code>BOOLEAN</code> look like, and instead continue our survey of views. The remaining views will all display information about the '''features''' of the class. The first of them, <code>Attributes</code>, lists the attributes. It's not very interesting for <code>LIST</code>, a deferred class with only one attribute -- you can check this for yourself by clicking the <code>Attributes</code> button -- so let's look at the next one. Click the <code>Routines</code> button now to display information about the routines of class <code>LIST</code> :
|
||||
|
||||
[[Image:es gt class tool routines 01]]
|
||||
|
||||
The sections of this display group routines according to the ancestors of <code>LIST</code> -- including <code>LIST</code> itself -- that first introduced them; for example <code>append</code> originally comes from <code>CHAIN</code> and <code>back</code> from <code>BILINEAR</code>. Much of the benefit of this display comes from its support for browsing: all the colored elements, representing classes and features, will be "clickable" hyperlinks.
|
||||
|
||||
The <code>Invariants</code> button shows the complete class invariant for <code>LIST</code>. This includes all invariant clauses that have been inherited from all ancestors.
|
||||
|
||||
Other Class tool buttons display information in the same format as <code>Attributes</code> and <code>Routines</code>. Each selects a specific subset of the target class's features. You can now try any of the others by clicking the corresponding button:
|
||||
* <code>Deferred</code> features: abstract features which don't have an implementation in the current class, only in eventual descendants. Try this for <code>LIST</code> ; you'll see that this deferred class indeed has a number of deferred features.
|
||||
* <code>Once</code> and constants: constant attributes, "once functions" which provide shared objects (close to the "singleton" pattern), and once procedures which provide a convenient initialization mechanism. <code>LIST</code> has 'Operating_environment' and 'Io' inherited from the parent class ANY.
|
||||
* <code>External</code> features, implemented as calls to routines, macros or other elements implemented in other languages. <code>LIST</code> hasn't any.
|
||||
* <code>Exported</code> features: those available to all clients. <code>LIST</code> has quite a few.
|
||||
|
||||
|
||||
==Restoring the look of the development window==
|
||||
|
||||
Once you're done looking at the different views, let's undo the changes that we made to the configuration of the development window at the beginning of this section in '''[[#Making some room|Making some room]]'''.
|
||||
|
||||
Reduce the relative size of the lower pane.
|
||||
|
||||
Then go to one of the tabs on the right margin of the development window, Groups, will work. Hold your cursor over it for a moment and it should expand. Then click the Disable Auto Hide icon, the horizontal pushpin, to restore the rightmost pane.
|
||||
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user