Deltek Maconomy 2.3 GA M-Script Programming December 2, 2016
While Deltek has attempted to verify that the information in this document is accurate and complete, some typographical or technical errors may exist. The recipient of this document is solely responsible for all decisions relating to or use of the information provided herein. The information contained in this publication is effective as of the publication date below and is subject to change without notice. This publication contains proprietary information that is protected by copyright. All rights are reserved. No part of this document may be reproduced or transmitted in any form or by any means, electronic or mechanical, or translated into another language, without the prior written consent of Deltek, Inc. This edition published December 2016. Deltek, Inc. Deltek s software is also protected by copyright law and constitutes valuable confidential and proprietary information of Deltek, Inc. and its licensors. The Deltek software, and all related documentation, is provided for use only in accordance with the terms of the license agreement. Unauthorized reproduction or distribution of the program or any portion thereof could result in severe civil or criminal penalties. All trademarks are the property of their respective owners. M-Script Programming ii
Contents Overview... 1 Source Code Formatting... 2 Document Setup... 2 Casing and Naming Conventions... 2 Indention and Alignment... 3 Invoking Procedures and Functions... 4 Source Code Comments... 4 Standard Constructions... 6 Localization... 6 MQL Expressions... 7 Using Packages... 7 Using Exceptions... 8 Strings... 9 GUI... 9 Guidelines for Writing Efficient Algorithms... 11 Limit the Use of Long Object Structures... 11 Use ++i instead of i++... 11 Appendix A... 12 M-Script Programming iii
Overview Overview This document contains the M-Script programming standard. The document is written with the intention of enabling all M-Script programmers to write consistent and efficient code and to enable them to easily read and comprehend other M-Script programmer s code. By complying with the standards and conventions set out in this document it is ensured that the code produced is readable and comprehensible to others. Additionally, by developing algorithms according the guidelines you will be able to create well-performing programs. M-Script Programming 1
Source Code Formatting Source Code Formatting M-Script source code will potentially be available to the customer. Accordingly, the source code should be seen as part of the delivery to the customer and thus has to comply with the same high standard as the rest of the Maconomy product. This means that the guidelines for source code formatting should be followed in order for all M-Script files to appear as part of an integrated system. As a general rule, when editing existing M-Script files the M-Script programmer should always try to comply with whatever programming style is used within the current M-Script. This means that it is legitimate to defer from this guideline in order to keep the programming style of a single M- Script file consistent. This section describes the formatting conventions that should be used when programming in M- Script. The syntax and structure of M-Script resembles Java and Java-script and accordingly as a general rule traditional Java-guidelines should be used when programming in M-Script. Document Setup M-Script documents are standard ASCII text documents. To avoid confusion about tab-sizes tabs should not be used in M-Script documents. Instead, formatting the document should be made using regular space characters. Most editors can be configured to automatically convert tab characters to regular space characters and to insert space characters when the tab key is used. To be able to print documents in a readable format indent size should be fixed at 2 spaces and line break should be fixed at 90 characters per line. M-Script source code must be developed in US English; hence error messages, filenames, source code comments, and so on, must be in US English. The only exception from this rule is kernel strings, which must be in Danish, since the official kernel language is Danish. Casing and Naming Conventions The M-Script programming language is case sensitive. Accordingly, the name of a procedure, function, parameter or variable should be cased identically at all times. All reserved key words (if, while, for, return, null, and so forth) are written in lowercase. As a general rule all M-Script procedure and function names as well as parameter and variable names should be initiated with a lowercase letter and have an uppercased first letter in each subsequent word. Procedures and Functions The name of a procedure or function is an imperative description of its functionality, for example: showemployeeload() or getemployeename(). Parameters and Variables All parameters and variables are named according to their semantics; for example, employeename, employeenumber. Parameters and variables that are used for intervals are prefixed from and to ; for example, fromemployeenumber, toemployeenumber. M-Script Programming 2
Source Code Formatting Indention and Alignment Constructs like if, while, for, and so on, are indented by two spaces. Additionally, procedure and function bodies are indented by two spaces. Curly Braces { } Curly brace, that marks the beginning and end of an M-Script construction, should be placed on separate lines. if (employeename == #N"") { employeename = #N"John"; } Accordingly, the following construction should not be used. if (employeename == #N""){ employeename = #N"John"; } Expressions Spanning Multiple Lines alongvariablename = anotherlongvariablename Alignment Variable declarations: var employeename = #N"John"; var employeenumber = 1001; + yetanotherlongvariablename thelastlongvariablename; Assignments: employeename = employeeinfo.name.value; employeenumber = employeeinfo.number.value; Procedure and function headers: function getemployeeinfo(employeenumber, detailedinfo) function calculateitemprice(itemnumber, Variable Declarations date, discountgroup, quantity) As a general rule, variables should not be declared before they are required and always within the local scope of the program where the variable is used. This means that M-Script functions should not be initiated by declaring all of the variables that are required within the function, but rather that variables should be declared as locally as possible. M-Script Programming 3
Source Code Formatting Invoking Procedures and Functions When invoking procedures and functions, the left parenthesis should always be located immediately after the name of the procedure or function using no white space. In case of multiple parameters the comma after each parameter should be followed by a white space. getemployeeinfo(employeenumber, detailedinfo); Procedures and functions that take more than two or three parameters can be split over multiple lines. When parameters are split over multiple lines, all parameters should be located on separate lines. Parameters for which the meaning is not clear from the context should be commented: getemployeeinfo(1001, // employee number detailedinfo); For procedures and functions that have a large number of parameters, the parameters should be logically grouped both in the declaration and the invocation: procedurex(a, b, c, d, e, f); Source Code Comments As a general rule, M-Script source code is commented, and the comments are written in US English. The more public a function is considered to be, the more comments should be included in the source code files. The comments are written in JavaDoc style, which is exemplified in the following. The use of JavaDoc allows for automatically generation of documentation. This can be found online at http://fabrik. For more information, see http://java.sun.com/j2se/javadoc/writingdoccomments/ M-Script File Headers All M-Script files are initiated with a #version-statement, a header that describes the content of the file, and optionally a package-statement if the file is a package. The following example shows illustrates a package file header. For a non-package file, the package-statement is, of course, left out, along with the version numbers in the revision log. #version 9 / Copyright 2002 by Maconomy Corporation @brief Interface for making MQL-Reports. This file contains the implementation of the mqlreport portal component. Revision log: 1.0.0 JHO, 01-10-2002: Initial revision. 1.0.1 JHO, 14-10-2002: Calculation error in calculateemployeeload corrected. M-Script Programming 4
Source Code Formatting / package MQLReports(1.0.1); The header comment starts with a copyright notice. Second, a @brief tag that gives a brief description of the package, which is used when creating an overview page of all of the available packages, follows. Third, a full description of the package follows (no tag is needed). Fourth, a revision log ends the header. If the package becomes deprecated, a @deprecated tag is added before the @brief tag: / Copyright 2002 by Maconomy Corporation @deprecated Use MQLReports.2.ms instead. @brief Interface for making MQL-Reports. Procedures and Functions All procedures and functions are preceded by a brief description that includes a description of the input and output. For complex procedures and functions, comments are added to the source code to explain any difficult part of the code. Parameters in M-Script functions are not qualified by their type; accordingly, the heading comment should contain a description of the required type. The following illustrates this. / This function calculates the load of an employee based on planning information from the Maconomy database. @return employeeload (real) the load. @param employeenumber (string) the employee number. @param startdate (date) start date of interval, as returned by the mkdate(). @param enddate (date) end date of interval, as returned by the mkdate(). @throws MQLReports if the employee cannot be found. @throws MQLReports if startdate > enddate. / public function calculateemplyeeload(employeenumber, startdate, enddate) {... } Comments within a procedure or function can be formatted according to the following examples: // Calculate the percentage-of-completion / Get the percentage-of-completion for all jobs. Only jobs in order are included in the list. / M-Script Programming 5
Standard Constructions Standard Constructions This section describes several standard constructions, such as localization, MQL-expressions, exceptions, and so on, that are commonly used when doing M-Script programming. Localization To be able to localize M-Script programs all strings (kernel, template, and MQL expressions) must be tagged according to the following guidelines. First a short overview of the different tags is provided, followed by a more detailed description of each tag and its use. Tag Description #K Kernel strings #T Template strings #S MQL strings #N Strings that should not be localized Kernel Strings Kernel strings are references to database fields, database values, dialogs, and pop-ups. All identifiers are considered to be kernel strings; hence, it is only necessary to use #K when kernel identifiers are packed into strings. A common example is the specification of a layout: var layout = {name: #N"myCard", pane: [[{kind: #N"input", name: #K"Sagsnavn" }]] } Because all identifiers are considered to be kernel identifiers, no tag is needed in the following example, where a job number is fetched from a data object that is returned from a dialog call. var jobnumber = jobdata.rows[0].hovedsagsnummer; Template Strings Template strings are messages that are intended for the (end) user, typically an error message. Template strings should be tagged with #T, as the following example illustrates. var errormessage = sprint(#t"could not find file '^1'", filename); throw myexception(errormessage); MQL Strings MQL strings are strings that are passed to functions like maconomy::mql(). They should be written as texts as shown here: var mqlquery = #S'MQLQUERY'; mselect Sagsnavn, Dokumentarkivnummer M-Script Programming 6
Standard Constructions from Sagshoved MQLQUERY var jobdata = maconomy::mql(mqlquery); Note that #S only should be used to tag the MQL-query and not in subsequent references to fields from the result of the query. Strings that Should not be Localized The last category of strings is those that should not be localized. This includes file references, component references, and the empty string: var afilename = #N"MyFile.txt"; MQL Expressions The use of SQL is strictly forbidden; MQL should be used, instead. When you write MQL expressions in M-Script, the expression cannot span multiple lines. To keep the MScript in a readable and printable format, MQL expressions should always be written using here-text functionality, as shown in the following. Notice, that sprint functionality is no longer used to transfer parameters to the query, as was the case with SQL. Now parameters (and their types) are declared within the query, and values are bound to parameters through a bind-object. var mqlquery = #S'MQLQUERY'; mselect from where Sagsnavn, Dokumentarkivnummer Sagshoved Sagsnavn = SagsnavnPar using parameters SagsnavnPar: string MQLQUERY var bindobject = { parameters: @{ SagsnavnPar: { value: #N"1234567" } } }; var jobdata = maconomy::mql(mqlquery, bindobject); Notice that MQL returns data that is correctly formatted. Field names are not truncated; they are cased correctly, and Danish letters are not expanded. Hence, @ is no longer necessary, and should not be used when accessing a date from the query, as was the case with SQL. Using Packages This section describes how to use the uses statement and package declarations with rules for version numbering of packages. uses Statement All uses statements should always be located right after the file header comment (and package declaration for packages). Basically, packages can be located in three different places: First, as part of the framework package distribution; second, as part of the global Portal package distribution; and finally, as a local package of the current component. The following example shows three uses statements that illustrate this. Notice that the uses statements are ordered so M-Script Programming 7
Standard Constructions that Framework packages are included before global Portal packages, and, finally, local component packages are included. uses Framework::packages::std::BrowserType(1) uses Application::Portal::Packages::Gui::GuiApi(5) uses.::packages::jobs(1) as browsertype; as guiapi; as jobs; package Statement A package is declared with the following statement at the top of the source file, just below the header comment: package MyPackage(1.0.0); The package version number consists of three parts; the major number, minor number, and revision code. The revision code is incremented when the file is altered. The minor number is always set to 0. The major number is used to control the released versions of the package that are not compatible. Thus, a package major number should only be incremented if the package is altered in such a way that backward compatibility is broken, and if the package has been released externally. Additionally, the major number should at most be incremented once within one Maconomy version. The following example illustrates this. GuiApi.5.ms is released as part of Maconomy 8.0. For Maconomy 8.1 GuiApi is changed two times, neither of which preserves backward compatibility. When the first change is made, the major number is incremented to 6; afterward, the major number is not touched (only the revision code is incremented), even though a change does not preserve backward compatibility. Maconomy 8.1 is released with GuiApi.6.ms (and GuiApi.5.ms if version 5 is still supported). All R&D-supported code uses GuiApi.6.ms. This procedure minimizes the number of versions of one package that are to be maintained by R&D. The drawback is that every time a change that breaks backward compatibility is made to a package, all uses of the package must be updated in R&D-supported code. However, this procedure is no different from the one that is used in other (MSL) parts of application development. Remember to use Perforce s integrate functionality when making new major versions of a package. This is described by BSH at: http://appl-pc.maconomy.dk/applikation/udvikling/appintegrate.html). Using Exceptions Exceptions are used for error handling. A general introduction to exceptions can be found at: http://webdemo/mscripthome/files/exceptionhandlingtutorial.pdf Catching Exceptions Exceptions can be caught based on their type; if no type is specified, all types are caught, hence all exceptions are caught. Catching all (types of) exceptions has the major drawback that they all must be handled; failing to do this might result in newer exceptions getting through to other parts of the code or the user. Thus, you should always list the types of exceptions that you want to catch (and handle) in the catch statement. Throwing Exceptions When throwing exceptions, the first thing to decide on is the type of the exception. The type should indicate the type of the exception, not the file or package from which the exception was thrown (such information is automatically recorded in the exception). To ensure a structured M-Script Programming 8
Standard Constructions usage of exception, a type hierarchy has been created, from which the type should always be chosen: PortalError ::Runtime ::StdLib ::Application ::StdLib ::File ::Gui ::Api ::RecordNotFound There are two major branches in the hierarchy, runtime exceptions (PortalError::Runtime) and application exceptions (PortalError::Application). Errors that make further execution impossible should be thrown as runtime exceptions. On the other hand, exceptions that might be handled in other parts of the code should be thrown as application exceptions. The most common situation would be to throw an exception of type PortalError::Application: throw PortalError::Application({ message: #T"A useful error message" }); The value of the exception should be an object that contains at least a message property that provides a useful error message. For runtime exceptions, the following optional properties are also available: exceptions: An array of exceptions that have been caught and might be the cause of this exception. additionaldata: Data that might be useful in tracking the error that caused the exception. Strings As a general rule of thumb, strings should be formatted using the sprint() function. The use of the + operator should especially be avoided in combination with template strings, because it can make correct localization almost impossible: If a string is formatted using + the correct word order of the entire string might not be possible to preserve during localization, because the string only appears as several small strings during localization. Paths A reference to a file system path should not end or start with a directory separator, such as / or :, which is illustrated in the following example. var rootpath = #N"Application/Portal/Standard/Portals"; var subpath = #N"Job/JobHome/Description"; var filename = #N"Jobs.lay"; var fullpath = sprint(#n"^1/^2/^3", rootpath, subpath, filename); GUI This section describes the standards that are related to the use of the M-Scripts GUI interface. M-Script Programming 9
Standard Constructions Island Islands and only islands should be used when grouping fields in the card part of a GUI layout. Hence, if you are planning to use spaces to divide the fields in your layout into groups, use islands instead. However, islands should not be used as extensively as they are used in the standard Windows client, because they take up space. M-Script Programming 10
Guidelines for Writing Efficient Algorithms Guidelines for Writing Efficient Algorithms This section contains a number of guidelines for writing efficient M-Script algorithms. Limit the Use of Long Object Structures Accessing variables within long object structures requires the M-Script interpreter to run through multiple object references. This slows down performance and also makes the code difficult to read and interpret. It can, however, be avoided by using a local variable that references the requested object property directly. Example The following two programming examples illustrate first an ineffective approach for accessing an array (which is a property within an object structure), and subsequently a more effective approach. Ineffective Approach for (var i=100; i>0; --i) { o1.o2.o3.o4.o5.array[i] = i; } In this example M-Script must search through the object structure for each iteration of the for loop. Effective Approach for (var i=100, reference = o1.o2.o3.o4.o5.array; i>0; --i) { reference[i] = i; } In this example a reference is created directly to the array within the last object in the object structure. In this way M-Script can access the elements of the array directly without having to search through the object structure. Use ++i instead of i++ The ++i operator is slightly more efficient than the i++ operator. Therefore, the ++i operator should be used wherever appropriate. M-Script Programming 11
Appendix A Appendix A This shows a template for an M-Script package. #version 9 / Copyright YYYY by Maconomy Corporation @brief SQLReport package This file contains the implementation of the qlreport portal component. Revision log: 1.0.0 JHO, 12-11-2002: Initial revision. / package MyPackage(1.0.0); // The include section of the M-Script file uses Framework::packages::std::BrowserType(1) / as BrowserType; This function calculates the load of an employee based on planning information from the Maconomy database. @return employeeload real @param employeenumber string / function getemployeename(employeenumber) { } var employeename = maconomy::mql (..).mqldata.rows[0]; return employeename; M-Script Programming 12
Deltek is the leading global provider of enterprise software and information solutions for professional services firms, government contractors, and government agencies. For decades, we have delivered actionable insight that empowers our customers to unlock their business potential. Over 14,000 organizations and 1.8 million users in approximately 80 countries around the world rely on Deltek to research and identify opportunities, win new business, optimize resource, streamline operations, and deliver more profitable projects. Deltek Know more. Do more. deltek.com