As you have hopefully seen from some of the examples included with Sloup, a transaction with Sloup consists of a sequence of command lines sent from the desktop. The simplest sequence consists of:
There are several variations on this: other commands/lines that can be included; and a "line" can consist of several lines, but before getting into that complexity, let's look at a sample transaction in slow motion to see how Sloup's status messages reflect where it thinks it is in this sequence.
Here is a preview of some possible variations in the above example of a Sloup file/transaction. These will be explained in more detail later.
MySoup![] {....} ... BYE![{structure: 'slot, type:...}
This allows the data entries to processed faster; however, when indexes are added at the end, the total time is greater (since entries have to be accessed again). Sloup only adds the indexes if there are none present, e.g., it assumes you have removed the soup earlier, or are using the same existing indexes. (To add just some indexes to some stores involves too much code that relies on undocumented features of how soups are represented). I would generally recommend that you add indexes first, but now you have a choice.
Since there are some differences between import and export, and between Notes and other soups, here is a summary of the four basic kinds of transfer supported by Sloup:
Here is a simple example of importing text into the Business folder.
Notes {labels: 'Business, viewFont: 10241} text a second line in same paragraph ----- another para ----- ----- BYE!
Notes is the soup name for the notepad; 2.x users can also use Newtworks to transfer plain text documents to Newtworks.
The entrySpec for Notes/Newtworks is used to specify several default values.
labels is a symbol corresponding to a folder destination, e.g., 'Personal, 'Business, or nil or 'nil (for Unfiled). If the label contains non-alphanumeric characters, you need to wrap the symbol with vertical bars, e.g., '|two words!|. If you include a symbol for labels slot that does not (yet) exist, be sure to Edit Folders later on your Newton to add it -- otherwise, the only way you'll see these notes is via All Notes
Notes entrySpec import examples:
If you know what you are doing (and have backed things up first), you can insert an ERASE! command after the entrySpec. This erases all entries from the specified soup; or if you've specified labels in your frame spec (for Names or Notes), it erases just the entries in that folder; if a field has labels, you can specify the symbol _all to erase entries in all folders, e.g., {labels: '_all}. ERASE! can be handy especially if want to get rid of many existing entries before adding new information (also see REPLACE! for selective replacement). Warning: this does not give you a dialog box asking to Confirm erasing of entries!
For example, if you edited Newt sources for your project on the desktop, and wanted to replace these completely on your Newton, you could do something like:
Notes {labels: 'Personal, viewFont: 10241} ERASE! myApp {_proto: protoApp, } ----- myApp+aButton {_proto: protoTextButton, viewBounds: RelBounds(10,20,50,15), } ----- BYE!
Although a soup is like a database and may have an index that treats a particular slot as a "primary key", Sloup does no checking to eliminate duplicates. So, it always adds new entries. Instead of erasing an entire folder and then storing entries, you could instead specify a slot to identify an entry; if an entry with the same name already exists, the new entry would replace the entry. You can also remove individual entries with a soup utility.
For Notes, title is the only slot supported, so REPLACE!title would replace any note that has the same title -- this works on 1.x by using the first line of the text as the "title". For Newt, the first line of a note is typically a unique identifier, e.g., "MyApp+button1"; for Newt's Cape, the first line could be a comment indicating the filename, e.g., <!--foo.htm-->
Note: all entries are added to the default store, e.g., on your memory card if "Store new items on card" is checked. If you "replace" an existing entry, the old entry is actually removed from its existing store, and a new entry is created on the default store.
You can Export text to desktop and Export data to desktop by using DUMP!. You can follow DUMP immediately with a frame, i.e., DUMP!{...}) to specify parameters related to delay, print function, field, record and soup (eof) delimiters. Final field always is followed by a field delimiter (previously, only record delimiter). Here are the slots you can specify (along with defaults):
Each note is separated by a line of at least 5 dashes, i.e., -----. The last note separator is optional: BYE! will also terminate the last Note. Empty notes are not saved to the Notepad.
For NOS 2.x systems, you can import text into outlines and checkLists using class. Each line is an entry; tabs indicate level. For example, this would add two checkLists to the Unfiled folder:
Notes {labels: nil, class: 'checkList} a checklist in Unfiled second level a next level item ----- another checklist indented1 indented2 another main entry indented1 BYE!
Add two lists to 2.x Business folder (lists are called outlines in the New picker):
Notes {labels: 'Business, class: 'list, viewFont: {family: 'casual, face: 0, size: 10}} an outline in Business indented item another indented item ----- another outline indented1 indented2 another main entry indented1 BYE!
For dumping (exporting) text to the desktop from Notes (or Newtworks for 2.x users), you can specify a folder, and several fields:
Note about field order: Sloup does not output class, and it defers title until just before the text; otherwise, fields (labels and _modTime) should appear in the order specified. Currently, entries are dumped from all mounted stores (internal, card,...).
DUMP! all Notes in Business folder
Notes {labels: 'Business} DUMP!
For NOS 2.x systems, that specification would have included all classes of Notes. You can also select just lists (outlines) or checkLists.
Dump just Unfiled checkLists:
Notes {labels: nil, class: 'checkList} DUMP!
Dump just plain notes (no checkLists or outlines) from all folders, along with titles and modification dates:
Notes {class: 'paperRoll, title: "string", _modTime: "dateTime"} DUMP!
Dump just Business outlines (i.e., lists):
Notes {labels: 'Business, class: 'list} DUMP!
Importing general data is more complicated than for Notes: there can be many fields and different data types, depending on the soup --these fields and types may or may not be documented. Each data entry is represented as single line of tab-delimited text (unless there are line continuations). For example, see CasioNam.tab. Blank lines are ignored
Sloup assumes that no more than approximately 20 fields are embedded at one level in one frame (you could have more than 20 fields total if you have nested frames or arrays); the order of values in a line must correspond to the order of slots in the frame spec. For small (<20) number of slots, the frame spec maintains a linear order when it is compiled; however, for larger number of slots this ordering is not preserved (I have no plans to redesign Sloup to avoid this limitation).
Since exporting uses the same entrySpecs, I will discuss these and provide examples a little later.
Assuming you have a valid entrySpec, export (DUMP!) is quite simple. The following example works if you have already created "testSoup" (if not, go to the later Soup Indexes section; then come back)
TestSoup {a: "int", b: "string"} DUMP!
For example, see CasioNam.dmp. Entries are written to terminal emulator as tab-delimited lines in frame specification order. (If possible, you should have your terminal emulator preserve tabs, wrap lines (rather than overwrite characters), and save/capture to a log file). Any data fields with text values that contain newlines will be transmitted as is -- you may need to re-edit results into a true tab-delimited text format, or modify field delimiters.
If you do not know the fields and value types for a soup, you can specify an empty frame {} as the entrySpec. In this case, Sloup will dump an pseudo-entrySpec based on the first soup entry, and then dump all remaining entries with respect to this entry. (This works only if levels of the soup structure are less than 20 in length, and subsequent entries are similar in structure to the first entry).
TestSoup {} DUMP!
Although you can use Sloup to discover soup structure, I would recommend that you use documentation wherever possible (e.g., additional Sloup docs for built-in soups like Notes and Names), or soup utilities (e.g., StewPot) or NTK Inspector. And of course, backup your Newton to avoid possible damage.
There are several special names that can occur in the soupname position (first line of a transaction) and are handled specially.
Package {} DUMP!
Sloup {fieldDelimiter: ",", stripQuotes: true,...} Names {....} ... BYE! Sloup {}
Or if you had earlier made global changes earlier and wanted to ensure that defaults were used:
Sloup {} ...
Here are the global fields you can set in a Sloup entry:
Sloup {convertUnicode: true} Notes {labels: nil} first line upsidedown question mark \u00BF\u embedded enye at end of line \u00F1 \u00A700A52126\u -- a few in a row in lowercase: copyright \u00a9\u yen \u00a5\u BYE! Sloup {}
default: "\u001A". ctrl-z. Evaluates the current selection or field (in Newt, in the Notepad, or any input field) as a NewtonScript expression. If Newt is installed, Sloup uses Newt's read/eval/print capability for the current expression; otherwise, Sloup does a simpler compile and print (only of immediate value results: strings, numbers, characters). Any errors messages also appear in the terminal window. (Newt, if present, decodes some of the common error codes). After an Eval, you'll hear a "plunk" sound. If the current field is Newt' source editor, the current object or method is Saved (it's checked/compiled) Some expressions to try:
3 3/ //syntax err 3/2 3/x //undef var 3/0 //div by 0 [2,4,6,8,10][0] "Hello," && userConfiguration.name {person: {lastName: "Smith", firstName: "John"}}.person.lastName GetRoot():Notify(3,"AN ERROR!", "(not)")
For illustration purposes (since this is redundant), assume you want to set esc as the clearKey. The unicode value for esc is 001B. So, to turn off debug printing and override this one key (the others are still defaulted):
Sloup {debug: nil, clearKey: $\u001B,}
Since these options are sticky across subsequent connects (until the next time you specify global settings), there are several strategies for multiple files:
Here is an example of using a line continuation in entrySpec, setting several parameters, and resetting at end:
Sloup {fieldDelimiter: ",", stripQuotes: true,\ translationTable: ["N~", "\u00D1"], totalRecords: 3} mysoup![] {a: "string", b: "string"} field1,"field2 with extra quotes" "xxx",eN~ye 3rd,entry BYE! Sloup {} // restore defaults (optional)
In the default situation, when a soup name does not exist, Sloup ignores it and subsequent lines until it finds a valid soup name.You can also create a new soup by appending ! to the soup name and including an array of soup indexes (this will also find an existing soup; to add new indexes, it is best to remove and reinitialize the soup). Before doing this, you should feel comfortable with transferring entries into existing soups and customizing an entrySpec. I would also recommend obtaining a soup utility so that you can inspect entries, remove entries and remove soups (if necessary).
To create a soup, follow the name with a ! followed by an array of index specifications, e.g., [] is none. The soup is created as a "union" soup; on 1.x, this is created on each store, i.e., internal memory and card, leading to some empty soups; on 2.x, the soup is created only on the current default store.
TestSoup![] {a: "int", b: "string"} 0 hello 1 there BYE!
Here is an example of a different soupname line if you had wanted to index on the integer field a:
TestSoup![{structure: 'slot, path: 'a, type: 'int},]
Indexes can be useful to applications for random access or for accessing soup entries in a particular sort order. For examples of other index specs see the NTK docs, or the bitmap and sound examples (next); more docs to follow...
You can add the indexes for a soup at the end (BYE!).
This is the most complicated part of Sloup. You need to specify the correct slot names and value types. For standard soups, you can discover this from NTK or additional Sloup documentation or examples. In general, you can use a soup utility (like StewPot) to inspect a soup, or print frames with the NTK Inspector or NewtDevEnv. Or, you can DUMP! a soup using an empty frame spec (note: this corresponds to the first soup entry, and requires Newt for complex entries).
Here is a summary of value types that you may encounter or wish to use. These would generally be specified as strings, i.e., enclosed in double quotes, e.g., "int".
slot | example | |
---|---|---|
longDateStrSpec (L) | Wednesday, July 22, 1992 | |
abbrDateStrSpec (L) | Wed, Jul 22, 1992 | |
yearMonthDayStrSpec (L) | July 22, 1992 | |
yearMonthStrSpec (L) | July 1992 | |
dayStrSpec (L) | Wed, Jul 22 | |
monthDayStrSpec (L) | July 22 | |
numericDateStrSpec (LS) | 7/22/92 | |
numericMDStrSpec (S) | 7/22 | |
numericYearStrSpec (LS) | 1992 | |
longMonthStrSpec (L) | July | |
abbrMonthStrSpec (L) | Jul | |
numericDayStrSpec (LS) | 22 | |
longDayOfWeekStrSpec (L) | Wednesday | |
abbrDayOfWeekStrSpec (L) | Wed | |
longTimeStrSpec (T) | 10:40:59 AM | |
shortTimeStrSpec (T) | 10:40 AM | |
shortestTimeStrSpec (T) | 10:40 | |
hourStrSpec (T) | x | 10 |
minuteStrSpec (T) | 40 | |
secondStrSpec (T) | 59 |
So, you could include a date (either long or short) and/or a time.
{... _modTime: "dateTimeSpecs:[@66.longDateStrSpec, nil, @66.longTimeStrSpec]",...}
You could also combine constants (e.g., adding different month + year components). Full details on format constants may be found in the Newton Toolkit Documentation:
Version 2.1. Last updated: Jan 1998