Formatting Vision Output

Printing

Several variations of the print message are defined at Object including:

Message Definition
print Prints recipient object's value using default for class.
printNL Prints recipient object's value using default for class followed by a new line.
print: fmt Prints recipient object's value using supplied format.
printNL: fmt Prints recipient object's value using supplied format followed by a new line.
printWithCommas: fmt Prints recipient object's value using supplied format, inserting commas where appropriate if the recipient is a number.
printWithCommasNL:fmt Prints recipient object's value using supplied format, inserting commas where appropriate, followed by a new line.

By default, the print message displays the name of the object's class. Many classes redefine the print message. The Ordinal subclasses all print the value of the recipient object instead of the name of the class. The Entity subclasses all print the value of the object's code property by default. The print: message provides the user with control over the printing format. The interpretation of the supplied parameter depends on the recipient's class.

The following rules apply to String objects:

  • The print message prints all characters in the recipient object. All characters are printed; no truncation or padding occurs.
  • The parameter to the print: message controls the output width. The supplied parameter should be an integer. Only the integer portion of a decimal number will be used. The supplied parameter indicates the number of characters that should be output.
  • Strings containing fewer characters than the supplied width are padded with the appropriate number of blanks on the right (i.e., they are left-justified) by default. A string containing more characters than the supplied width will have its rightmost characters truncated.
  • If the supplied width is a negative value, the recipient will be padded with the blanks on the left (i.e., right-justified).
  • Strings can contain the new line and other special characters.

For example:

Expression Returns
"xyz" print: 1 x
"xyz" print: 2 xy
"xyz" print: 3 xyz
"xyz" print: 4 xyz#
"xyz" print: -4 #xyz

where the # indicates a blank.

The following rules apply to Integer objects:

  • The print message prints the value of the recipient in 9 character positions with no decimals places. The format is automatically expanded if more space is needed.
  • The parameter to the print: and printWithCommas: messages controls the output width. The supplied parameter should be an integer. Only the integer portion of a decimal number will be used. The supplied parameter indicates the number of characters that should be output. When using the comma format, you need to supply an integer wide enough to accommodate the additional comma characters as well.
  • Integers that require fewer positions than the supplied width are padded with the appropriate number of blanks on the left (i.e., they are right-justified) by default. If the specified width is not large enough, **** will be displayed instead of the value.
  • If the supplied width is a negative value, the recipient will be padded with the blanks on the right (i.e., left-justified).

For example:

Expression Returns
3 print: 10 #########3
3 print: -10 3#########
3 print: 2 #3
300 print: 2 **
3000 printWithCommas: 5 3,000
30000 print: 5 *****

where the # indicates a blank.

The following rules apply to Double and Float objects:

  • The print message prints the value of the recipient in 9 character positions with 2 decimal places. The format is automatically expanded if more space is needed.
  • The parameter to the print: and printWithCommas: messages controls the output width and the number of decimal places. The integer portion of the parameter indicates the total column width and the decimal portion of the parameter indicates the number of decimal digits. If the supplied parameter is an integer, the number of decimal places is assumed to be 2. The total column width should be wide enough to include the decimal point, decimal digits, and the commas if appropriate.
  • Numbers that require fewer positions than the supplied width are padded with the appropriate number of blanks on the left (i.e., they are right-justified) by default. If the specified width is not large enough, **** will be displayed instead of the value.
  • If the supplied width is a negative value, the recipient will be padded with the blanks on the right (i.e., left-justified).

For example:

Expression Returns
3.333 print: 8.1 #####3.3
3.333 print: 8.3 ###3.333
3.333 print: 8.5 #3.33300
3.333 print: -8.5 3.33300#

where the # indicates a blank.

The following rules apply to Date objects:

  • The print message prints the value of the recipient in M/D/Y format where M is a number from 1 - 12, D is a number from 1 - 31, and Y is the four-digit year.
  • The parameter to the print: message controls the output width and the type of date format used. The smallest width is 5. Any positive value less than 5 is reset to 5.
  • Dates that require fewer positions than the supplied width are padded with the appropriate number of blanks on the right (i.e., they are left-justified) by default.
  • If the supplied width is a negative value, the recipient will be padded with the blanks on the left (i.e., right-justified).

Possible widths and their related formats for displaying the date March 5, 1990 are summarized below:

Width Format Formats To
5 MM/YY #3/90
6 MM/YY# 03/90#
7 MM/YY## 03/90##
8 MM/DD/YY 03/05/90
9 MM/DD/YY# 03/05/90#
10 MM/DD/YYYY 03/05/1990
11 MM/DD/YYYY# 03/05/1990#
-11 #MM/DD/YYYY #03/05/1990

The following rules apply to the NA object:

  • The print message prints the string "NA " in 9 character positions (6 leading spaces and 1 trailing space).
  • The parameter to the print: message controls the output width. The supplied parameter should be an integer. Only the absolute value of the integer portion of a decimal number will be used. The supplied parameter indicates the number of characters that should be output. The string "NA " is always right justified in a field of the supplied width.

The print messages can be redefined as needed by a class. By convention, these messages are usually defined to return the recipient object (i.e., ^self) after performing the print. As a rule, only the print and print: messages need to be redefined. Since printNL is defined at Object to run the object's print message followed by printing a new line, it should not be necessary to redefine this message when you redefine print. For example:

  Entity defineMethod:
  [ | print |
    code print ; ^self
  ] ;

  Entity defineMethod: 
  [ | print: f |
    code print: f ; ^self
  ] ;
