Document Version 1.1 Updated 6-May-2002 REBOL Technologies HTTP://www.rebol.com
Table of Contents
1. Version 2.5.2
1.1. CONSTRUCT Object Creator
1.2. LOAD No Longer Evaluates Script Header (Important)
1.3. HELP Expanded
1.4. SUFFIX? Function Added
1.5. SIGN? Function Added
1.6. COMPONENT? Function Added
1.7. SEND Function Updated
1.8. Miscellaneous Fixes
1.8.1. TYPE? (As used in PARSE)
1.8.2. MOLD/ALL
1.8.3. FTP on IIS and FTP Links
2. Version 2.5.1
2.1. Source Code Form for Values of NONE, TRUE, etc.
2.2. Less Aggressive Evaluation (Important!)
2.3. COMPOSE/ONLY Inserts Blocks
2.4. REMOVE-EACH - Easy Series Element Removal
2.5. ATTEMPT for Error Handling
2.6. EXTRACT Function Updated
2.7. SAVE to Memory
2.8. SEND Refinements /Subject /Attach
2.9. Difference for Date/time
2.10. System Port Added
2.11. Interpreter Fixes
2.12. Networking Fixes
2.13. Other Function Fixes
We've added a "light-evaluation" object creator to provide a higher level of security for imported data objects. The function is called CONSTRUCT and it makes new objects, but without a normal evaluation of the object's specification (as is done in the MAKE and CONTEXT functions).When you CONSTRUCT an object, only literal types are accepted. Functional evaluation is not performed. This allows your code to directly import objects (such as those sent from unsafe external sources such as email, cgi, etc.) without concern that they may include "hidden" side effects using executable code.
CONSTRUCT is used in the same way as the CONTEXT function:
but, no evaluation takes place. That means object specifications like:obj: construct [ name: "Fred" age: 27 city: "Ukiah" ]
do not produce their evaluated results.obj: construct [ name: uppercase "Fred" age: 20 + 7 time: now ]The CONSTRUCT function is useful for importing external objects. For example, loading preference settings from a file can done with:
Similarly, you can use CONSTRUCT to load a CGI or email response.prefs: construct load %prefs.rTo provide a template object that contains default variable values (similar to MAKE), use the /WITH refinement. The example below would use an existing object called standard-prefs as the template.
The CONSTRUCT function will perform evaluation on the words TRUE, FALSE, NONE, ON, and OFF to produce their expected values. Literal words and paths will also be evaluated to produce their respective words and paths. For example:prefs: construct/with load %prefs.r standard-prefs
The obj/a value would be logical TRUE, obj/b would be NONE, and obj/c would be WORD.obj: construct [ a: true b: none c: 'word ]
Script header objects are now created by the CONSTRUCT function and are no longer evaluated. The LOAD function can be used safely without the need to use LOAD/ALL to inspect a script header prior to evaluation.This change provides a greater level of default security when the LOAD function is used to load REBOL data (in CGI, VID fields, data files, libraries, etc). The change should affect few scripts (only those that depend on evaluated header variables, which is rare).
Help can now be used to explore the fields of an object in a user-friendly format. For example, typing this line at the prompt:
will produce this result:help system
This works for other types of objects as well as user-created objects. The code below would display the contents of the text-face object created by a View layout:SYSTEM is an object of value: version tuple! 1.0.4.3.1 build date! 1-May-2002/13:31:11-7:00 product word! Link components block! length: 45 words object! [unset! error! datatype! context! native! action! ... license string! {REBOL End User License Agreement IMPORTANT. READ ... options object! [home script path boot args do-arg link-url server... user object! [name email home words] script object! [title header parent path args words] console object! [history keys prompt result escape busy tab-size b... ports object! [input output echo system serial wait-list] network object! [host host-address] schemes object! [default Finger Whois Daytime SMTP POP IMAP HTTP F... error object! [throw note syntax script math access command resv... standard object! [script port port-flags email face sound] view object! [screen-face focal-face caret highlight-start high... stats native! System statistics. Default is to return total memo... locale object! [months days] user-license object! [name email id message]
Sub-objects can also be viewed. They are specified as paths. For example, to see the options object of the system object:out: layout [text-face: text "test"] help text-face
The result would look something like this:help system/options
In addition, the search feature in help now provides more information about matches that were made. If you type:SYSTEM/OPTIONS is an object of value: home file! %/d/rebol/link/ script file! %/d/rebol/link/ranch/utilities/console.r path file! %/d/rebol/link/ranch/ boot file! %/d/rebol/link/rebol-link.exe args none! none do-arg none! none link-url string! "tcp://localhost:4028" server none! none quiet logic! true trace logic! false help logic! false install logic! false boot-flags integer! 2064 binary-base integer! 16 cgi object! [server-software server-name gateway-interface ser...
You will now see:help "to-"
Found these words: caret-to-offset native! Returns the offset position relative to the face o... offset-to-caret native! Returns the offset in the face's text correspondin... to-binary function! Converts to binary value. to-bitset function! Converts to bitset value. to-block function! Converts to block value. to-char function! Converts to char value. to-date function! Converts to date value. to-decimal function! Converts to decimal value. to-email function! Converts to email value. to-event function! Converts to event value. to-file function! Converts to file value. to-get-word function! Converts to get-word value. to-hash function! Converts to hash value. to-hex native! Converts an integer to a hex issue!. to-idate function! Returns a standard Internet date string. to-image function! Converts to image value. to-integer function! Converts to integer value. to-issue function! Converts to issue value. to-list function! Converts to list value. to-lit-path function! Converts to lit-path value. to-lit-word function! Converts to lit-word value. to-local-file native! Converts a REBOL file path to the local system fil... to-logic function! Converts to logic value. to-money function! Converts to money value. to-none function! Converts to none value. to-pair function! Converts to pair value. to-paren function! Converts to paren value. to-path function! Converts to path value. to-rebol-file native! Converts a local system file path to a REBOL file ... to-refinement function! Converts to refinement value. to-set-path function! Converts to set-path value. to-set-word function! Converts to set-word value. to-string function! Converts to string value. to-tag function! Converts to tag value. to-time function! Converts to time value. to-tuple function! Converts to tuple value. to-url function! Converts to url value. to-word function! Converts to word value.
The SUFFIX? function is a helper function that returns the file "extension" portion of a filename or URL. For example:
SUFFIX? can be useful when selecting files from a directory. The example below will only select html and htm files:>> suffix? %into.txt == %.txt >> suffix? http://www.rebol.com/docs.html == %.html >> suffix? %test == none >> suffix? %test.it/file == none
foreach file load %. [ if find [%.html %.htm] suffix? file [ browse file ] ]
The SIGN? function returns a positive, zero, or negative integer based on the sign of its argument.
The sign is returned as an integer to allow it to be used as a multiplication term within an expression:print sign? 1000 print sign? 0 print sign? -1000
new: 2000 * sign val if size > 10 [xy: 10x20 * sign num]
COMPONENT? is a helper function that checks for the existence of a named REBOL component.
if component? 'crypt [print "Encryption available."] if not component? 'sound [print "No sound."]
The SEND function now includes a /SHOW refinement that will show all TO recipients in the header. By default, recipients are not normally shown.
In addition the FROM field will include the sender's name as well as an email address. The string in system/user/name is used as the from address. For example, if:send/show [bob@example.com fred@example.com] message
Then when the email is sent, the from field will now appear as:system/user/name: "Fred Reboller"
If system/user/name is NONE or empty, it will not be used.From: Fred Reboller <fred@example.com>Finally, some problems in the /ATTACH refinement have been fixed. Attachments of the form:
should work properly now. See 2.5.1 notes on SEND for more information about /ATTACH.send/attach user content [[%file.txt "text message"]]
1.8.1. TYPE? (As used in PARSE)
Fixed the problem reported in the TYPE? function that caused the datatype error in PARSE. Code of the form below will work properly now:
parse [34] reduce [type? 34] parse [34.5] reduce [type? 34.5]1.8.2. MOLD/ALL
Fixed the problem with function molding when /ALL refinement is provided.
load mold/all context [test: func [arg] [print arg]]1.8.3. FTP on IIS and FTP Links
Two fixes:
Thanks: Cal and Reichart at Prolific.com for submitting the above FTP fixes.
- When connecting to a Microsoft IIS based FTP server Rebol did not recognize folders correctly. They were marked as type 'directory but no slash was appended to the file name as done with other types of FTP servers.
- In FTP soft-links can now be identified. They can now return an file type of 'LINK.
To better support persistent values between SAVE, MOLD, and LOAD, a new syntactic element has been added to REBOL.In the past, the source code representation of values like NONE and TRUE required evaluation in order to convert those words into their actual values. For example:
would return the word NONE, not the value none. This required that your code either evaluate the result (with DO, REDUCE, or TRY) or manually convert the NONE word with code such as:load "NONE"
Thus, if you were storing REBOL data using MOLD or SAVE functions, when you read the data back in, you would need to either evaluate it (e.g. with REDUCE) or add checks for a few specific types of words (as shown above).if value = 'none [value: none]To better handle this situation with the literal expression of NONE, TRUE, FALSE, and other values that require evaluation, a new syntactic form has been added to the language:
Where datatype indicates the datatype and value provides its value. For simple datatypes such as NONE, TRUE, and FALSE the shorthand form:#[datatype value]
is also allowed. For example:#[word]
expresses the value NONE, not the word NONE, even with unevaluated code or data. Similarly,#[none]
express the values of TRUE and FALSE within non-evaluated code.#[true] #[false]The LOAD, DO, and other source translating functions have been expanded to accept this new syntax. The example below helps show the change:
The literal expression of REBOL objects is also allowed by this new format. For example the non-evaluated expression:block: load " none #[none] true #[true] " foreach value block [print type? value] word none word logic
is equivalent evaluating:#[object! [name: "Fred" skill: #[true]]]
Thus, a persistent (mold/load symmetric) form of objects now becomes available to programmers.make object! [ name: "Fred" skill: true ]To create or save source code or data using these new datatype expressions, the MOLD and SAVE functions have been given a new refinement called /ALL. This refinement will output the new #[] format for necessary values. For example:
word return the string:mold/all reduce ["Example" true none time]
Similarly, using SAVE/ALL would store the above expression to a file.["Example" #[true] #[none] 5-May-2002/9:08:04-7:00]
Variables are no longer aggressively evaluated.In previous versions of REBOL, variables that held set-words, parens, paths, and other evaluative datatypes would be evaluated on reference. That is no longer the case.
For example, in earlier versions, if you wrote:
the result would be an evaluation of b/c/d. This evaluation caused problems because it is more common to reference such data, not evaluate it. For instance, you want to be able to write:a: first [b/c/d] print a
and smoothly traverse the elements of the data block as simple values. You would not want those values to self evaluate.data: ["test" A: mold/only (10 + 2.5)] foreach value data [print value]This change to evaluation has some deeper implications. For example, it affects any function that specifies literal values within arguments. For example, code such as:
The REBOL design definition of a literal function argument is to accept the argument always as a literal value and NOT evaluate it. However, in the actual implementation it turned out that an evaluation would normally occur when the variable was referenced. (As part of the PRINT in this case.)f: func ['word] [print word]For instance, if you passed:
within the function, the reference to the word would cause the path to be evaluated at that point. Hence, if you referred to the word argument three times, each time it would be evaluated.f a/b/cThis implicit and "aggressive" evaluation, while interesting, was not intuitive, created hard to find errors, and generated error messages that were difficult to understand.
Consider the case where the set-word datatype might be passed as the argument:
The set word (test:) would be evaluated where WORD appears (in the PRINT line), and that operation would require an argument. The code would produce an error message that would tell you that set requires an argument. Yet, you would see no set within your code. It would look like an interpreter flaw, when in fact it was doing precisely what you asked.f test:Since the vast majority of REBOL programs do not rely on this type of evaluation, we've taken it out. This cleans up the semantics of literal arguments, but it also means that where programs depend on passing non-literals and assume that evaluation occurs, they do not. That will break some code, but it is rare. (For example, in the entire source code base of REBOL Technologies, there was only one such case.)
The COMPOSE function now has an /ONLY refinement similar to the INSERT/ONLY refinement. When /ONLY is specified, blocks that are inserted are inserted only as blocks, not as the elements of the block (the default). A REDUCE on the block is not required.For example:
>> block: [1 2 3] >> compose [example (block)] == [example 1 2 3] >> compose [example (reduce [block])] == [example [1 2 3]] >> compose/only [example (block)] == [example [1 2 3]]
The new function REMOVE-EACH works in a similar fashion to FOREACH and makes removing values from strings, blocks, and other series much easier.Also, in most cases REMOVE-EACH is many times faster than using a WHILE loop and the REMOVE function.
The format of REMOVE-EACH is identical to FOREACH except that it uses the result of the block expression to determine removal. REMOVE-EACH iterates over one or more elements of a series and evaluates a block for each. If the block returns FALSE or NONE, nothing is removed, but if the block returns any other value, the item (or items) are removed.
Similar to FOREACH, REMOVE-EACH can operate on multiple elements from the series (and uses the appropriate skip to get to the next set of elements):remove-each value series [expression]
Note that in addition to modifying the series, REMOVE-EACH also returns the series as its result.remove-each [val1 val2 val3] series [expression]Here are a number of examples.
To remove the odd numbers from block:
To remove all numbers greater than 10 from block:>> blk: [1 22 333 43 58] >> remove-each item blk [odd? item] == [22 58] >> probe blk == [22 58]
To remove all directories from a directory listing:>> blk: [3 4.5 20 34.5 6 50] >> remove-each item blk [item > 10] == [3 4.5 6] >> probe blk == [3 4.5 6]
To keep only the directories in the listing:>> dir: load %. >> remove-each file dir [#"/" = last file] == [%calculator.r %clock.r %console.r %find-file.r...]
To remove keep only the .doc files:remove-each file load %. [#"/" <> last file]
Here is an example of a block that uses multiple values:remove-each file load %. [not suffix? ".doc"]
REMOVE-EACH also removes characters from a string:blk: [ 1 "use it" 2 "rebol" 3 "great fun" 4 "the amazing bol" ] >> remove-each [num str] blk [even? num] == [ 1 "use it" 3 "great fun"] >> remove-each [num str] blk [not find str "bol"] == [ 2 "rebol" 4 "the amazing bol"]
>> str: "rebol is fun to use" >> remove-each chr str [chr = #"e"] == "rbol is fun to us" >> remove-each chr str [find "uno " chr] == "rblisfts"
The ATTEMPT function is a shortcut for the common REBOL idiom:
The format for ATTEMPT is:error? try [block]
ATTEMPT is useful in cases where you either do not care about the error result or you want to make simple types of decisions based on the error.attempt [block]For example, you may want to create a directory, but you don't care if the function fails:
Note that ATTEMPT returns the result of the block if an error did not occur. If an error did occur, a NONE is returned. For example, in the line:attempt [make-dir %fred]
the value may be set to NONE if the %data file cannot be loaded (e.g. it's missing or contains an error). This allows you to write conditional code such as:value: attempt [load %data]
Or, even simpler:if not value: attempt [load %data] [alert "Problem"]
In this line, if the file cannot be loaded, then the value is set to 1234.value: any [attempt [load %data] 1234]
The EXTRACT function now includes an /INDEX refinement to allow you to specify what "column" you want to extract. For example:
If index is not supplied, then the first column is extracted.data: [ 10 "fred" 1.2 20 "bob" 2.3 30 "ed" 4.5 ] >> probe extract/index data 3 2 == ["fred" "bob" "ed"]In addition, the extract function has been fixed to properly extract blocks from a block series.
The SAVE function can now write its results into memory. This is useful because the SAVE function contains formatting refinements that are found no where else.To use SAVE to write to memory, specify a binary value rather than a file name. For example:
Now the BIN binary holds the PNG formatted image. It was not necessary to write it to a file and read it back in.bin: make binary! 20000 ; (auto expands if necessary) image: load %fred.gif save/png bin image
The SEND function used for sending email has been extended to easily allow a subject line to be specified with a /SUBJECT refinement. This is a handy shortcut. For example:
The above example will send the text of the letter with a subject line as specified. If the /SUBJECT refinement is not given, then the first line of the letter would be used as the subject.letter: read %letter.txt send/subject luke@rebol.com letter "Here it is!"In addition, the SEND function can now include attachment files by providing an /ATTACH refinement. A single file or multiple files can be attached. The specified files can be read from disk or can be provide as a filename with data. The formats are:
You can also combine the formats.send/attach user letter file send/attach user letter [file1 file2 ...] send/attach user letter [[%filename data] ...]
Example attachments are:send/attach user letter [%file1 [%filename data] ...]
user: luke@rebol.com letter: read %letter.txt send/attach user letter %example.r send/attach user letter [%file1.txt %file2.jpg] send/attach user letter compose/deep [ [%options.txt (mold system/options)] ]
The DIFFERENCE function will now provide the time difference (hours, minutes, seconds) between two date/time values.
Normally, when you subtract date/time the result is the number of days, not time:>> difference now 1-jan-2000 == 20561:20:26
>> now - 1-jan-2000 == 856
The system port component was added. This component allows direct access to various OS-specific features. For example, the system port can catch Unix and Linux termination signals and perform a controlled shutdown. Under Win32, this port can be used to access win-messages.More information about the System Port component will be provided as a separate document.
The following internal interpreter problems have been fixed.
- Series Expansion: Significant performance and memory problem has been fixed resulting in many times greater speed in some types of uses. This change speeds up MOLD and SAVE by many times.
- Lit-path! comparison works properly
- Time zone bug in date comparison fixed
- Handling of "--" in command line arguments
- Tab expansion of words in console
- Component version numbers added to the boot message
- Increased the global word limit to 8000
- Potential crash during expansion and recycling of hash! values
- Potential crash when recycling open, unreferenced ports
- Port cleanup to close ports in the correct order
The following fixes were made to networking:
- DNS - Unix only: fixed lockup when DNS helper process dies unexpectedly.
- DNS - Unix only: DNS helper process no longer remains a "zombie" if the main process is killed.
- FTP - conflicts with generic proxy setups fixed
- FTP - allow more response codes from CWD command in FTP
- HTTP - proxy authentication added
- HTTP - POST linefeed conversion problem fixed
- HTTP - forwarding fixed where host name in header was not updated
- POP - will try APOP if port/algorithm is set to 'apop (workaround for bug in some POP servers).
- TCP - On Windows only: TCP listen sockets no longer allow multiple listeners on the same port. Workaround for bug in Windows TCP/IP stack regarding SO_REUSEADDR.
Fixes to natives and functions include:
- COMPRESS/DECOMPRESS - series offsets are now allowed
- DEBASE - potential crash fixed
- DEBASE - series offsets are now allowed
- FIND - when using bitset with chars greater than 127
- FIND/MATCH/CASE - fixed
- LOAD/MARKUP - potential crash fixed
- MAKE - potential crash with make object! object! fixed
- MAKE-DIR/DEEP - fixed bug
- SET-MODES - fixed file date setting when no time value is provided
- SORT - handles hashed blocks now, and potential crashes fixed
- UNION, INTERSECT, etc. - series offsets are now allowed on the second argument