You can also define new variations of the print messages. For example, you could define printBar: to do a formatted print followed by a vertical bar character using:
  Object defineMethod:
  [ | printBar: f |
    ^self print: f ; "|" print ; ^self
  ] ;


Basic String Formatting

Many messages have been defined at the class String that aid in formatting your output. The messages take:, drop:, from:to:, from:for:, from:, and to: are used to extract a substring of the recipient string. The message concat: appends the supplied string to the end of the recipient string. For example:

  "This is a very long string" take: 8 . concat: "shorter" .
returns the string "This is shorter".

The messages center: and centerNL: are used to center the recipient string in the supplied width. For example:

  "This is a very long string" take: 8 .
     concat: "shorter" .
     center: 80 . printNL ;
centers the string "This is shorter" over 80 columns and print it.

The messages fill: and pad: are used to return a string containing the supplied number of characters. If the recipient string count is less than the parameter, the fill: message will repeat the characters in the recipient until a string of the specified length is formed. If the recipient string count is less than the parameter, the pad: message will pad the recipient with blanks. For example:

  "=" fill: 5 . concat: ">" . pad: 10
returns the string "=====>    ".


Converting Objects to Strings

As you have seen, there are a number of useful formatting messages defined at the class String. You can convert an object into a string by sending it the asString message which returns the result of sending the print message to the object as a string. For example:

  ^today asString center: 80 . print ;
converts the current date to a string, then centers and prints it.

The divertOutput message provides a general purpose way to create strings. Defined at the class Block, this message is designed to divert any print messages used in the block and returns a single string containing this output. For example, the program:

  !x <- 2 + 2 ;
  "The answer is: " print ;
   x printNL ;
prints the string followed by the value. If you wanted to center this entire output, you could use divertOutput to capture the results first:
  [ !x <- 2 + 2 ;
    "The answer is: " print ;
    x print ;
  ] divertOutput center: 80 . print ;

Several messages have been defined to convert dates into strings using different date formats:

Expression Returns String
960305 asDate formatUsingLongName March 5, 1996
960305 asDate formatUsingShortName _5-Mar-1996
960305 asDate formatUsingMMDD 03/05
960305 asDate formatUsingMMDDYY 03/05/96
960305 asDate formatUsingMMDDYYYY 03/05/1996

For example, to center the current date formatted using its long name, you could use the expression:

  ^today formatUsingLongName center: 80 . print ;


Output Files

The messages substituteOutputOf: and appendOutputOf: are defined at the class String to allow you to create/overwrite a file or append output to an existing file. The recipient string provides the filename. The parameter to these messages should be a block. All print statements encountered in the block are printed to the file instead of your standard output device. For example, the expression:

  "myFile" appendOutputOf:
     [ "First 10 Squares" centerNL: 20 . print ;
       10 sequence
       do: [ !currentNumber <- ^self ;
             currentNumber print: 10 ;
             currentNumber * currentNumber printNL: 10 ;
           ] ;
     ] ;
creates a table of the first 10 integers and their squares and appends this output to the end of the file myFile. No output will be displayed on your standard output device.

The message filterOutputOf: can be used to submit the output from a Vision request to another program. This message is sent to a string containing the name of the operating system level command or program to run. The parameter is a block. Any printing performed within the block is sent to the external program as standard input. Any output generating by the external program is returned and printed by default. For example, suppose you wanted to use the Unix utility grep to select the numbers in the first 1000 integers that contain the digits 10. You could use the expression:

  "grep 10" filterOutputOf:
     [ 1000 sequence do: [ printNL ] ;
     ] ;
The results are displayed on your output device. The expression:
  !result <-
     [ "grep 10" filterOutputOf: [ 1000 sequence do: [ printNL ] ] ;
     ] divertOutput ;
can be used to capture the result a string.


Additional Formatting

The message formatForExcel can be sent to a block and generates tab-delimited output suitable for loading into Excel and other many other packages. The message returns a string. Any print statement encountered while executing this block will be followed by a tab character. For example:

  [ 100 sequence
    do: [ print ;
          (^self + 1 ) asInteger print ;
          (^self * 2 ) asInteger printNL ;
        ]
  ] formatForExcel print ;
To save these results to an output file named myFile use:
  "myFile" substituteOutputOf: [
     [ 100 sequence
       do: [ print ;
             (^self + 1 ) asInteger print ;
             (^self * 2 ) asInteger printNL ;
           ]
     ] formatForExcel print ;
  ] ;
The formatForExcel message uses the divertDelimitedOutput message to mark the spots in the output where printing has occurred. Each print statement encountered while evaluating the block will be followed by the octal 377 character, returning the result as a string. This character can be translated into any other character using the translate:to: message. For example:
  #-- capture output delimited by octal 377 character
  !output <-
     [ 100 sequence
       do: [ print ;
             (^self + 1 ) asInteger print ;
             (^self * 2 ) asInteger printNL ;
           ]
     ] divertDelimitedOutput ;

  #-- convert character into | and print
  !delimiter <- "\377" ;     #- must be actual octal character
  output translate: delimiter to: "|" . print ;

Related Topics