Core
Core
Core
REBOL/CORE USER
GUIDE
VERSION 2.3
SEPTEMBER 2000
REBOL™ Technologies, 301 South State Street, Ukiah, CA 95482
http://www.REBOL.com
Copyright © 2000 REBOL Technologies
All rights reserved.
Printed in the United States of America
No part of this publication may be stored in a retrieval system, transmitted, or reproduced in any way, including
but not limited to photocopy, photographic, magnetic or other record, without the prior agreement and written
permission of REBOL Technologies.
All other product names, marks, logos, and symbols may be trademarks or registered trademarks of their
respective owners.
We would like to thank the following individuals for their contributions in the production of this manual:
09292000
Contents
Introduction
About REBOL/Core . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xxii
About this Guide . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xxii
Additional Documentation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xxiii
Document Conventions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xxiii
Contacting REBOL Technical Support . . . . . . . . . . . . . . . . . . . . . . . . . xxiii
REBOL Welcomes Your Comments . . . . . . . . . . . . . . . . . . . . . . . . . . . xxiv
Chapter 1. Operation
Installing REBOL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1-2
Distribution Files . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1-2
Network Setup . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1-2
Proxy and Firewall Settings . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1-3
License Agreement . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1-4
Starting REBOL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1-4
From an Icon . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1-4
From a Shell . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1-5
From Another Application . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1-5
Security Issues . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1-5
Program Arguments . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1-9
Script File . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .1-10
Specifying Options . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .1-10
File Redirection . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .1-12
Script Arguments . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .1-12
iii
Startup Files . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1-13
Quitting REBOL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1-14
Using the Console . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1-14
Mulitple Line Input . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1-15
Interrupting a Script . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1-16
History Recall . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1-16
Word Completion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1-16
Busy Indicator . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1-17
Network Connections . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1-17
Virtual Terminal . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1-17
Getting Help . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1-18
Online Help . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1-18
Viewing Source Code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1-22
Download Documents . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1-23
Script Library . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1-23
User Mailing List . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1-23
Contacting Us . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1-23
Errors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1-25
Error Messages . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1-25
Redirecting Errors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1-26
Upgrading . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1-26
iv
Strings . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2-4
Tags . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2-4
Email Addresses . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2-4
URLs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2-5
Filenames . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2-5
Pairs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2-5
Issues . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2-6
Binary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2-6
Words . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2-6
Blocks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2-7
Variables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2-9
Evaluation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2-10
Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2-12
Paths . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2-13
Objects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2-15
Scripts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2-16
Files . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2-17
Networking . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2-19
HTTP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .2-19
FTP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .2-20
SMTP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .2-20
POP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .2-20
NNTP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2-21
Daytime . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2-21
Whois . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2-21
Finger . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2-21
DNS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .2-22
TCP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .2-22
v
Chapter 3. Expressions
Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3-2
Blocks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3-4
Values . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3-5
Evaluating Expressions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3-6
Evaluating Console Input . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3-6
Evaluating Directly Expressed Values . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3-6
Evaluating Blocks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3-7
Reducing Blocks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3-9
Evaluating Scripts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .3-10
Evaluating Strings . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3-11
Evaluation Errors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3-12
Words . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3-13
Word Names . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3-13
Word Usage . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3-15
Setting Words . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3-16
Getting Words . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3-18
Literal Words . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3-19
Unset Words . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .3-21
Protecting Words . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3-22
Conditional Evaluation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3-23
Conditional Blocks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3-23
Any and All . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3-26
Conditional Loops . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3-28
Common Mistakes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3-30
Repeated Evaluation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3-31
Loop . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .3-31
Repeat . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3-32
For . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3-33
Foreach . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3-35
vi
Forall and Forskip . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .3-36
Forever . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .3-38
Break . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .3-38
Selective Evaluation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3-40
Select . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .3-40
Switch . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .3-41
Stopping Evaluation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3-45
Trying Blocks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3-46
Chapter 4. Scripts
Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4-2
File Suffix . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4-2
Structure . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4-2
Headers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4-2
Script Arguments . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4-7
Program Options . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4-8
Running Scripts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4-9
Loading Scripts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4-9
Saving Scripts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4-11
Commenting Scripts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .4-12
Style Guide . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4-13
Formatting . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .4-13
Word Names . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .4-16
Script Headers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .4-18
Function Headers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .4-18
Script File Names . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .4-18
Embedded Examples . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .4-19
Embedded Debugging . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .4-19
Minimize Globals . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .4-19
Script Cleanup . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4-20
vii
Chapter 5. Series
Basic Concepts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5-2
Traversing a Series . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5-2
Skipping Around . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5-7
Extracting Values . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .5-10
Extracting a Sub-series . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5-12
Inserting and Appending . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5-13
Removing Values . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5-16
Changing Values . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5-19
Series Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5-21
Creation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .5-21
Navigation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .5-21
Information . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5-22
Extraction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5-22
Modification . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5-23
Search . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5-23
Ordering . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5-24
Data Sets . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5-24
Series Data Types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5-24
Block Types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5-25
String Types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5-25
Pseudo-types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5-26
Type Test Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5-26
Series Information . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5-26
Length? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5-26
Head? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5-29
Tail? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5-29
Index? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5-30
Offset? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .5-31
Making and Copying Series . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5-31
vii i
Partial Copies . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .5-33
Deep Copies . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .5-33
Initial Copies . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .5-34
Series Iteration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5-36
While Loop . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .5-36
Forall Loop . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .5-37
Forskip Loop . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .5-39
Foreach Loop . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .5-39
The Break Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .5-40
Searching Series . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5-41
Simple Find . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .5-41
Refinement Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .5-42
Partial Searches . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .5-43
Tail Positions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .5-44
Backward Searches . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .5-45
Repeated Searches . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .5-46
Matching . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .5-46
Wildcard Searches . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .5-49
Select . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .5-50
Search and Replace . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5-51
Sorting Series . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5-53
Simple Sorting . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .5-54
Group Sorting . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .5-56
Comparison Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .5-56
Series as Data Sets . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5-57
Unique . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .5-58
Intersect . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .5-58
Union . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .5-60
Exclude . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .5-62
Difference . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .5-62
Multiple Series Variables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5-64
ix
Modification Refinements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5-65
Part . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5-65
Only . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5-67
Dup . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5-67
x
Chapter 8. Functions
Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8-2
Evaluating Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8-3
Arguments . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8-3
Argument Data Types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8-5
Refinements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8-7
Function Values . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8-9
Defining Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8-10
Interface Specifications . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8-11
Literal Arguments . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .8-14
Get Arguments . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .8-16
Defining Refinements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .8-17
Local Variables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .8-18
Returning a Value . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .8-20
Returning Multiple Values . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .8-22
Nested Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8-23
Unnamed Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8-24
Conditional Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8-25
Function Attributes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8-26
Forward References . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8-29
Scope of Variables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8-29
Reflective Properties . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8-31
Online Function Help . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8-33
Viewing Source Code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8-35
Chapter 9. Objects
Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9-2
Making Objects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9-2
Cloning Objects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9-4
xi
Accessing Objects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9-6
Object Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9-7
Prototype Objects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9-10
Referring to Self . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9-12
Encapsulation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9-13
Reflective Properties . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9-15
xii
strict-equal . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10-26
strict-not-equal . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10-27
Logarithmic Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10-28
exp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10-28
log-10 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10-28
log-2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10-29
log-e . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10-29
power . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10-29
square-root . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10-29
Trigonometric Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10-29
arccosine . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10-29
arcsine . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10-30
arctangent . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10-30
cosine . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10-30
sine . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10-30
tangent . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10-30
Logic Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10-31
and . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10-31
or . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10-32
xor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10-32
complement . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10-33
not . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10-33
Errors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10-33
Attempt to divide by zero . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10-34
Math or number overflow . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10-34
Positive number required . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10-34
Cannot use operator on datatype! value . . . . . . . . . . . . . . . . . . . . . . . . . 10-34
x iii
File Names . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11-2
Path Strings . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11-3
Case Sensitivity . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11-5
File Name Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11-5
Reading Files . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11-6
Reading Text Files . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11-6
Reading Binary Files . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11-7
Reading Over the Network . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11-7
Writing Files . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11-8
Writing Text Files . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11-8
Writing Binary Files . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11-9
Writing Files to a Network . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11-9
Line Conversion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11-10
Blocks of Lines . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11-11
File and Directory Information . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11-13
Directory Check . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11-13
File Existence . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11-14
File Size . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11-14
File Modification Date . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11-14
Directory Information . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11-15
Directories . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11-16
Reading a Directory . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11-16
Making a Directory . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11-17
Renaming Directories and Files . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11-17
Deleting Directories and Files . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11-18
Current Directory . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11-19
Changing the Current Directory . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11-19
Listing the Current Directory . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11-19
xiv
Chapter 12. Network Protocols
Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12-2
REBOL Networking Basics . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12-3
Modes of Operation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .12-3
Specifying Network Resources . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .12-4
Schemes, Handlers, and Protocols . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .12-6
Initial Setup . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12-9
Basic Network Settings . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .12-9
Proxy Settings . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12-10
Other Settings . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .12-12
Access to Settings . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .12-13
DNS - Domain Name Service . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12-14
Whois Protocol . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12-16
Finger Protocol . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12-18
Daytime - Network Time Protocol . . . . . . . . . . . . . . . . . . . . . . . . . . 12-19
HTTP - Hyper Text Transfer Protocol . . . . . . . . . . . . . . . . . . . . . . . . 12-20
Reading a Web Page . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .12-20
Scripts on Web Sites . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12-21
Loading Markup Pages . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .12-22
Other Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .12-24
Acting Like a Browser . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .12-25
Posting CGI Requests . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .12-25
SMTP - Simple Mail Transport Protocol . . . . . . . . . . . . . . . . . . . . . . . 12-26
Sending Email . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .12-26
Multiple Recipients . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .12-27
Bulk Mail . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .12-28
Subject Line and Headers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .12-29
Debug Your Scripts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .12-29
POP – Post Office Protocol . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12-30
Reading Email . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12-30
xv
Removing Email . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .12-32
Handling Email Headers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .12-33
FTP - File Transfer Protocol . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12-36
Using FTP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .12-36
FTP URLs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .12-37
Transferring Text Files . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .12-37
Transferring Binary Files . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .12-39
Appending to Files . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .12-39
Reading Directories . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .12-40
File Information . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .12-40
Making Directories . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .12-42
Deleting Files . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .12-42
Renaming Files . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .12-42
About Passwords . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .12-43
Transferring Large Files . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .12-44
NNTP – Network News Transfer Protocol . . . . . . . . . . . . . . . . . . . . . 12-45
Reading the Newsgroup List . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .12-45
Reading All Messages . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .12-45
Reading Single Messages . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .12-46
Handling News Headers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .12-47
Sending a News Message . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .12-47
CGI - Common Gateway Interface . . . . . . . . . . . . . . . . . . . . . . . . . . 12-49
CGI Server Setup . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .12-49
CGI Scripts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .12-50
Generating HTML Content . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .12-52
CGI Environment . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .12-53
CGI Requests . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .12-54
Processing HTML Forms . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .12-56
TCP - Transmission Control Protocol . . . . . . . . . . . . . . . . . . . . . . . . 12-59
Creating Clients . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .12-59
Creating Servers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12-61
xvi
A Tiny Server . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .12-63
Testing TCP Code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .12-64
UDP (User Datagram Protocol) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .12-64
x vii
Return Value . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14-11
Expressions in Rules . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .14-12
Copying the Input . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .14-14
Marking the Input . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .14-14
Modifying the String . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .14-16
Using Objects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .14-17
Debugging . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .14-18
Dealing with Spaces . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14-19
Parsing Blocks and Dialects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14-21
Matching Words . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14-21
Matching Data Types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .14-22
Characters Not Allowed . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .14-22
Dialect Examples . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .14-22
Parsing Sub-blocks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .14-24
Summary of Parse Operations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14-26
Appendix A. Values
Number Values . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . A-2
Decimal . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . A-2
Integer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . A-5
Series Values . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . A-8
Binary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . A-8
Block . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . A-10
Email . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . A-14
File . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . A-17
Hash . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . A-19
Image . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . A-20
Issue . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . A-22
List . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . A-24
Paren . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . A-27
Path . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . A-30
xvi ii
String . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . A-40
Tag . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . A-43
URL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . A-45
Other Values . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . A-48
Character . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . A-48
Date . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .A-51
Logic . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . A-58
Money . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . A-62
None . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . A-67
Pair . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . A-69
Time . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . A-71
Tuple . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . A-77
Words . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . A-79
Appendix B. Errors
Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .B-2
Error Categories . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . B-2
Syntax Errors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . B-2
Script Errors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . B-3
Math Errors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . B-3
Access Errors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . B-3
User Errors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . B-3
Internal Errors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . B-3
Catching Errors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . B-3
Error Object . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . B-6
Generating Errors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . B-7
Error Messages . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . B-11
Syntax Errors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .B-11
Script Errors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . B-12
Access Errors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . B-22
x ix
Internal Errors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . B-28
Appendix C. Console
Command Prompt . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . C-2
History Recall . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . C-2
Busy Indicator . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . C-3
Advanced Console Operations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . C-3
Keyboard Input Sequences . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . C-4
Terminal Output Sequences . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . C-4
xx
Introduction
xxi
About REBOL/Core 0
REBOL is the next generation of distributed communications. REBOL code and data
can span more than 40 platforms without modification using ten built-in Internet
protocols. A script written and executed on a Windows platform can also be run on
a UNIX platform with no changes. REBOL can exchange not only traditional files
and text, but also graphical user interface content and domain specific dialects that
communicate specific meaning between systems. Distributed communications
includes information exchanged between computers, between people and
computers, and between people. REBOL can be used for all of these.
REBOL scripts are as easy to write as HTML or shell scripts. A script can be a single
line or an entire application.
This guide provides the basic information necessary for using REBOL/Core. It
assumes that the reader is already familiar with general programming and operating
system terminology and concepts.
REBOL Dictionary
For copies of these documents, please refer to the REBOL Technologies Web
site at http://www.REBOL.com.
Document Conventions 0
The following table describes the typographical conventions used in this guide.
do %feedback.r
Using the feedback script automatically includes your REBOL version number in the
email sent to REBOL's help desk.
To help us with future versions of this documentation, we want to know about any
corrections or clarifications that you would find useful. Please include in your
message the following information:
■ Your name, company name, job title or functional area, phone number, and
email address
This chapter gives basic information on how to install and operate REBOL/Core. It
includes the following information:
1- 1
Operation
Installing REBOL
Installing REBOL A
REBOL installation takes only a few seconds and is very easy, non-intrusive, and
non-disruptive.
For other REBOL products, installation may require you to provide additional
information, such as where to store related files. Refer to the release notes that are
included with the distribution files.
Distribution Files 0
■ scripts.r— A script that downloads the REBOL script library, which contains
Network Setup 0
The first time you start REBOL, it prompts you for network information. This
information is optional. Some protocols, such as email or FTP, require an email
address or an email server name. In addition, if you are behind a firewall or use a
proxy server, you need to provide specific information to access the Internet.
■ Use the name of the email server you normally use. If you are not sure of the
name of the server, contact your network administrator or Internet service
provider for the name of your SMTP (email) server.
■ Specify whether you use a proxy server. If you are directly connected to the
Internet with a modem or ethernet, type N (no). If you use a proxy or firewall,
provide the required information as described in “Proxy and Firewall Settings”
below.
■ Once the startup questions are answered, REBOL creates a user.r file and
places your network settings in it. You can change these settings at any time by
editing the user.r file.
Frequently, organizations use a firewall or proxy server to protect access to and from
the Internet. Before REBOL can access the Internet through these systems, you need
to provide some additional information.
■ When REBOL asks if you use a proxy server, answer by typing Y (yes).
■ Type the name of your proxy host. This is the computer or firewall on your
network serving as a proxy.
■ Type the port number used by the proxy host for proxy requests. Typically, this
is port 1080, but this can vary. If you don’t know the port number, check your
Web browser settings or ask your network administrator.
REBOL defaults to using a SOCKS proxy protocol. You can specify some other type
of proxy by editing the user.r file and supplying the set-net function with the
appropriate identification for the type of proxy being used. The following settings
are supported:
These settings are provided as the sixth argument to the set-net function called in
the user.r file. For more information about modifying the proxy settings in the
user.r file, refer to the “Network Protocols” Chapter.
License Agreement 0
The REBOL end-user license agreement that you agreed to when you downloaded
or installed REBOL can be viewed at any time from the REBOL console by typing
license at the REBOL prompt.
Starting REBOL A
REBOL runs over a large variety of systems. You start REBOL the same way you
start other applications on your system. Depending on the specific operating
system, REBOL can be started from one or more of the following: an icon, the
command shell, or other applications.
From an Icon 0
If you double-click on the program icon, REBOL boots, displays the console, and
provides you with a prompt.
If you want to launch REBOL with a script, you can do so in the following ways:
From a Shell 0
From a shell command line, go to the directory that contains the REBOL.exe file,
and type rebol or ./rebol.
On some operating systems, such as UNIX, you can create alias shell commands
that are able to run REBOL with a set of arguments and files. In addition, UNIX
enables you to create shell scripts that include a path, such as !#/path/to/rebol,
in the top line of the script file. When you type the name of the script file at the
command prompt, UNIX will launch REBOL to execute the script.
For writing and debugging REBOL scripts, it is handy to set up your favorite text
editor to run REBOL and pass it the script file you are editing. Each text editor does
this differently. For instance, in the Premia Codewright editor you can use the
language compiler options to set up REBOL. Specify the REBOL program rather
than a compiler. You can press a single key that saves the script and evaluates it.
Security Issues 0
By default, security is set to prevent scripts from modifying any of your files or
directories.
Port Security
The secure function provides flexibility in setting and controlling the security
features of REBOL. This function is not backward-compatible with previous
versions of REBOL and will require changes to scripts that use the secure native
function. The current security settings are returned as a result of calling the secure
function.
Security settings use a REBOL dialect, that is, a language within a language. The
normal dialect consists of a block of paired values. The first value in the pair
specifies what is being secured:
A file name or directory path allows you to specify security levels for a specific file
or directory.
The second value in the pair specifies the level of security. This can be either a
security level word or a block of words. The security level words are:
For example, to allow all network access, but to quit on any file access:
secure [
net allow ;allows any net access
file quit ;any file access will cause the program to
quit
]
If a block is used instead of a security level word, it can contain pairs of security
levels and access types. This lets you specify a greater level of detail about the
security you require. The access types allowed are:
The pairs are processed in the order they appear, with later pairs modifying the
effect of earlier pairs. This permits setting one type of access without explicitly
setting all others. For example:
secure [
net allow
file [
ask all
allow read
]
]
The above sets the security level to ask for all operations except for reading which
is to be allowed. This technique can also be used for individual files and directories.
For example:
asks if an attempt is made to read the %source directory. Otherwise, it uses the
default (quit).
There is a special case in which the secure function takes a single word argument
that must be one of the security access levels. In that case, the security level for all
network and file access is set to that level. This is very similar to the previous syntax
except that there is no way to specify separate read and write access using this
form.
secure quit
The secure function also accepts none, allowing access with no restrictions (same
as allow).
The default security level (which corresponds to the old read level) is now:
secure [
net allow
file [
ask all
allow read
]
]
If no security access level is specified for either network or file access, it defaults to
ask. The current settings will not be modified if an error occurs parsing the security
block argument.
You can modify the current security level by querying the current settings,
modifying them, then using the secure function to set the new values.
As in the past, lowering the security level produces a change security settings
request. The exception is when the REBOL session is running in quiet mode which
will, instead, terminate the REBOL session. No query is generated when security
levels are raised. Note that the security request now includes an option to allow all
access for the remainder of the scripts processing.
When running REBOL from the shell, the -s argument is equivalent to secure allow
and the +s arguments is equivalent to secure quit. You can now follow the --secure
argument with one of the security access levels for both network and file access:
Program Arguments 0
There are a number of arguments that can be specified in a shell command line, in
a batch script, or in the properties of an icon. To view the arguments and options
available for any version of the REBOL language, type usage at the console prompt.
Examples:
REBOL script.r
REBOL script.r 10:30 [email protected]
REBOL script.r -do "verbose: true"
REBOL --cgi –s
REBOL --cgi --secure throw --script cgi.r
REBOL --secure none
Where:
■ script is the file name of the script you want to run. If the file name contains
spaces, it should be typed in quotes.
■ arguments are the arguments passed to the script as a string. These arguments
can be accessed from within the script.
All of the above arguments are optional, and any combination is permitted.
NOTE: In some operating systems, like Windows or Amiga, you can create icons that
supply any of the above options as part of the icon. Using this technique, you can
create icons that directly execute REBOL scripts with the correct options.
Script File 0
Typically, you run REBOL with the file name of the script that you want it to
evaluate. Only one script file is allowed. For example:
REBOL script.r
Specifying Options 0
Program options are identifed with a plus sign (+) or minus sign (–) before a
single character or by a double dash (--) before a full word. This is a standard
practice for specifying program options on most operating systems.
To run a script with an option, such as the –s option, which evaluates the script
with security turned off, type:
REBOL -s script.r
REBOL -?
REBOL --help
To run REBOL without opening a new window (this is done when you need to
redirect output to a file or server), type:
REBOL -w
REBOL --nowindow
To prevent the printout of startup information which is useful if you are redirecting
the output to a file or server, type:
REBOL -q
REBOL --quiet
REBOL -s script.r
REBOL --secure none script.r
To use REBOL scripts for CGI (see the “CGI - Common Gateway Interface” Section
of the “Network Protocols” Chapter for more information), type:
REBOL -c cgi-script.r
REBOL --cgi
Multiple options are also allowed. Multiple single character options can be included
together. Multiple full word options must be separated with spaces.
The above example runs in CGI mode, with security turned off. The shorthand
method is required for various web servers that restrict the number of arguments
allowed on the command line (such as the Apache server on Linux).
File Redirection 0
On most systems, it is possible to redirect standard input and output from and to
files. The example:
NOTE: The -w option prevents the REBOL console window from opening, as it
interferes with standard input and output redirection.
Script Arguments 0
Everything on the command line that follows the script file name is passed to the
script as its argument. This allows you to write scripts that accept arguments
directly from the command line.
The script in the above example is passed these arguments in the system object. To
print the arguments that have been passed, type:
probe system/script/args
["10:30" "[email protected]"]
Startup Files 0
When REBOL starts, it attempts to load the rebol.r and user.r boot files. These
files are optional, but when found, they can be used to set up networking, define
common functions, and initialize data used by scripts.
The rebol.r script file holds special functions or extensions to REBOL that are
provided as part of the standard distribution. It is suggested that you do not edit this
file as it is overwritten with each new release of REBOL.
The user.r script file holds user preferences. You can edit this file and add
whatever definitions or data you require.
On multi-user systems, there can be a different user.r for every user. While the
user.r file is not part of the distribution, it is automatically generated if it does not
exist.
When REBOL starts, it looks for the rebol.r and user.r files first in the current
directory. If the files are not found, REBOL looks in a directory that is specified with
the operating system environment variable REBOL_HOME or by examining the
contents of the .rebol file in your user home directory.
To provide a home directory, you can set an environment variable in the appropriate
login or startup script for your system. For example, on Windows NT you can add:
set REBOL_HOME=C:\REBOL
■ Type REBOL_HOME in the variable field and C:\REBOL in the value field.
■ On Unix systems, you can set the path to REBOL by adding a line like the
following in your login shell script or profile:
set REBOL_HOME=/usr/bin/rebol
For some versions of REBOL, the path is stored in a .rebol file that is located in
your home directory.
Quitting REBOL A
To exit REBOL at any time, select Quit from the Console File menu or by type quit
or q at the prompt. You can also quit the program from within a script:
The REBOL console may also quit if an error occurs during startup.
Note: Do not use the word exit to quit REBOL. This word is used for exiting
functions and generates an error if used for quitting.
Whenever you run REBOL/Core, it opens a console to display output and accept
input. If you provide a script argument to the program, the script is run, and you
see the output from that script. If you do not provide a script file, the console
prompts you for input. The input prompt looks like this:
>>
If you type an expression at the input prompt, it is evaluated and any returned
values are displayed following the output prompt:
==.
For example:
>> 100 + 20
== 120
== 20341
NOTE: The prompt characters can be changed. See the “Console” Appendix for more
information.
The console also becomes active if a script encounters an error or if the script calls
the halt function directly.
If you begin a block on the command line and don’t end it, the block is extended to
the next line. This is indicated by a prompt that begins with a bracket and is
followed by indentation. The line will be indented four spaces for each open block.
For example:
loop 10 [
[ print "example"
[ if odd? random 10 [
[ print "here"
[ ]
[ ]
Brackets and braces that appear within quoted strings are ignored. You can escape
from input at any time by pressing the ESCAPE key.
Interrupting a Script 0
A script can be interrupted by pressing the ESCAPE key, which returns immediately
to the command prompt.
During some types of operating system or network activity there may be a delay in
response from the ESCAPE interrupt.
History Recall 0
Each line that is typed into REBOL is stored for later recall. The up and down arrow
keys are used to scroll through the list of previous lines. For instance, pressing the
up arrow once recalls the prior input line.
History lines can be written to a file by saving the history block. See the “Console”
Appendix for more information.
Word Completion 0
To help speed typing of long words and file names, the REBOL console has word
and file name completion. After typing a few letters of a word, press the tab key.
If the letters uniquely identify the word, the rest of the word is displayed. For
example, typing:
>> sq
>> square-root
If the letters do not uniquely identify the word, you can press tab again to get a list
of choices. For example, typing:
>> so
and you can type the rest of the word or enough of it to be unique.
Completion also works for files when they are begun with a percent sign.
Busy Indicator 0
When REBOL waits for a network operation to complete, a busy indicator appears
to indicate that something is happening. You can change the indicator to your own
character pattern. See the “Console” Appendix for more information.
Network Connections 0
If necessary, you can disable this output by setting the quiet flag. See the “Console”
Appendix for more information.
Virtual Terminal 0
The console provides virtual terminal capability that allows you to perform
operations such as cursor movement, cursor addressing, line editing, screen
clearing, control key input, and cursor position querying.
The virtual terminal uses the standard ANSI character sequences. This allows you
to write platform-independent terminal programs such as text editors, email clients,
or telnet emulators.
Getting Help A
Several sources of information exist online help built into REBOL, the source
function, documents on the REBOL web site, the REBOL script library, the REBOL
mailing list, and sending feedback to REBOL.
Online Help 0
The online help function provides a quick way to obtain summary information
about REBOL words. There are several ways to use help.
>> help
help insert
help find
help "path"
help to-
help native!
help datatype!
If you provide a function word as an argument, help prints all of the information
that was provided about the function:
>> ? insert
USAGE:
INSERT series value /part range /only /dup count
DESCRIPTION:
Inserts a value into a series and returns the
series after the insert.
INSERT is an action value.
ARGUMENTS:
REFINEMENTS:
The help function also finds words that contain a specified string. For instance, to
find all of the words that include the string path, type:
>> ? "path"
You can also search for all globally defined words that are of a given data type. For
example, to list all words that are function! data types, type:
>> ? function!
? (function)
?? (function)
about (function)
append (function)
array (function)
ask (function)
build-tag (function)
change-dir (function)
charset (function)
choose (function)
clean-path (function)
...
>> ? datatype!
action! (datatype)
any-block! (datatype)
any-function! (datatype)
any-string! (datatype)
any-type! (datatype)
any-word! (datatype)
binary! (datatype)
bitset! (datatype)
block! (datatype)
char! (datatype)
datatype! (datatype)
date! (datatype)
...
The help function does not provide useful information about the objects of the
system.
Advanced users can learn more about specific REBOL functions by examining the
source code. The source function displays the code for any mezzanine level or
user-defined function:
join: func [
"Concatenates values."
value "Base value"
rest "Value or block of values"
][
value: either series? value [copy value] [form value]
repend value rest
]
Download Documents 0
Check the REBOL Web site (http://www.REBOL.com) for a list of the current
documentation. In addition to this manual, there is a REBOL Dictionary.
The REBOL Dictionary includes all predefined words available in REBOL. If the
console help or this guide does not contain sufficient information about a REBOL
word, look in the Dictionary for a detailed description.
Script Library 0
The REBOL Web site contains a library with numerous useful debugged scripts that
cover a variety of topics. The library is divded into categories to make it easy to
find a script specific to a given function. You can also search the library for scripts
that contain a specific word.
You can also obtain help from the on-line REBOL community by joining the email
discussion list. To sign up, send an email to [email protected] with the subject line
containing the word "subscribe". For example:
Be sure that your correct email address has been set up in advance with set-net.
Contacting Us 0
■ Make suggestions
You can contact the REBOL Technologies customer support group by sending an
email message to [email protected].
Another way to provide feedback is to run the feedback.r script that is part of
the distribution. Type:
do %feedback.r
This script presents a menu to help guide you though the feedback process.
FEEDBACK CATEGORY
--------------------
1 > Bug report
2 > General Question
3 > Enhancement idea
4 > Comment/Praise
5 > Documentation note
6 > Other
7 > Quit
Using the feedback script automatically includes the version number of REBOL
release you are using in the email sent to REBOL’s helpdesk. If you contact us
directly at feedback, please provide the version number of the product you are
using.
Errors A
Error Messages 0
There are several types of errors within REBOL. When an error occurs a message is
displayed that tells you what the error was and approximately where it occurred.
For instance if you type:
>> abc
** Script Error: abc has no value.
** Where: abc
The type of error is indicated by the first few words of the message. In the above
example, the error is a Script Error. Script errors are the most common and occur
when you use a function of the language in the wrong way or with improper
arguments. Other types of errors are described in Table 1-1.
Table 1-1. Error Types
Syntax errors Occur when the script contains an invalid value or a missing
header, quote, bracket, or parenthesis.
Math errors Occur when dividing a number by zero or there was a math
overflow or underflow.
Access errors Occur when a file, directory, or network operation cannot be
accessed or access permissions are restricted.
Throw errors Occur when a break, exit, or throw is used in an improper
manner.
User errors Defined by the user’s script.
Internal errors Returned when a problem occurs within the REBOL system. If
you encounter one of these types of errors, please report it to
[email protected].
Most types of errors can be trapped and processed by your script. See “Trying
Blocks” on page 3-46 for a description of the try function.
Redirecting Errors 0
If a script terminates while running in non-interactive mode, you can use the shell
reduction operator (>>) to output the error to a file:
The shell reduction operator appends the output to a file in most operating systems.
Upgrading A
version.revision.update.platform.variation
2.3.0.3.1
indicates that you are running version 2, revision 3, update 0, for Windows 95/98/
NT (REBOL platform number 3.1).
You can obtain the version number from the REBOL prompt with:
print system/version
Only the latest release of REBOL is supported by REBOL Technologies. You can
verify that you have the latest version and automatically update it if out of date. To
do so, be sure that you are connected to the Internet, then from within REBOL type:
upgrade
or:
2- 1
Quick Tour
Overview
Overview B
This chapter provides a quick way to familiarize yourself with the REBOL language.
Using examples, this chapter presents the basic concepts and structure of the
language, illustrating everything from data values to performing network
operations.
Values B
A script is written with a sequence of values. A wide variety of values exist; you
are familiar with most of them from daily experience. This section lists all the valid
values and describes how they are expressed in REBOL.
Note that where possible, REBOL allows the use of international formats for values
such as decimal numbers, money, time, and date.
Numbers 0
Times 0
Time is written in hours, minutes, and seconds, each separated by colons. For
example:
Dates 0
Money 0
Tuples 0
Tuples are used for version numbers, RGB color values, and network addresses
They are written as short numeric sequences separated by dots. For example:
Strings 0
Tags 0
Tags are useful for markup languages such as XML and HTML. Tags are enclosed in
angle brackets For example:
<title> </body>
Email Addresses 0
Email addresses are written directly in REBOL. They must include an at sign(@).
For example:
URLs 0
Most types of Internet URLs are accepted directly by REBOL. They begin with a
scheme name (e.g., http) followed by a path. For example:
http://www.rebol.com
ftp://ftp.rebol.com/sendmail.r
ftp://freda:[email protected]/dir/files/
mailto:[email protected]
Filenames 0
Filenames are preceded by a percent sign to distinguish them from other words. For
example:
%data.txt
%images/photo.jpg
%../scripts/*.r
Pairs 0
Pairs are used to indicate spatial coordinates, such as positions on a display. They
are used to indicate both positions and sizes. Coordinates are separated by an x.
For example:
100x50
1024x800
-50x200
Issues 0
#707-467-8000
#0000-1234-5678-9999
#MFG-932-741-A
Binary 0
Binary values are byte strings of any length. They can be encoded directly as
hexidecimal or base-64. For example:
#{42652061205245424F4C}
64#{UkVCT0wgUm9ja3Mh}
Words B
Words are the symbols used by REBOL. A word may or may not be a variable,
depending on how it is used. Words are also used directly as symbols.
REBOL has no keywords; there are no restrictions on what words are used or how
they are used. For instance, you can define your own function called print and
use it instead of the predefined function for printing values.
Words are not case sensitive and can include hyphens and a few other special
characters such as +, -, ‘, *, !, ~, &, ., and ?. The following examples illustrate
valid words:
image-files l’image
++ -- == +-
***** *new-line*
left&right left|right
The end of a word is indicated by a space, a line break, or one of the following
characters:
[ ] ( ) { } " : ; /
@ # $ % ^ ,
Blocks B
Values and words are grouped in blocks. Blocks are used for code, lists, arrays,
tables, directories, associations, and other sequences. A block is a type of series,
which is a set of values organized in a specific order.
A block is enclosed in square brackets [ ]. Within a block, values and words can
be organized in any order and can span any number of lines. The following
examples illustrate the valid forms of blocks:
[
Ted [email protected] #213-555-1010
Bill [email protected] #315-555-1234
Steve [email protected] #408-555-4321
]
[
"Elton John" 6894 0:55:68
"Celine Dion" 68861 0:61:35
"Pink Floyd" 46001 0:50:12
]
Blocks are used for code as well as for data, as shown in the following examples:
sites: [
http://www.rebol.com [save %reb.html data]
http://www.cnn.com [print data]
ftp://www.amiga.com [send [email protected] data]
]
A script itself also is a block. Although it does not include the brackets, the block
is implied. The example script:
red
green
blue
yellow
is a block that contains red, green, blue, and yellow. It is equivalent to writing:
Variables B
Words can be used as variables that refer to values. To define a word as a variable,
follow the word with a colon (:), then the value to which the variable refers as
shown in the following examples:.
age: 22
snack-time: 12:32
birthday: 20-Mar-1997
A variable can refer to any type of value, including functions (see “Functions” on
page 2-12) and objects (see “Objects” on page 2-15).
A variable refers to a specific value only within a defined context, such as a block,
a function, or an entire program. Outside that context the variable can refer to some
other value or to no value at all. The context of a variable can span an entire
program or it can be restricted to a particular block, function, or object. In other
languages, the context of a variable is often referred to as the scope of a variable.
Evaluation B
Blocks are evaluated to compute their results. When a block is evaluated the values
of its variables are obtained. The following examples evaluate the variables age,
snack-time, birthday, and friends that were defined in the previous section:
print age
22
12:32
Georgia
NOTE: Each of these code lines is a block, even though the brackets are not shown.
All scripts have an implied block around their entire text.
A block can be evaluated multiple times by using a loop, as shown in the following
examples:
**********
loop 20 [
wait 8:00
send [email protected] read http://www.cnn.com
]
count: 1
count: 2
count: 3
The evaluation of a block returns a result. In the following examples, 5 and PM are
the results of evaluating each block:
print do [2 + 3]
PM
In REBOL, there are no special operator precedence rules for evaluating blocks. The
values and words of a block are always evaluated from first to last, as shown in the
following example:
print 2 + 3 * 10
50
2 + (3 * 10)
32
(length? "boat") + 2
You can also evaluate a block and return each result that was computed within it.
This is the purpose of the reduce function:
reduce [1 + 2 3 + 4 5 + 6]
3 7 11
Functions B
A function is a block with variables that are given new values each time the block
is evaluated. These variables are called the arguments of the function.
In the following example, the word sum is set to refer to a function that accepts two
arguments, a and b:
sum: func [a b] [a + b]
In the above example, func is used to define a new function. The first block in the
function describes the arguments of the function. The second block is the block of
code that gets evaluated when the function is used. In this example, the second
block adds two values and returns the result.
The next example illustrates one use of the function sum that was defined in the
previous example:
print sum 2 3
Some functions need variables as well as arguments. To define this type of function,
use function, instead of func, as shown in the following example:
47
In the above example, the word series is an argument and the word total is a
local variable used by the function for calculation purposes.
The function argument block can contain strings to describe the purpose of a
function and its argument, as shown in the following example:
average: function [
"Return the numerical average of numbers"
series "Numbers to average"
] [total] [
total: 0
foreach value series [total: total + value]
total / (length? series)
]
These descriptive strings are kept with the function and can be viewed by asking
for help about the function, as shown below:
help average
USAGE:
AVERAGE series
DESCRIPTION:
ARGUMENTS:
Paths B
If you are using files and URLs, then you are already familiar with the concept of
paths. A path provides a set of values that are used to navigate from one point to
another. In the case of a file, a path specifies the route through a set of directories
to the location of the file. In REBOL, the values in a path are called refinements.
A slash (/) is used to separate words and values in a path, as shown in the following
examples of a file path and a URL path:
%source/images/globe.jpg
http://www.rebol.com/examples/simple.r
Paths can also be used to select values from blocks, pick characters from strings,
access variables in objects, and refine the operation of a function, as shown in the
following examples:
The print function in next example shows the simplicity of using a path to access
a mini-database created from a few blocks:
towns: [
Hopland [
phone #555-1234
web http://www.hopland.ca.gov
]
Ukiah [
phone #555-4321
web http://www.ukiah.com
email [email protected]
]
]
print towns/ukiah/web
http://www.ukiah.com
Objects B
An object is a block of variables that have values in a specific context. Objects are
used for managing data structures that have more complex behavior. The following
example shows how a bank account can benefit from using an object to specify its
attributes and functions:
In the above example, the words name, balance, ss-number, deposit, and
withdraw are local variables of the account object. The deposit and
withdraw variables are functions that are defined within the object. The variables
of the account can be accessed with a path, as shown in the next example:
print account/balance
$100.00
account/deposit $300
The next example shows how to make another account with a new balance but with
all the other values remaining the same
You can also create an account that extends the account object by adding the bank
name and last activity date, as shown in the following example:
print checking-account/balance
$2000.00
print checking-account/bank
Savings Bank
print checking-account/last-active
20-Jun-2000
Scripts B
A script is a file that holds a block that can be loaded and evaluated. The block can
contain code or data, and typically contains a number of sub-blocks.
Scripts require a header to identify the presence of code. The header can include
the script title, date, and other information. In the following example of a script, the
first block contains the header information:
REBOL [
Title: "Web Page Change Detector"
File: %webcheck.r
Author: "Reburu"
Date: 20-May-1999
Purpose: {
Determine if a web page has changed since it was
last checked, and if it has, send the new page
via email.
}
Category: [web email file net 2]
]
if any [
not exists? %page-sum.r
page-sum <> (load %page-sum.r)
][
print ["Page Changed" now]
save %page-sum.r page-sum
send [email protected] page
]
Files B
In REBOL, files are easily accessed. The following table describes some of the ways
to access files.
For instance, you could write out the current time with:
do %script.r
Make-dir %newdir/
print what-dir
delete %oldfile.txt
Networking B
There are a number of Internet protocols built into REBOL. These protocols are easy
to use and require very little knowledge of networking.
HTTP 0
The following example shows how to use the HTTP protocol to read a web page:
The next example fetches an image from a web page and writes it to a local file:
FTP 0
The following reads and writes files to a server using the file transfer protocol (FTP):
SMTP 0
The following example sends email with the simple mail transfer protocol (SMTP):
POP 0
The following example fetches email with the post office protocol (POP) and prints
all of the current messages but leaves them on the server:
NNTP 0
The following example fetches news with the network news transfer protocol
(NNTP), reading all of the news in a particular news group:
The next example reads a list of all news group and prints them:
Daytime 0
Whois 0
The following example finds out who is in charge of a domain using the whois
protocol:
Finger 0
The following example gets user information with the finger protocol:
DNS 0
The following example determines an Internet address from a domain name and a
domain name from an address:
TCP 0
Direct connections with TCP/IP are also possible in REBOL. The following example
is a simple, but useful, server that waits for connections on a port:
forever [
connection-port: first server-port
until [
wait connection-port
error? try [do first connection-port]
]
close connection-port
]
This chapter explains the use of blocks, values and words, as well as the functions
necessary to evaluate expressions in REBOL. It includes the following information:
3- 1
Expressions
Overview
Overview C
The expression shown in the above example looks a lot like English, making it easy
to compose if you are sending it and easy to understand if you are receiving it.
However, this line is actually a valid expression in REBOL, so your computer could
also understand and act on it. REBOL provides a common language between you
and your computer. In addition, if your computer sends this expression to your
stock broker’s computer, which is also running REBOL, your stock broker’s
computer can understand the expression and act on it. REBOL provides a common
language between computers. The line could be sent to millions of other computer
systems that could also act on it.
The expression shown in the above example may have come from your doctor
typing it, or perhaps it originated from an application that was run by your doctor.
It does not matter. What is important is that the expression can be acted upon
regardless of the type of computer, hand-held device, kiosk, or television console
you are using.
The data values (numbers, strings, prices, dates, and times) in all of the expressions
shown in the previous examples are standardized valid REBOL formats. The
words, however, depend on a specific context of interpretation to convey their
meaning. Words such as sell, at, and read have different meanings in different
contexts. The words are relative expressions—their meaning is context dependent.
Expressions can be processed in one of two ways: directly by the REBOL interpreter,
or indirectly by a REBOL script. A script processed indirectly is called a dialect. The
previous examples are dialects and, therefore, are processed by a script. The
following example is not a dialect and is processed directly by the REBOL
interpreter:
In this example, the words send and read are functions that are processed by the
REBOL interpreter.
Blocks C
Expressions are based on one concept: you combine values and words into blocks.
[
"Bill" [email protected] #315-555-1234
"Steve" [email protected] #408-555-4321
"Ted" [email protected] #213-555-1010
]
sites: [
http://www.rebol.com [save %reb.html data]
http://www.cnn.com [print data]
ftp://www.amiga.com [send [email protected] data]
]
Some blocks do not require square brackets, because they are implied. For example,
in a REBOL script, there are no brackets around the entire script, however, the script
content is a block. The square brackets of an outer-block of the script are implied.
The same is true for expressions typed at the command prompt or for REBOL
messages sent between computers—each is an implied block.
Values C
REBOL provides a built-in set of values that can be expressed and exchanged
between all systems. Values are the primary elements for composing all REBOL
expressions.
Every REBOL value is of a particular data type. A data type is a definition of a set
of data that specifies the possible range of values of the set, the operations that can
be performed on the values, and the way in which the values are stored in memory.
By convention, REBOL data type words are followed by an exclamation point (!),
as shown in the following examples:
See the “Values” Appendix for a description of all the REBOL data types.
Evaluating Expressions C
Any expression that can be evaluated in a script, can also be evaluated from the
REBOL prompt, providing a simple means of testing individual expressions in a
script.
For example, if you type the following expression at the console prompt:
>> 1 + 2
== 3
NOTE: In the example above, the console prompt (>>) and result indicator
(==)are shown to give you an idea of how they appear in the console. For the
examples that follow, the prompt and result strings are not shown. However, you
can assume that these examples can be typed into the console to verify their results.
Since the value of directly expressed values is known, when they are evaluated the
known value is returned. For example, if you type the following line:
10:30
the value 10:30 is returned. This is the behavior of all directly expressed values,
including:
integer 1234
decimal 12.34
string "REBOL world!"
time 13:47:02
date 30-June-1957
tuple 199.4.80.1
money $12.49
pair 100x200
char #"A"
binary #{ab82408b}
email [email protected]
issue #707-467-8000
tag <IMG SRC="xray.jpg">
file %xray.jpg
url http://www.rebol.com/
block [milk bread butter]
Evaluating Blocks 0
Normally, blocks are not evaluated. For example, typing the following block:
[1 + 2]
[1 + 2]
do [1 + 2]
The do function returns the result of the evaluation. In the previous example, the
number 3 is returned.
If a block contains multiple expressions, only the result of the last expression is
returned:
do [
1 + 2
3 + 4
]
In this example, both expressions are evaluated, but only the result of the
expression 3 + 4 is returned.
There are a number of functions such as if, loop, while, and foreach that evaluate
a block as part of their function. These functions are discussed in detail later in this
chapter, but here are a few examples:
past noon
looping
looping
looping
looping
This is important to remember: blocks are treated as data until they are explicitly
evaluated by a function. Only a function can cause them to be evaluated.
Reducing Blocks 0
When you evaluate a block with do, only the value of its last expression is returned
as a result. However, there are times when you want the values of all the
expressions in a block to be returned. To return the results of all of the expressions
in a block, use the reduce function. In the following example, reduce is used to
return the results of both expressions in the block:
reduce [
1 + 2
3 + 4
]
[3 7]
In the above example, the block was reduced to its evaluation results. The reduce
function returns results in a block.
Some functions, like print, use reduce as part of their operation, as shown in the
following example:
print [1 + 2 3 + 4]
3 7
The rejoin, reform, and remold functions also use reduce as part of their
operation, as shown in the following examples:
print rejoin [1 + 2 3 + 4]
37
print reform [1 + 2 3 + 4]
3 7
print remold [1 + 2 3 + 4]
[3 7]
The rejoin, reform, and remold functions are based on the join, form, and mold
functions, but reduce their blocks first.
Evaluating Scripts 0
do [print "Hello!"]
Hello!
But, when do evaluates a file name instead of a block, the file will be loaded into
the interpreter as a block, then evaluated as shown in the following example:
do %script.r
NOTE: Note that for a script file to be evaluated, it must include a valid REBOL
header, which is described in the “Scripts” Chapter. The header identifies that the
file contains a script and not just random text.
Evaluating Strings 0
The do function can be used to evaluate expressions that are found within text
strings. For example, the following expression:
do "1 + 2"
returns the result 3. First the string is converted to a block, then the block is
evaluated.
Evaluating strings can be handy at times, but it should be done only when
necessary. For example, to create a REBOL console line processor, type the
following expression:
The above expression would prompt you with => and wait for you to type a line of
text. The text would then be evaluated, and its result would be printed. (Of course,
it’s not really quite this simple, because the script could have produced an error.)
do [1 + 2]
REBOL blocks can be constructed just as easily as strings, and blocks are better for
expressions that need to be evaluated.
Evaluation Errors 0
Errors may occur for many different reasons during evaluation. For example, if you
divide a number by zero, evaluation is stopped and an error is displayed
100 / 0
** Math Error: Attempt to divide by zero.
** Where: 100 / 0
size + 10
** Script Error: size has no value.
** Where: size + 10
10 + [size]
** Script Error: Cannot use add on block! value.
** Where: 10 + [size]
Sometimes errors are not so obvious, and you will need to experiment to determine
what is causing the error.
Words C
Expressions are built from values and words. Words are used to represent meaning.
A word can represent an idea or it can represent a specific value.
In the previous examples in this chapter, a number of words were used within
expressions without explanation. For instance, the do, reduce, and try words are
used, but not explained.
Words are evaluated somewhat differently than directly expressed values. When a
word is evaluated, its value is looked up, evaluated, and returned as a result. For
example, if you type the following word:
zero
==0
the value 0 is returned. The word zero is predefined to be the number zero. When
the word is looked up, a zero is found and is returned.
When words like do and print are looked up, their values are found to be functions,
rather than a simple value. In such cases, the function is evaluated, and the result
of the function is returned.
Word Names 0
Words are composed of alphabetic characters, numbers, and any of the following
characters:
? ! . ’ + - * & | = _ ~
A word cannot begin with a number, and there are also some restrictions on words
that could be interpreted as numbers. For example, -1 and +1 are numbers, not
words.
The end of a word is marked by a space, a new line, or one of the following
characters:
[ ] ( ) { } " : ; /
Thus, the brackets of a block are not part of a word. For example, the following
block contains the word test:
[test]
The following characters are not allowed in words as they cause words to be
misinterpreted or to generate an error:
@ # $ % ^ ,
Words can be of any length, but cannot extend past the end of a line:
this-is-a-very-long-word-used-as-an-example
image-files l’image
++ -- == +-
***** *new-line*
left&right left|right
REBOL is not case sensitive. The following words all refer to the same word:
blue
Blue
BLUE
Words can be reused. The meaning of a word is dependent on its context, so words
can be reused in different contexts. There are no keywords in REBOL. You can
reuse any word, even those that are predefined in REBOL. For instance, you can
use the word if in your code differently than the REBOL interpreter uses this word.
NOTE: Pick the words you use carefully. Words are used to associate meaning. If
you pick your words well, it will be easier for you and others to understand your
scripts.
Word Usage 0
Words are used in two ways: as symbols or as variables. In the following block,
words are used as symbols for colors.
green
the words have no meaning other than their use as names for colors. All words used
within blocks serve as symbols until they are evaluated.
word Evaluates the word. This is the most natural and common way to
write words. If the word holds a function, it will be evaluated.
Otherwise, the value of the word will be returned.
word: Defines or sets the value of a word. It is given a new value. The
value can be anything, including a function. See “Setting Words”
below.
:word Gets the word’s value, but doesn’t evaluate it. This is useful for
referring to functions and other data without evaluating them.
See “Getting Words” below.
’word Treats the word as a symbol, but does not evaluate it. The word
itself is the value.
Setting Words 0
age: 42
lunch-time: 12:32
birthday: 20-March-1990
town: "Dodge City"
test: %stuff.r
NOTE: The reason words are set using a colon is to make their expression atomic.
You can write code that finds set-word operations. They also distinguish the set
operation from equality(=).
You can set a word to be any type of value. In the previous examples, words are
defined to be integer, time, date, string, and file values. You can also set words to
be more complex types of values. For example, the following words are set to block
and function values:
Multiple words can be set at one time by cascading the word definitions. For
example, each of the following words are set to 42:
In this example, the line sets the word time to 10:30. The word time is written
as a literal (using a single quote) so that it will not be evaluated.
10 10 10
In the above example, notice that the words do not need to be quoted because they
are within a block, which is not evaluated. The print function shows that each
word is set to the integer 10.
If set is provided a block of values, each of the individual values are set to the
words. In this example, one, two, and three are set to 1, 2, and 3:
print three
1 2 3
See the “Words” Section in the “Values” Appendix for more about setting words.
Getting Words 0
To get the value of a word that was previously defined, place a colon (:) at the front
of the word. A word prefixed with a colon obtains the value of the word, but does
not evaluate it further if it is a function. For example, the following line:
drucken: :print
defines a new word, drucken (which is German for print), to refer to the same
function print does. This is possible because :print returns the function for print,
but does not evaluate it.
drucken "test"
test
Both print and drucken are set to the same value, which is the function that does
printing.
This can also be accomplished with the get function. When given a literal word, get
returns its value, but does not evaluate it:
stampa "test"
test
The ability to get the value of a word is also important if you want to determine
what the value is without evaluating it. For example, you can determine if a word
is a native function using the following line:
true
Here the get returns the function for if. The if function is not evaluated, but rather
it is passed to the native? function which checks if it is a native data type. Without
the colon, the if function would be evaluated, and, because it has no arguments, an
error would occur.
Literal Words 0
The ability to deal with a word as a literal is useful. Both set and get, as well as
other functions like value?, unset, protect, and unprotect, expect a literal value.
Literal words can be written in one of two ways: by prefixing the word with a single
quotation mark, also known as a tick, (‘) or by placing the word in a block.
word: ’this
In the above example, the word variable is set to the literal word this, not to the
value of this. The word variable just uses the name symbolically. The example
below shows that if you print the value of the word, you will see the this word:
print word
this
You can also obtain literal words from an unevaluated block. In the following
example, the first function fetches the first word from the block. This word is then
set to the word variable.
Any word can be used as a literal. It may or may not refer to a value. For example,
in the example below the word here has no value. The word print does have a
value, but it can still be used as a literal because literal words are not evaluated.
word: ’here
print word
here
word: ’print
print word
video: [
title "Independence Day"
length 2:25:24
date 4/july/1996
]
print select video ’title
Independence Day
In this example, the word title is searched for in a block. If the tick was missing
from title, then its natural value would be used. If title has no natural value,
an error is displayed.
See the “Words” Section in the “Values” Appendix for more information about word
literals.
Unset Words 0
A word that has no value is unset. If an unset word is evaluated, an error will occur:
>> outlook
** Script Error: outlook has no value.
** Where: outlook
The error message in the previous example indicates that the word has not been set
to a value. The word is unset. Do not confuse this with a word that has been set to
none, which is a valid value.
unset ’word
To determine if a word has been set, use the value? function, which takes a literal
word as its argument:
Determining whether a word is set can be useful in scripts that call other scripts.
For instance, a script may set a default parameter that was not previously set:
Protecting Words 0
You can prevent a word from being set with the protect function:
protect ’word
word: "here"
** Script Error: Word word is protected, cannot modify.
** Where: word: "here"
unprotect ’word
word: "here"
Important function and system words can be protected using the protect-system
function. Protecting function and system words is especially useful for beginners
who might accidentally set important words. If protect-system is placed in your
user.r file, then all predefined words are protected.
Conditional Evaluation C
Conditional Blocks 0
The if function takes two arguments. The first argument is a condition and the
second argument is a block. If the condition is true, the block is evaluated,
otherwise it is not evaluated.
past noon
found
The either function extends if to include a third argument, which is the block to
evaluate if the condition is false:
after lunch
Both the if and either functions return the result of evaluating their blocks. In the
case of an if, the block value is only returned if the block is evaluated; otherwise, a
none is returned. The if function is useful for conditional initialization of variables:
print flag
lunch eaten
Making use of the result of the either function, the previous example could be
rewritten as follows:
after lunch
Since both if and either are functions, their block arguments can be any expression
that results in a block when evaluated. In the following examples, words are used
to represent the block argument for if and either.
Wake up!
notices: [
[print "It’s past sunrise!"]
[print "It’s past noon!"]
[print "It’s past sunset!"]
]
if now/time > 12:00 second notices
Wake up!
The conditional expressions used for the first argument of both if and either can be
composed from a wide variety of comparison and logic functions. Refer to the
“Math” Chapter for more information.
NOTE: The most commonly made mistake in REBOL is to forget the second block on
either or add a second block to if. These types of errors may be difficult to detect,
so keep this in mind if the function does not seem to be doing what you expect.
The any and all functions offer a shortcut to evaluating some types of conditional
expressions. These functions can be used in a number of ways:either in conjunction
with if, either, and other conditional functions, or separately.
Both any and all accept a block of expressions, which is evaluated one expression
at a time. The any function returns on the first true expression, and the all function
returns on the first false expression. Keep in mind that a false expression can also
be none, and that a true expression is any value other than false or none.
The any function returns the first value that is not false, otherwise it returns
none. The all function returns the last value if all the expressions are not false,
otherwise it returns none.
Both the any and all functions only evaluate as much as they need. For example,
once any has found a true expression, none of the remaining expressions are
evaluated. Here is an example of using any:
size: 50
if any [size < 10 size > 90] [
print "Size is out of range."
]
The behavior of any is also useful for setting default values. For example, the
following lines set a number to 100, but only when its value is none:
number: none
print number: any [number 100]
100
Similarly, if you have various potential values, you can use the first one that actually
has a value (is not none):
80
You can use any with functions like find to always return a valid result:
999
Similarly, all can be used for conditions that require all expressions to be true:
Size is in range
You can verify that values have been set up before evaluating a function:
a: "REBOL/"
b: none
probe all [string? a string? b append a b]
none
b: "Core"
probe all [string? a string? b append a b]
REBOL/Core
Conditional Loops 0
The until and while functions repeat the evaluation of a block until a condition is
met.
The until function repeats a block until the evaluation of the block returns true
(that is, not false or none). The evaluation block is always evaluated at least
once. The until function returns the value of its block.
The example below will print each word in the color block. The block begins by
printing the first word of the block. It then moves to the next color for each color
in the block. The tail? function checks for the end of the block, and will return
true, which will cause the until function to exit.
red
green
blue
The break function can be used to escape from the until loop at any time.
The while function repeats the evaluation of its two block arguments while the first
block returns true. The first block is the condition block, the second block is the
evaluation block. When the condition block returns false or none, the expression
block will no longer be evaluated and the loop terminates.
Here is a similar example to that show above. The while loop will continue to print
a color while there are still colors to print.
red
green
blue
The condition block can contain any number of expressions, so long as the last
expression returns the condition. To illustrate this, the next example adds a print to
the condition block. This will print the index value of the color. It will then check
for the tail of the color block, which is the condition used for the loop.
1
red
2
green
3
blue
4
The last value of the block is returned from the while function.
Common Mistakes 0
Conditional expressions are only false when they return false or none, and they
are true when they return any other value. All of the conditional expressions in
the following examples return true, even the zero and empty block values:
yep
if 1 [print "yep"]
yep
if 0 [print "yep"]
yep
if [] [print "yep"]
yep
yep
Do not confuse either with if. For example, if you intended to write:
the if function would ignore the second block. This would not cause an error, but
the second block would never get evaluated.
The opposite is also true. If you write the following line, omitting a second block:
the either function will not evaluate the correct code and may produce an
erroneous result.
Repeated Evaluation C
The while and until functions above where used to loop until a condition was met.
There are also several functions that let you loop for a specified a number of times.
Loop 0
The loop function evaluates a block a specified number of times. The following
example prints a line of 40 dashes:
----------------------------------------
Note that the prin function is similar to the print function, but prints its argument
without a line termination.
The loop function returns the value of the final evaluation of the block:
i: 0
print loop 40 [i: i + 10]
400
Repeat 0
The repeat function extends loop by allowing you to monitor the loop counter. The
repeat function’s first argument is a word that will be used to hold the count value:
count: 1
count: 2
count: 3
i: 0
print repeat count 10 [i: i + count]
55
In the previous examples, the count word only has its value within the repeat
block. In other words, the value of count is local to the block. After repeat
finishes, count returns to any previous set value.
For 0
The for function extends repeat by allowing the starting value, the ending value,
and the increment to the value to be specified. Any of the values can be positive or
negative.
The example below begins at zero and counts to 50 by incrementing 10 each time
through the loop.
0
10
20
30
40
50
The for function cycles through the loop up to and including the ending value.
However, if the count exceeds the ending value, the loop is still terminated. The
example below specifies an ending value of 55. That value will never be hit because
the loop increments by 10 each time. The loop stops at 50.
0 10 20 30 40 50
The next example shows how to count down. It begins at four and counts down to
zero one at a time.
4
3
2
1
0
The for function also works for decimal numbers, money, times, dates, series, and
characters. Be sure that both the starting and ending values are of the same data
type. Here are several examples of using the for loop with other data types.
10.5 9.5 8.5 7.5 6.5 5.5 4.5 3.5 2.5 1.5 0.5
abcdefghijklmnopqrstuvwxyz
The for function also works on series. The following example uses for on a string
value. The word end is defined as the string with its current index at the d
character. The for function moves through the string series one character at a time
and stops when it reaches the character position defined to end:
str: "abcdef"
end: find str "d"
for s str end 1 [print s]
abcdef
bcdef
cdef
def
Foreach 0
The foreach function provides a convenient way to repeat the evaluation of a block
for each element of a series. It works for all types of block and string series.
red
green
blue
string: "REBOL"
foreach char string [print char]
R
E
B
O
L
files: read %.
foreach file files [
if find file ".t" [print file]
]
file.txt
file2.txt
fox.txt
newfile.txt
output.txt
somefile.txt
test.txt
When a block contains groups of values that are related, the foreach function can
fetch all the values of the group at the same time. For example, here is a block that
contains a time, string, and price. By providing the foreach function with a block
of words for the group, each of their values can be fetched and printed.
movies: [
8:30 "Contact" $4.95
10:15 "Ghostbusters" $3.25
12:45 "Matrix" $4.25
]
In the above example, the foreach value block, [time title price], specifies
that three values are to be fetched from movies for each evaluation of the block.
The variables used to hold the foreach values are local to the block. Their value
are only set within the block that is being repeated. Once the loop has exited, the
variables return to their previously set values.
Similar to foreach, the forall function evaluates a block for every value in a series.
However, there are some important differences. The forall function is handed the
series that is set to the beginning of the loop. As it proceeds through the loop, forall
modifies the position within the series.
red
green
blue
In the above example, after each evaluation of the block, the series is advanced to
its next position. When forall returns, the color index is at the tail of the series.
To continue to use the series you will need to return it to its head position with the
following line:
The forskip function evaluates a block for groups of values in a series. The second
argument to forskip is the count of how many elements to move forward after each
cycle of the loop.
Like forall, forskip is handed the series with the series index set to where it is to
begin. Then, forskip modifies the index position as it continues the loop. After each
evaluation of the body block, the series index is advanced by the skip amount to its
next index position. The following example demonstrates forskip:
movies: [
8:30 "Contact" $4.95
10:15 "Ghostbusters" $3.25
12:45 "Matrix" $4.25
]
Contact
Ghostbusters
Matrix
In the above example, forskip returns with the movies series at its tail position.
You will need to use the head function to return the series back to its head position.
Forever 0
The forever function evaluates a block endlessly or until a it encounters the break
function.
The following example uses forever to check for the existence of a file every ten
minutes:
forever [
if exists? %datafile [break]
wait 0:10
]
Break 0
You can stop the repeated evaluation of a block with the break function. The break
function is useful when a special condition is encountered and the loop must be
stopped. The break function works with all types of loops.
In the following example, the loop will break if a number is greater than 5.
repeat count 10 [
if (random count) > 5 [break]
print "testing"
]
testing
testing
testing
testing
testing
testing
testing
The break function does not return a value from the loop unless a /return
refinement is used:
testing
testing
testing
testing
stop here
In the above example, if the repeat terminates without the condition occurring, the
block returns the string normal exit. Otherwise, break/return will return the
string stop here.
Selective Evaluation C
Select 0
The select function is often used to obtain a particular value or block, given a target
value. If you define a block of values and actions, you can use select to search for
the action that corresponds to a value.
cases: [
center [print "center"]
right [print "right"]
left [print "left"]
]
action: select cases ’right
if action [do action]
right
In the previous example, the select function finds the word right and returns
the block that follows it. (If for some reason the block was not found, then none
would have been returned.) The block is then evaluated. The values used in the
example are words, but they can be any kind of value:
cases: [
5:00 [print "everywhere"]
10:30 [print "here"]
18:45 [print "there"]
]
action: select cases 10:30
if action [do action]
here
Switch 0
The select function is used so often that there is a special version of it called switch,
which includes the evaluation of the resulting block. The switch function makes it
easier to perform inline selective evaluation. For instance, to switch on a simple
numeric case:
switch 22 [
11 [print "here"]
22 [print "there"]
]
there
The switch function also returns the value of the block it evaluates, so the previous
example can also be written as:
print switch 22 [
11 [join str "here"]
22 [join str "there"]
]
right there
and:
2406.2
The cases can be any valid data type, including numbers, strings, words, dates,
times, urls, and files. Here are some examples:
Strings:
person: "kid"
switch person [
"dad" [print "here"]
"mom" [print "there"]
"kid" [print "everywhere"]
]
everywhere
Words:
person: ’kid
switch person [
dad [print "here"]
mom [print "there"]
kid [print "everywhere"]
]
everywhere
Files:
file: %rebol.r
switch file [
%user.r [print "here"]
%rebol.r [print "everywhere"]
%file.r [print "there"]
]
everywhere
URLs:
url: ftp://ftp.rebol.org
switch url [
http://www.rebol.com [print "here"]
http://www.cnet.com [print "there"]
ftp://ftp.rebol.org [print "everywhere"]
]
everywhere
Tags:
tag: <LI>
print switch tag [
<PRE> ["Preformatted text"]
<TITLE> ["Page title"]
<LI> ["Bulleted list item"]
]
Times:
time: 12:30
switch time [
8:00 [send [email protected] "Hey, get up"]
12:30 [send [email protected] "Join me for lunch."]
16:00 [send [email protected] "Dinner anyone?"]
]
Default Case
A default case can be specified when none of the other cases match. Use the default
refinement to specify a default:.
time: 7:00
switch/default time [
5:00 [print "everywhere"]
10:30 [print "here"]
18:45 [print "there"]
] [print "nowhere"]
nowhere
Common Cases
If you have common cases, where the result would be the same for several values,
you can define a word to hold a common block of code:
url: http://www.rebol.com
switch url [
http://www.rebol.com case1
http://www.cnet.com [print "there"]
ftp://ftp.rebol.org case1
]
20
Other Cases
More than just blocks can be evaluated for cases. This example evaluates the file
that corresponds to a day of the week:
switch now/weekday [
1 %monday.r
5 %friday.r
6 %saturday.r
]
So, if it’s Friday, the friday.r file is evaluated and its result is returned from the
switch. This type of evaluation also works for URLs:
switch time [
8:30 ftp://ftp.rebol.org/wakeup.r
10:30 http://www.rebol.com/break.r
18:45 ftp://ftp.rebol.org/sleep.r
]
The cases for switch are enclosed in a block, and therefore can be defined apart
from the switch statement:
schedule: [
8:00 [send [email protected] "Hey, get up"]
12:30 [send [email protected] "Join me for lunch."]
16:00 [send [email protected] "Dinner anyone?"]
]
NOTE: Note that for best performance, you can put the most frequently used cases
first.
Stopping Evaluation C
Evaluation of a script can be stopped at any time by pressing the ESC key on the
keyboard or by using the halt and quit functions.
The halt function stops evaluation and returns you to the REBOL console prompt:
The quit function stops evaluation and exits the REBOL interpreter:
Trying Blocks C
There are times when you want to evaluate a block, but should an error occur, you
do not want to stop the evaluation of the rest of your script.
For example, you might be performing a number division, but do not want your
script to stop if a divide-by-zero occurs.
The try function allows you to catch errors during the evaluation of a block. It is
almost identical to do. The try function will normally return the result of the block;
however, if an error occurs, it will return an error value instead.
In the following example, when the divide by zero occurs, the script will pass an
error back to the try function, and evaluation will continue from that point.
for num 5 0 –1 [
if error? try [print 10 / num] [print “error”]
]
5
4
3
2
1
error
4- 1
Scripts
Overview
Overview D
The term script refers not only to single files that are evaluated but also to source
text embedded within other types of files (such as, web pages), or fragments of
source text that are saved as data files or passed as messages.
File Suffix 0
REBOL scripts typically append a .r suffix to file names; however, this convention
is not required. The interpreter reads files with any suffix and scans the contents for
a valid REBOL script header.
Structure 0
The structure of a script is free-form. Indentation and spacing can be used to clarify
the structure and content of the script. In addition, you are encouraged to use the
standard scripting style to make scripts more universally readable. See the “Style
Guide” on page 4-13 for more information.
Headers D
Directly preceding the script body, every script must have a header that identifies
its purpose and other script attributes. A header can contain the script name,
author, date, version, file name, and additional information. REBOL data files that
are not intended for direct evaluation do not require a header.
■ They identify a script as being valid source text for the REBOL interpreter.
■ The interpreter uses the header to print out the script’s title and determine what
resources and versions it needs before evaluating the script.
■ Headers provide a standard way to communicate the title, purpose, author, and
other details of scripts. You can often determine from a script’s header if a script
interests you.
■ Script archives and web sites use headers for generating script directories,
categories, and cross references.
■ Some text editors access and update a script’s header to keep track of
information such as the author, date, version, and history.
REBOL [block]
For the interpreter to recognize the header, the block must immediately follow the
word REBOL. Only white space (spaces, tabs, and lines) is permitted between the
word REBOL and the block.
The block that follows the REBOL word is an object definition that describes the
script. The preferred minimal header is:
REBOL [
Title: "Scan Web Sites"
Date: 2-Feb-2000
File: %webscan.r
Author: "Jane Doer"
Version: 1.2.3
]
When a script is loaded, the header block is evaluated and its words are set to their
defined values. These values are used by the interpreter and can also be used by
the script itself.
Note that words defined as a single value can also be defined as multiple values by
providing them in a block:
REBOL [
Title: "Scan Web Sites"
Date: 12-Nov-1997
Author: ["Ema User" "Wasa Writer"]
]
Headers can be more complex, providing information about the author, copyright,
formatting, version requirements, revision history, and more. Because the block is
used to construct the header object, it can also be extended with new information.
This means that a script can extend the header as needed, but it should be done
with care to avoid ambiguous or redundant information.
REBOL [
Title: "Full REBOL Header Example"
Date: 8-Sep-1999
Name: ’Full-Header ; For window title bar
Version: 1.1.1
File: %headfull.r
Home: http://www.rebol.com/rebex/
Purpose: {
The purpose or general reason for the program
should go here.
}
Note: {
An important comment or notes about the program
can go here.
}
History: [
0.1.0 [5-Sep-1999 "Created this example" "Carl"]
0.1.1 [8-Sep-1999 {Moved the header up, changed
comment on extending the header, added
advanced user comment.} "Carl"]
]
Language: ’English
]
Prefaced Scripts
Script text does not need to begin with a header. Scripts can begin with any text,
allowing them to be inserted into email messages, web pages, and other files.
The header marks the beginning of the script, and the text that follows is the body
of the script. Text that appears before the header is called the preface and is ignored
during evaluation.
REBOL [
Title: "Preface Example"
Date: 8-Jul-1999
]
Embedded Scripts
If a script is to be followed by other text unrelated to the script itself, the script must
be enclosed with square brackets [ ]:
Only white space is permitted between the initial bracket and the word REBOL.
Script Arguments D
When a script is evaluated, it has access to information about itself. This is found
in the system/script object. The object contains the fields listed in Table 4-1.
Table 4-1. Object Fields for system/script
Field Description
print system/script/title
print system/script/header/date
do system/script/args
do system/script/path/script.r
The last example evaluates a script called script.r in the same directory as the
script that is currently running.
Program Options 0
Scripts also have access to the options provided to the REBOL interpreter when it
was started. These are found in the system/options object. The object contains
the fields listed in Table 4-2.
Table 4-2. Object Fields for system/options
Field Description
The system/options object also contains additional options that were provided
on the command line. Type
probe system/options
Examples:
print system/options/script
probe system/options/args
Running Scripts D
There are two ways to run a script: as the initial script when the REBOL interpreter
is started, or from the do function.
To run a script when starting the interpreter, provide the script name on the
command line following the REBOL program name:
rebol script.r
From the do function, provide the script file name or URL as an argument. The file
is loaded into the interpreter and evaluated:
do %script.r
do http://www.rebol.com/script.r
The do function returns the result of the script when it finishes evaluation.
Note that the script file must include a valid REBOL header.
Loading Scripts 0
Script files can be loaded as data with the load function. This function reads the
script and translates the script into values, words, and blocks, but does not evaluate
the script. The result of the load function is a block, unless only a single value was
loaded, then that value is returned.
The script argument to the load function is a file name, URL, or a string.
load %script.r
load %datafile.txt
load http://www.rebol.org/script.r
load "print now"
probe data
Note that a file does not require a header to be loaded. The header is necessary only
if the file is to be run as a script.
The load function supports a few refinements. Table 4-3 lists the refinements and a
description of their functionality:
Table 4-3. The load Function Refinements
Refinement Description
Normally, load does not return the header from the script. But, if the /header
refinement is used the returned block contains the header object as its first
argument.
The /next refinement loads the next value and returns a block containing two
values. The first returned value is the next value from the series. The second
returned value is the string position immediately following the last item loaded.
The /markup refinement loads HTML and XML data as a block of tags and strings.
All tags are tag data types. All other data are treated as strings.
<title>This is an example</title>
probe data
Saving Scripts 0
Data can be saved to a script file in a format that can be loaded into REBOL with
the load function. This is a useful way to save data values and blocks of data. In
this fashion, it is possible to create entire mini-databases.
The save function expects two arguments: a file name and either a block or a value
to be saved:
The data is written out in REBOL source text format, which can be loaded later
with:
Simple values can also be saved and loaded. For instance, a date stamp can be
saved with:
To save a script file with a header, the header can be provided in a refinement as
either an object or a block:
Commenting Scripts 0
You can also use strings for comments. For instance, you can create multi-line
comments with a string enclosed in braces:
{
This is a long multilined comment.
}
This technique of commenting works only when the string is not interpreted as an
argument to a function. If you want to make sure that a multi-line comment is
recognized as a comment and is not interpreted as code, precede the string with the
word comment:
comment {
This is a long multilined comment.
}
The comment function tells REBOL to ignore the following block or string.
NOTE: Note that string and block comments are actually part of the script block.
Care should be taken to avoid placing them in data blocks, because they would
appear as part of the data.
Style Guide D
REBOL scripts are free-form. You can write a script using the indenting, spacing,
line length, and line terminators you prefer. You can put each word on a separate
line or join them together on one long line.
While the formatting of your script does not affect the interpreter, it does affect its
human readability. Because of this, REBOL Technologies encourages you to follow
the standard scripting style described in this section.
Of course, you don’t have to follow any of these suggestions. However, scripting
style is more important than it first seems. It can make a big difference in the
readability and reuse of scripts. Users may judge the quality of your scripts by the
clarity of their style. Sloppy scripts often mean sloppy code. Experienced script
writers usually find that a clean, consistent style makes their code easier to produce,
maintain, and revise.
Formatting 0
Use the following guidelines for formatting REBOL scripts for clarity.
Where possible, an opening square bracket remains on the line with its associated
expression. The closing bracket can be followed by more expressions of that same
level. These same rules apply equally to parenthesis ( ) and braces { }.
if check [
do this and do that
do another thing
do a few more things
]
either check [
when an expression extends
past the end of a block...
][
this helps keep things
straight
]
while [
do a longer expression
to see if it’s true
][
the end of the last block
and start of the new one
are at the WHILE level
]
adder: func [
"This is an example function"
arg1 "this is the first arg"
arg2 "this is the second arg"
][
arg1 + arg2
]
An exception is made for expressions that normally belong on a single line, but
extend to multiple lines:
This also applies to grouped values that belong together, but must be wrapped to fit
on the line:
[
"Hitachi Precision Focus" $1000 10-Jul-1999
"Computers Are Us"
Word Names 0
Words are a user’s first exposure to your code, so it is critical to choose words
carefully. A script should be clear and concise. When possible, the words should
relate to their English or other human language equivalent, in a simple, direct way.
Local words can often be shortened to a single word. Longer, more descriptive
words are better for global words.
When using a noun as a verb, use special characters such as ? where applicable.
For instance, the function for getting the length of a series is length?. Other REBOL
functions using this naming convention are:
Script Headers 0
The advantage of using headers is clear. Headers give users a summary of a script
and allow other scripts to process the information (like a cataloging script). A
minimum header provides a title, date, file name and purpose. Other fields can also
be provided such as author, notes, usage, and needs.
REBOL [
Title: "Local Area Defringer"
Date: 1-Jun-1957
File: %defringe.r
Purpose: {
Stabilize the wide area ignition transcriber
using a double ganged defringing algorithm.
}
]
Function Headers 0
defringe: func [
"Return the defringed localization radius."
area "Topo area to defringe"
time "Time allotted for operation"
/cost num "Maximum cost permitted"
/compound "Compound the calculation"
][
...code...
]
The best way to name a file is to think about how you can best find that file in a
few months. Short and clear names are often enough. Plurals should be avoided,
unless meaningful.
In addition, when naming a script, consider how the name will sort in a directory.
For instance, keep related files together by starting them with a common word.
%net-start.r
%net-stop.r
%net-run.r
Embedded Examples 0
Where appropriate, provide examples within a script to show how the script
operates and to give users a quick way of verifying that the script works correctly
on their system.
Embedded Debugging 0
verbose: on
check-data: off
Minimize Globals 0
In large scripts and where possible, avoid using global variables that carry their
internal state from one module or function to another. For short scripts, this isn’t
always practical. But recognize that short scripts may become longer scripts over
time.
If you have a collection of global variables that are closely related, consider using
an object to keep track of them:
Script Cleanup D
Here is a short script that can be used to clean up the indentation of a script. It
works by parsing the REBOL syntax and reconstructing each line of the script. This
example can be found in the REBOL Script Library at www.REBOL.com.
clean-script: func [
"Returns new script text with standard spacing."
script "Original Script text"
/spacey "Optional spaces near brackets/parens"
/local str new
] [
spaced: found? Spacey
out: append clear copy script newline
parse script blk-rule: [
some [
str:
newline (emit-line) |
#";" [thru newline | to end] new:
[#"[" | #"("]
(emit str 1 append indent tab)
blk-rule |
[#"]" | #")"]
(remove indent emit str 1) |
skip (set [value new]
load/next str emit str new) :new
]
]
remove out ; remove first char
]
This chapter explains the concepts behind series and how they are used in
REBOL/Core. It includes the following information:
5- 1
Series
Basic Concepts
Basic Concepts E
The concept of a series is quite simple to grasp and is the basis for nearly everything
in REBOL. It is very important to understand series well.
There are many series data types in REBOL. A block, a string, a list, a URL, a path,
an email, a file, a tag, a binary, a bitset, a port, a hash, an issue, and an image are
all series data types. Series data types can all be accessed and processed in the same
way with the same small set of functions.
Traversing a Series 0
Since a series is an ordered set of values, you can traverse within it. As an example,
take a series of three colors defined by the following block:
There is nothing special about this block. It is a series containing three words. It
has a set of values: red, green, and blue. The values are organized into a specific
order: red is first, green is second, and blue is third.
The first position of the block is called its head. This is the position occupied by
the word red. The last position of the block is called its tail. This is the position
immediately after the last word in the block. If you were to draw a diagram of the
block, it would look like this:
Head Tail
Notice that the tail is just past the end of the block. The importance of this will
become more clear shortly.
The variable colors is used to refer to the block. It is currently set to the head of
the block:
Colors
true
red
green
You can reposition the colors variable in the block using various functions. To
move the colors variable to the next position in the colors block, use the next
function:
The next function moves forward one value in the block and returns that position
as a result. The colors variable is now set to that new position:
Colors
The position of the colors variable has changed. Now the variable is no longer
at the head of the block:
false
green
The position of the value that is returned by the first function is relative to the
position that colors has in the block. The returned value is not the first color in
the block, but the first color immediately following the current position of the block.
Similarly, if you ask for the length or the second color, you find that these are
relative as well:
blue
You could move to the next position, and get a similar set of results:
blue
Colors
The colors variable is now at the last color in the block, but it is not yet to the tail
position.
false
Now the colors variable is resting at the tail of the block. It is no longer
positioned at a valid color, but is past the end of the block.
re d green blue
Colors
false
You receive an error in this last case because there is no valid first item when you
are past the end of the block.
you will move the colors variable back one position in the series:
Colors
blue
Skipping Around 0
The previous examples move through the series one item at a time. However, there
are times when you want to skip past multiple items using the skip function.
Assume that the colors variable is positioned at the head of a series:
Colors
The skip function is similar to next in that skip returns the series at the new
position.
Colors
blue
This is similar to back. In the above example, a skip of –1 moves back one item.
Colors
green
Note that you cannot skip past the tail or the head of a series. If you attempt to do
so, skip only goes as far as it can. It will not generate an error.
If you skip too far forward, skip returns the tail of the series:
true
If you skip too far back, skip returns the head of the series:
true
To skip directly to the head of the series, use the head function:
true
red
true
Extracting Values 0
Some of the previous examples made use of the first and second ordinal functions
to extract specific values from a series. The full set of ordinal functions is:
first
second
third
fourth
fifth
last
Ordinal functions are provided as a convenience, and are used for picking values
from the most common position in a series. Here are some examples:
red
blue
indigo
teal
blue
indigo
print colors/3
blue
print colors/5
indigo
Extracting a value past the end of its series generates an error in the case of the
ordinal functions and returns none in the case of the pick function or a pick path:
none
print colors/10
none
Extracting a Sub-series 0
You can extract multiple values from a series with the copy function. To do so, use
copy with the /part refinement, which specifies the number of values that you want
to extract:
probe sub-colors
[red green]
copy/part colors 2
red green
To copy a sub-series from any position within the series, first traverse to the starting
position. The following example moves forward to the second position in the series
using next before performing the copy:
probe sub-colors
[green blue]
green blue
The length of the series to copy can be specified as an ending position, as well as a
copy count. Note that the position indicates where the copy should stop, not the
ending position.
[red]
[red green]
[green]
This can be useful when the ending position is found as the result of the find
function:
file: %image.jpg
image
You can insert one or more new values into any part of a series using the insert
function. When you insert a value at a position in a series, space is made by shifting
its prior values toward the tail of the series.
red green
Colors
To insert a new value at the head of the block where the colors variable is now
positioned:
The red and green words are shifted over and the blue word (which is prefixed
with a tick because it is a word and should not be evaluated) is inserted at the head
of the list.
Colors
Note that the colors variable remains positioned at the head of the list.
probe colors
Also note that the return from the insert function was not used because it was not
set to a variable or passed along to another function. If the return had been used to
set the value of the colors variable with the line:
the effect on the block would have been the same, but the position of the colors
variable would have changed as a result of setting the return value. The position
returned from insert is immediately following the insertion point.
Colors
An insertion can be made anywhere in the series. The position of the insert can be
specified, and it can include the tail. Inserting at the tail has the effect of appending
to the series.
probe colors
Colors
Colors
The word gold has been inserted at the tail of the series.
Another way to insert at the tail of a series is with the append function. The
append function works in the same way as insert, but always inserts at the tail.
The previous example would become:
The insert and append function also accept a block of arguments to insert. As an
example:
probe colors
If you want to insert the new values between the red and green words:
probe colors
The insert and append functions have other capabilities that are covered in more
detail in a later section.
Removing Values 0
You can remove one or more values from any part of a series by using the remove
function.
As shown here:
Colors
You can remove the first value from the block with the line:
remove colors
Colors
probe colors
The remove function removes values relative to the position of the colors
variable. You can remove values from anywhere in the series by setting the
position.
green gold
Colors
remove/part colors 2
Colors
Removing all of the remaining values is a common operation. The clear function is
provided to make this more direct. Clear removes all values from the current
position to the tail. For example:
As shown here:
Colors
blue
Colors
clear colors
Changing Values 0
One additional set of functions is provided for changing values in a series. The
change function replaces one or more values with new values. Although this can
be accomplished by removing and inserting values, it is more efficient to use
change.
Colors
Colors
probe colors
The poke function allows you to specify that the change occur at a particular
position relative to the colors variable. The poke function is similar to the pick
function described earlier.
Colors
As proven by:
probe colors
The change function has additional refinements that are described later in this
chapter.
Series Functions E
Here is a summary of the functions that operate on series. Most of these were
described in detail in the previous section. Others will be covered in more detail in
this section.
Creation 0
Function Description
Navigation 0
Function Description
Information 0
Function Description
Extraction 0
Function Description
Modification 0
Function Description
Search 0
Function Description
Ordering 0
Function Description
Data Sets 0
Function Description
All series data types can be divided into two broad classes. Each includes a data
type value and a type test function.
Block Types 0
String Types 0
Pseudo-types 0
Series data types are grouped into a few pseudo-types that make function argument
and type testing easier:
Table 5-11. Pseudo-types
Pseudo-type Description
Series Information E
Length? 0
The length of a series is the number of items (values for a block or characters for a
string) from the current position to the tail. If the current position is the head of the
series, then the length is the number of items in the entire series.
Length of 3
Colors Tail
Length of 2
Colors Tail
print length? []
data: [1 2 3 4 5 6 7 8]
print length? data
Head? 0
The head of a series is the position of its first value. If a series is at its head, the
head? function returns true:
data: [1 2 3 4 5]
print head? data
true
false
Tail? 0
The tail of a series is the position immediately following the last value. If a series
variable is at the tail, the tail? function returns true:
data: [1 2 3 4 5]
print tail? data
false
true
true
If empty? returns true, it means there are no values between the current position
and the tail; however, there still may be values in the series. Values can still be
present before the current position. If you need to determine if the series is empty
from head to tail, use:
false
Index? 0
The index is the position in a series relative to the head of the series. To determine
the index position for a series variable, use the index? function:
data: [1 2 3 4 5]
print index? data
Offset? 0
The distance between two positions in a series can be determined with the offset?
function.
data: [1 2 3 4]
data1: next data
data2: back tail data
print offset? data1 data2
In this example, the offset is the difference between position 2 and position 4:
Offset of 2
1 2 3 4
data1 data2
Empty?
New series are created with the make and copy functions.
Use the make function to create a new series from a series data type and an initial
size. The size is an estimate of the size needed for the series. If the initial size is
too small, the series will automatically expand, but at a slight performance cost.
block: copy [1 2 3 4 5]
Copying is also important for use with functions that modify the contents of a
series. For instance, if you want to change the case of a string without modifying
the original, use the copy:
Partial Copies 0
The copy function /part refinement takes a single argument, which is either an
integer specifying the number of items to copy or a position within the series
indicating the last position to copy.
Message in a bottle
Message
in a
Deep Copies 0
Many blocks contain other blocks and strings. When such a block is copied, its
sub-series are not copied. The sub-series are referred to directly and are the same
series data as the original block. If you modify any of these sub-series, you modify
them in the original block as well.
The copy/deep refinement forces a copy of all series values within a block:
["abc" [1 2 3]]
["abc" [1 2 3]]
["abc" [1 2 3]]
If either the string or block contained in blk-two is modified, the series values in
blk-one are also modified.
["abcDEF" [1 2 3 4 5 6]]
["abcDEF" [1 2 3 4 5 6]]
Using copy/deep makes a copy of all series values found in the block:
["abcDEF" [1 2 3 4 5 6]]
["abcDEFghi" [1 2 3 4 5 6 7 8 9]]
Initial Copies 0
When initializing a string or block series, use copy on the value to make is a unique
series:
Using copy assures that a new series is created for the word every time the word is
initialized. Here is an example of why this is important.
print-it
ha
print-it
haha
print-it
hahaha
In this example, because copy wasn’t used, the empty string series is modified with
every call of print-it. The string series ha is inserted into str each time
print-it is called.
Examining the source of the function as it now exists exposes the root of the
problem:
source print-it
Although str is a local variable, its string value is global. To avoid this problem,
the function should copy the empty string or use make on the string.
print-it
ha
print-it
ha
print-it
ha
Series Iteration E
You can use a loop to traverse a series. There are a few loop functions that can help
automate the iteration process.
While Loop 0
The most flexible approach is to use a while loop, which allows you to do just about
anything to the series without problems.
The method shown below allows you to insert values without hitting a value twice:
This example illustrates that the insert returns the position immediately following
the insertion.
To remove a value without accidentally skipping a value, use the following code:
Forall Loop 0
The forall loop is similar to the while loop, but eliminates some of the effort
required. The forall loop starts from the current index and advances through a
series to its tail evaluating a block for every value.
The forall loop takes two arguments: a series variable and a block to evaluate for
each iteration.
red
green
blue
yellow
orange
The forall advances the variable position through the series, so when it returns the
variable is left at its tail:
true
Also, if the block modifies the series, be careful to avoid missing or repeating a
value. The forall loop works in some cases; however, if you are uncertain, use the
while loop instead.
forall colors [
if colors/1 = 'blue [remove colors]
print first colors
]
red
green
yellow
orange
Forskip Loop 0
Similar to forall, the forskip loop advances through a series starting at the current
position, but skips the specified number of values each time.
The forskip loop takes three arguments: a series variable, the skip between each
iteration, and a block to evaluate for each iteration.
red
blue
orange
The forskip loop leaves the series at its tail, requiring you to reset it.
true
Foreach Loop 0
The foreach loop moves through a series setting a word or multiple words in to the
values in the series.
The foreach loop takes three arguments: a word or a block of words that holds the
values for each iteration, a series, and a block to evaluate for each iteration.
red
green
blue
yellow
orange
gold
red green
blue yellow
orange gold
The foreach loop does not advance the current index through the series, so there is
no need to reset its series variable.
Any of the loops can be stopped at any time by evaluating the break function from
within the evaluation block. See the “Expressions” Chapter for more information
about the break function.
Searching Series E
The find function searches through block or string series for a value or pattern.
This function has many refinements that permit a wide range of variations in search
parameters.
Simple Find 0
The simplest and most common use of find is to search a block or string for a value.
In this case, find requires only two arguments: the series to search and the value to
find.
blue
The find function can also search for values by data type. This can be quite useful.
20-Feb-2000
United
none
Refinement Summary 0
Find has many refinements that support a wide variety of search parameters:
Table 5-12. Refinement Summary
Refinement Description
Refinement Description
Partial Searches 0
The next example uses an ending position. The search is restricted to a single line
of text:
text: {
This is line one.
This is line two.
}
line one.
Tail Positions 0
The find function returns the position in the series where an item was found. The
/tail refinement returns the position immediately following the item that was
found. Here’s an example:
filename: %script.txt
.txt
txt
script.r
Backward Searches 0
The last example in the previous section would fail if the filename had more than
one period. For instance:
filename: %new.script.txt
print find filename "."
.script.txt
In this example we want the last occurrence of the period in the string, which can
be found using the /last refinement. The /last refinement searches backward
through a series.
.txt
txt
If you want to continue to search backward through the string, you need the
/reverse refinement. This refinement performs a search from the current position
backward toward the head, rather than forward toward the tail.
.txt
.script.txt
Notice that /reverse continues the search just before the position of the last match.
This prevents it from finding the same period again.
Repeated Searches 0
You can easily repeat the find function to search for multiple occurrences of a value
or string. Here is an example that would print all the strings found in a block:
The next example counts the number of new lines in a script. It uses the /tail
refinement to prevent an infinite loop and returns the position immediately
following the match.
To perform a repeated search in reverse, use the /reverse refinement. The following
example prints all of the index positions in reverse order for the text of a script.
Matching 0
The /match refinement modifies the behavior of find to perform pattern matching
on the current position of a series. This refinement allows parsing operations to be
performed by matching the next part of a series with expected patterns. See the
chapter on “Parsing” for another way to match series.
none
none
Notice in the example that a search is not performed. The beginning of the series
either matches or it does not. If it does match, the series is advanced the position
immediately following the match point, allowing you to match the next sequence.
grammar: [
["keep" "make" "trust"]
["things" "life" "ideas"]
["simple" "smart" "happy"]
]
true
true
false
The capability of /match can be greatly extended with the addition of the /any
refinement as discussed below.
Wildcard Searches 0
The /any refinement enables wildcard pattern matching. The question mark (?)
and asterisk (*) characters act as wildcards for matching any single character or any
number of characters respectively. The /any refinement can be used in conjunction
with find with or without the /match refinement.
Examples:
str: "abcdefg"
print find/any str "c*f"
cdefg
bcdefg
email-list: [
[email protected]
[email protected]
[email protected]
[email protected]
[email protected]
]
foreach email email-list [
if find/any email *@rebol.dom [print email]
]
[email protected]
[email protected]
[email protected]
The next example uses the /match refinement to attempt to match the pattern to
the next part of the series:
file-list: [
%rebol.exe
%notes.html
%setup.html
%feedback.r
%nntp.r
%rebdoc.r
%rebol.r
%user.r
]
rebdoc.r
rebol.r
Select 0
A useful variation of the find function is the select function, which returns the
value following the one found. The select function is often used to lookup a value
in tagged blocks of data. The select function takes the same arguments as find: the
series to search and the value find. However, unlike find, which returns a series
position, the select function returns the value that follows the match.
blue
Given a simple database, the select function can be used to access its values:
email-book: [
"George" [email protected]
"Paul" [email protected]
"Ringo" [email protected]
"Robert" [email protected]
]
Use the select function to find a block of expressions to evaluate. For example, given
the following data:
cases: [
10 [print "ten"]
20 [print "twenty"]
30 [print "thirty"]
]
do select cases 10
ten
do select cases 30
thirty
To replace values throughout a series, you can use the replace function. This
function searches for a specific value in a series, then replaces it with a new value.
The replace function takes three arguments: the series to search, value to replace,
and the new value.
data: [1 2 8 4 5]
probe replace data 8 3
[1 2 3 4 5]
[1 2 3 four 5]
[0 2 3 four 5]
Use the /all refinement to replace all occurrences of the value from the current
position to the tail.
[0 0 0 four 0]
do code
hello
world
Sorting Series E
The sort function offers a simple, quick method of sorting series. It is most useful
for blocks of data, but can also be used on strings of characters.
Simple Sorting 0
abellmops
Notice that sort is destructive to its argument series. It reorders the original data.
To prevent this, use copy, as in the following example:
0123456789AbCdEfGhI
ABCDEFGHIabcdefghi
0123456789ABCDEFGHIabcdefghi
Group Sorting 0
Often it is necessary to sort a data set that has more than one value per record. The
/skip refinement supports this for sorting records that have a fixed length. The
refinement takes one additional argument: an integer specifying length of each
record.
Here is an example that sorts a block that contains first name, last name, ages, and
emails. The block is sorted by its first column, first-name.
names: [
"Evie" "Jordan" 43 [email protected]
"Matt" "Harrison" 87 [email protected]
"Luke" "Skywader" 32 [email protected]
"Beth" "Landwalker" 104 [email protected]
"Adam" "Beachcomber" 29 [email protected]
]
sort/skip names 4
foreach [first-name last-name age email] names [
print [first-name last-name age email]
]
Comparison Functions 0
The /compare refinement allows you to perform custom comparisons on the data
being sorted. This refinement takes an additional argument, which is the
comparison function to use for ordering the data.
If the first value is less than the second, then true is returned from the function
and the first value is placed before the second value.
Similarly:
If the first value is greater than the second value, then true is returned and the data
is sorted with greater values first. The sort will descend from greater values.
Notice that in both cases the comparison function is passed by providing its name
preceded with a colon. The name preceded with a colon causes the function to be
passed to sort without first being evaluated. The comparison function could also
be provided directly with:
There are a few functions that operate on series as data sets. These functions allow
you to perform operations such as finding the union or intersection between two
series.
Unique 0
The unique function returns a unique set that contains no duplicate values.
Examples:
abrcd
Intersect 0
The intersect function takes two series and returns a series that contains the values
that are present in both series.
Examples:
[Bob]
[ham carrot]
print intersect [1 3 2 4] [3 5 4 6]
3 4
CD
all-chars: "ABCDEFGHI"
charset1: charset "ABCDEF"
charset2: charset "DEFGHI"
charset3: intersect charset1 charset2
true
false
[bill Bob]
Union 0
The union function takes two series and returns a series that contains all the values
from both series, but no duplicates.
Examples:
print union [1 3 2 4] [3 5 4 6]
1 3 2 4 5 6
ABCDEF
true
true
Exclude 0
The exclude function takes two series and returns a series that contains all the
values of the first series, less the values of the second.
probe exclude [1 2 3 4] [1 2 3 5]
[4]
[Bill Bart]
[cheese bread]
AB
[Bill bob]
Difference 0
The difference function takes two series and returns a series that contains all of the
values not in common with both series.
Examples:
probe difference [1 2 3 4] [1 2 3 5]
[4 5]
ABEF
data: [1 2 3 4 5]
start: find data 3
end: find start 4
print first start
Both the start and end variables refer to the series. They have different positions,
but the series they reference is the same.
1 2 3 4 5
start end
If an insert or remove function is performed on a series, the values in the series will
shift and the start and end variables may no longer refer to the same values. For
instance, if a value is removed from the series at the start position:
remove start
print first start
The series has shifted to the left and the variables now refer to different values.
1 3 4 5
start end
Notice that the index positions of the variables have not changed, but the values in
the series have changed. The same situation would occur when using insert.
Sometimes this side effect will work to your advantage. Sometimes it will not, and
you will need to correct for it in your code.
Modification Refinements E
The change, insert, and remove functions can take additional refinements to
modify their operation.
Part 0
The /part refinement accepts a count or a position in the series and uses it to limit
the effect of the function.
str: "abcdef"
blk: [1 2 3 4 5 6]
change/part str [1 2 3 4] 3
probe str
1234def
["abcd" 4 5 6]
You can insert part of a series into the tail of str and blk using insert/part.
1234def-ghi
["abcd" 4 5 6 "--" 7 8 9]
To remove part of the str and blk series, use remove/part. Note how find is used
to obtain the series position:
1234-ghi
["abcd" "--" 7 8 9]
Only 0
The /only refinement changes or inserts a block as a block, rather than its
individual values.
Examples:
blk: [1 2 3 4 5 6]
You can replace the 2 in blk with the block [a b c] and insert the block [$1 $2
$3] at the position of the 5.
[1 [a b c] 3 4 5 6]
Dup 0
Examples:
str: "abcdefghi"
blk: [1 2 3 4 5 6]
You can change the first four values in a string or block series to an asterisk(*)
with:
****efghi
To insert a dash (-) four times before the last value in a string or block:
****efgh----i
This chapter explores the block series type in more detail. It includes the following
information:
6- 1
Block Series
Blocks of Blocks
Blocks of Blocks F
When a block appears as a value within another block, it counts as a single value
regardless of how many values it contains. For example:
values: [
"new" [1 2]
%file1.txt ["one" ["two" %file2.txt]]
]
probe values
The length? of values is four. The second and fourth values are counted as single
values:
The block values within the values block can be used as a block as well. In the
following examples, second is used to extract the second value from values.
[1 2]
block
In the same way, series operations can be performed on other types of series values
in blocks. In the following examples, pick is used to extract %file1.txt from
values.
%file1.txt
file
The fourth value in values is a block containing another block. The following
examples use a path to get information about this value.
probe values/4
probe values/4/2
["two" %file2.txt]
block
block
The two series values in the fourth value’s block can also be accessed.
probe values/4/2/1
two
probe values/4/2/2
%file2.txt
string
file
too
%file2.r
The above examples illustrate REBOL’s ability to operate on values nested inside
blocks. Note that in the last series of examples, change is used to modify a string
and file series three layers deep in values. Printing out the values block
produces:
probe values
Arrays F
arr: [
[1 2 3 ]
[a b c ]
[$10 $20 $30]
]
You can obtain the values of an array with the series extraction functions:
[1 2 3]
You can also use paths to obtain values from the array:
probe arr/1
[1 2 3]
probe arr/3
probe arr/3/2
$20.00
arr/1/2: 20
probe arr/1
[1 20 3]
$40.00
Creating Arrays 0
The array function creates arrays dynamically. The function takes an argument that
is either an integer or a block of integers and returns a block that is the array. By
default, the cells of an array are initialized to none. To initialize array cells to some
other value, use the /initial refinement explained in the next section.
When array is supplied with a single integer, a one-dimensional array of that size
is returned:
arr: array 5
probe arr
When a block of integers is provided, the array has multiple dimensions. Each
integer provides the size of the corresponding dimension.
Here is an example of a two dimensional array that has six cells, two rows of three
columns:
arr: array [2 3]
probe arr
This can be made into a three dimensional array by adding another integer to the
block:
arr: array [2 3 2]
foreach lst arr [probe lst]
The block of integers that is passed to array can be as big as your memory will
support.
Initial Values 0
To initialize the cells of an array to a value other than none, use the /initial
refinement. This refinement takes one argument: the initial value. Here are some
examples:
arr: array/initial 5 0
probe arr
[0 0 0 0 0]
arr: array/initial [2 3] 0
probe arr
[[0 0 0] [0 0 0]]
Composing Blocks F
The compose function is handy for creating blocks from dynamic values. It can be
used for creating both data and code.
The compose function takes a block as an argument and returns a block that has
each value in the argument block. Values in parentheses are evaluated before the
block is returned. For example:
[1 2 7]
If the values in parentheses return a block, that block’s individual values are used:
[a b c d]
[a b [c d]]
[a b c d]
When compose is given a block that contains sub-blocks, the sub-blocks are not
evaluated, even if they contain parentheses:
[a b [c (d e)]]
If you would like the sub-blocks to be evaluated, use the /deep refinement. The
/deep refinement causes all parentheses to be evaluated, regardless of where they
are:
[a b [c d e]]
This chapter describes the string series type and its use in REBOL/Core. It includes
the following information:
7- 1
String Series
String Functions
String Functions G
There are a wide variety of functions that operate on or produce strings. Functions
are available for modifying strings, searching strings, compressing and
decompressing strings, changing the spacing of strings, parsing strings, and
converting strings. These functions operate on all string related datatypes, such as
string!, binary!, tag!, file!, URL!, email!, and issue!.
The string creation, modification and search functions are covered in the “Series”
chapter. They include the items listed in Table 7-1.
Table 7-1. String Functions
Function Description
In addition, the series traversing functions like next, back, head, and tail were
covered. They are used to reposition in strings. In addition, the series test functions
allow you to determine your position within a string.
This chapter will introduce functions that convert REBOL values into strings. These
functions are used often, and they are also used by the print and probe functions.
They include:
Table 7-2. String Conversion Functions
Function Description
Function Description
Function Description
Join 0
The join function takes two arguments and concatenates them into a single series.
The data type of series returned is based on the value of the first argument. When
the first argument is a series value, that series type is returned.
str: "abc"
file: %file
url: http://www.rebol.com/
abc123
%file.txt
http://www.rebol.com/index.html
When the first argument is not a series, the join converts it to a string first, then
performs the append:
$11.00 dollars
9:11:01 elapsed
30-Jun-2000 -- today
255.255.255.0 netmask
When the second argument to join is a block, the values of that block are evaluated
and appended to the series returned.
abc12
%/dir1/sub-dir/filename.txt
11:09:11AM on 30-Jun-2000
312.423123987234
Rejoin 0
The rejoin function is identical to join, except that it takes one argument, a block.
try123
hello
Form 0
$1.50
money
string
The following example uses form to find a number by its decimal value:
44.11
11.11
When form is used on a block, all values in the block are converted to string values
with spaces between each value:
The form function does not evaluate the values of a block. This results in words
being converted to string values:
Reform 0
The reform function is like form, except that blocks are reduced before being
converted.
Mold 0
The mold function converts a value to a string that is usable by REBOL. Strings
created with mold can be converted back to values with the load function.
block
string
[11 * 4]
#"["
block
[11 * 4]
money: $11.11
sub-blk: [inside another block mold this is unevaluated]
probe mold [$22.22 money "-- unevaluated block:" sub-blk]
Remold 0
The remold function works just like mold, except that blocks are reduced before
being converted.
Trim
The trim function removes extra spaces from a string.
The default operation of trim is to remove extra spaces from the head and tail of a
string:
print str
/auto – removes space from each line, relative to the first line
Use the /head and /tail refinements to trim from either end of a string:
Use the /auto refinement to trim leading spaces from multiple lines leaving
indented spaces intact:
str: {
indent text
indent text
indent text
indent text
indent text
}
print str
indent text
indent text
indent text
indent text
indent text
{indent text
indent text
indent text
indent text
indent text
}
Use /lines to trim the head and tail and also convert newlines into spaces:
indenttextindenttextindenttextindenttextindenttext
The /with refinement will remove all characters that you specify. In the following
example, spaces, line breaks and the characters e and t are removed:
indnxindnxindnxindnxindnx
str:
{^(tab)line one
^(tab)^(tab)line two
^(tab)^(tab)^(tab)line three
^(tab)line^(tab)full^(tab)of^(tab)tabs}
print str
line one
line two
line three
line full of tabs
By default, the detab function converts tabs to four spaces (the REBOL standard
spacing). All tabs in the string will be converted to spaces, regardless of where they
are located.
{ line one
line two
line three
line full of tabs}
Note that the detab and entab functions affect the string that is provided as an
argument. To change a copy of the source string, use the copy function.
The entab function converts spaces to tabs. Every four spaces will be converted to
a single tab. Only spaces at the beginning of a line will be converted to tabs.
{^-line one
^-^-line two
^-^-^-line three
^-line full of tabs}
You can use the /size refinement to specify the size of tabs. For instance, if you
want to convert each tab to eight spaces, or convert every eight spaces to a tab, you
can use this example:
There are two functions for changing character casing: uppercase and lowercase.
The uppercase function takes a string argument and converts its characters to
uppercase:
Ukiah
Checksum 0
The checksum returns the checksum of the string value. There are three types of
checksum that can be computed:
52719
356358
10943
A secure checksum will return a binary value, not an integer. Use the /secure
refinement to compute a secure checksum:
#{AAF4C61DDCC5E8A2DABEDE0F3B482CD9AEA9434D}
The compress function will compress a string and return a binary datatype. In the
following example, a small file is compressed by reading its contents, compressing
them, then writing it back to disk:
Str:
306 bytes
156 bytes
NOTE: Always keep an uncompressed backup of compressed data. If you lose only
one byte from a compressed binary, it can be difficult to recover the data. Do not
store file archives in a compressed format unless you have copies that are not
compressed.
Encoded strings can be decoded with the debase function. Note that the result is a
binary value. To convert it back to a string, use the to-string function.
binary
probe b-line
#{4E6F2120546865726527732061206C616E6421}
The /base refinement may be used with enbase and debase to specify a base2
(binary), base16 (hexadecimal), or base64 encoding.
01100001
binary
probe b2-str
#{61}
4E6F2120546865726527732061206C616E6421
binary
probe b16-line
#{4E6F2120546865726527732061206C616E6421}
The dehex function converts Internet URL and CGI style hexadecimal encoded
characters to strings. Hexadecimal ASCII representations appear in a URL or CGI
string as %xx, where xx is the hexadecimal value.
str: "there%20seem%20to%20be%20no%20spaces"
print dehex str
hello
This chapter introduces the use of functions in REBOL. It includes the following
information:
8- 1
Functions
Overview
Overview H
Evaluating Functions H
The “Expressions” Chapter covered the general details of evaluation. The way
function arguments are evaluated dictates the general order of words and values in
the language. This section goes into more detail on how functions are evaluated.
Arguments 0
Functions receive arguments and return results. Most functions require one or more
arguments; although, some functions, such as now (current date and time), do not
require any arguments.
The arguments that are supplied to a function are processed by the interpreter and
then passed to the function. Arguments are processed in the same way, regardless
of the type of function called, be it a native function, operator, user-defined
function, or otherwise. For example, the send function expects two arguments:
friend: [email protected]
message: "message in a bottle"
If you provide too few arguments to a function, an error message is returned. For
example, the send function expects two arguments and if you send one, an error is
returned
send friend
If too many arguments are provided, the extra values are ignored.
In the previous example, send already has two arguments, so the string, which is
the third argument, is ignored. Notice that no error message occurs. In this case,
there were no functions expecting the third argument. However, in some cases the
third argument may belong to another function that was evaluated before send.
Arguments to a function are evaluated from left to right. This order is followed even
when the arguments themselves are functions. For example, if you write:
the second argument must be computed by evaluating the detab function and the
copy function. The result of the copy will be passed to detab, and the result of
detab will be passed to send. In the previous example, the copy function is taking
a single argument, the message, and returns a copy of it. The copied message is
passed to the detab function, which removes the tab characters and returns the
detabbed message, which is passed to the send function. Notice how the results of
functions flow from right to left as the expression is evaluated.
The evaluation that is happening here can be shown by using parentheses to clarify
what is evaluated first. (However, the parentheses are not required, and actually
slow down the evaluation slightly.)
file: %image
insert tail insert file %graphics/ %.jpg
print file
graphics/image.jpg
In the following example, a directory name and a suffix are added to the base file
name. Parentheses can be used to clarify the order of evaluation:
NOTE: Parentheses make good “training wheels” to get started in writing REBOL.
However, it won’t take long before you can shed this aid and write the expressions
directly without the parentheses. Not using parentheses lets the interpreter
evaluate expressions quicker.
Functions usually require arguments of a specific data type. For example, the first
argument to the send function can only be an email address or block of email
addresses. Any other type of value will produce an error:
In the previous example, the error message is telling you that the address argument
of the send function needs to be either an email address or a block.
A quick way to find out what types of arguments are accepted by a function is to
type the following at the console prompt:
help send
USAGE:
SEND address message /only /header header-obj
DESCRIPTION:
Send a message to an address (or block of
addresses)
SEND is a function value.
ARGUMENTS:
address -- An address or block of addresses
(Type: email block)
message -- Text of message. First line is subject.
(Type: any)
REFINEMENTS:
/only -- Send only one message to multiple addresses
/header -- Supply your own custom header
header-obj -- The header to use (Type: object)
The ARGUMENTS section indicates the data type of each argument. Notice that the
second argument can be of any data type. So, it is valid to write:
Refinements 0
Refinements are specified by following the function name with a forward slash (/)
and a refinement name. For instance:
You have seen the copy function used to make a copy of a string. By default, copy
returns a copy of its argument:
no time
In the previous example, the /part refinement specifies that only seven characters
of the string are copied.
To review what refinements are allowed on a function such as copy, use online help:
help copy
USAGE:
COPY value /part range /deep
DESCRIPTION:
Returns a copy of a value.
COPY is an action value.
ARGUMENTS:
value -- Usually a series
(Type: series port bitset)
REFINEMENTS:
/part -- Limits to a given length or position.
range -- (Type: number series port)
/deep -- Also copies series values within the block.
Notice that the /part refinement requires an additional argument. Not all
refinements require additional arguments. For example, the /deep refinement
specifies that copy make copies of all its sub-blocks. No other arguments are
required.
When multiple refinements are used with a function, the order of the extra
arguments is determined by the order in which the refinements are specified. For
example:
str: "test"
insert/dup/part str "this one" 4 5
print str
Reversing the order of the /dup and /part refinement changes the order of the
arguments. You can see the difference:
str: "test"
insert/part/dup str "this one" 4 5
print str
thisthisthisthisthistest
Function Values 0
The previous examples describe how functions return values when they are
evaluated. Sometimes, however, you want to obtain the function as a value, not the
value it returns. This can be done by preceding the function name with a colon or
using the get function. For example, to set a word, pr, to the print function, you
would write:
pr: :print
pr "this is a test"
this is a test
Defining Functions H
You can define functions that work in the same way as native functions. These are
called user-defined functions. User-defined functions are of the function! data type.
You can make simple functions that require no arguments with the does function.
This example defines a new function that prints the current time:
10:30
The does function returns a value, which is the new function. In the example, the
print-time word is set to the function. However, this function value can be set
to a word, passed to another function, returned as the result of a function, saved in
a block, or immediately evaluated.
Functions that require arguments are made with the func function, which accepts
two arguments:
The first argument is a block that specifies the interface to the function. It includes
a description of the function, its arguments, the types allowed for arguments,
descriptions of the arguments, and other items. The second argument is a block of
code that is evaluated whenever the function is evaluated.
The newly defined function accepts two arguments, as specified in the first block.
The second block is the body of the function, which, when evaluated, adds the two
arguments together. The new function is returned as a value from func and the sum
word is set to it. Here it is in use:
444
NOTE: Func is a function that makes other functions. It performs a make on the
function! data type. Func is defined as:
Interface Specifications 0
The first block of a function definition is called its interface specification. This block
includes a description of the function, its arguments, the data types allowed for
arguments, descriptions of the arguments, and other items.
[
"function description"
[optional attributes]
argument-1 [optional type]
"argument description"
argument-2 [optional type]
"argument description"
...
/refinement
"refinement description"
refinement-arg-1 [optional type]
"refinement argument description”
...
]
Field Description
sum: func [
"Return the sum of two numbers."
arg1 [number!] "first number"
arg2 [number!] "second number"
][
arg1 + arg2
]
Now, the data type of the arguments is automatically checked, catching errors like:
To allow additional argument data types, more than one can be given:
sum: func [
"Return the sum of two numbers."
arg1 [number! tuple! money!] "first number"
arg2 [number! tuple! money!] "second number"
][
arg1 + arg2
]
4.4.4
$1334.00
Now the sum function accepts a number, tuple, or monetary value as arguments.
If within the function you need to distinguish what data type was passed, you can
use the data type test functions:
Because the sum function provided description strings, the help function now
supplies useful information about it:
help sum
USAGE:
SUM arg1 arg2
DESCRIPTION:
Return the sum of two numbers.
SUM is a function value.
ARGUMENTS:
arg1 -- first number (Type: number tuple money)
arg2 -- second number (Type: number tuple money)
Literal Arguments 0
As described earlier, the interpreter evaluates the arguments of functions and passes
them to the function body. However, there are times when you do not want
function arguments evaluated. For instance, if you need to pass a word and access
it from the function body, you do not want it evaluated as an argument. The help
function, which expects a word, is a good example:
help print
To prevent print from being evaluated, the help function must specify that its
argument should not be evaluated.
To specify that an argument not be evaluated, precede the argument name with a
single quote (indicates a literal word). For example:
test: 10
zap test
print test
10
The var argument is preceded with a single quote, which instructs the interpreter
to obtain the argument without evaluating it first. The argument is passed as the
word. For example:
test
Another example is a function that increments a variable by one and returns its
result (similar to the ++ increment function in C):
count: 0
++ count
print count
print ++ count
Get Arguments 0
Function arguments can also specify that a word’s value be fetched but not
evaluated. This is similar to the literal arguments described above, but rather than
passing the word, the value of the word is passed without being evaluated.
To specify that an argument be fetched but not evaluated, precede the argument
name with a colon. For example, the following function accepts functions as
arguments:
The sample function prints the body of a function that is passed to it. The argument
is preceded by a colon, which indicates that the value of the word should be
obtained, but not further evaluated.
print-body reform
[
form reduce value
]
print-body rejoin
[
block: reduce block
append either series? first block [copy first block]
[form first block]
next block
]
Defining Refinements 0
Within the body of the function, the refinement word is used as a logic value to
determine if the refinement was provided when the function was called.
For example, the following code adds a refinement to the sum function, which was
defined in a previous example:
sum: func [
"Return the sum of two numbers."
arg1 [number!] "first number"
arg2 [number!] "second number"
/average "return the average of the numbers"
][
either average [arg1 + arg2 / 2][arg1 + arg2]
]
The sum function specifies the /average refinement. In the body of the function,
the word is tested with the either function, which returns true when the refinement
is specified.
222
sum: func [
"Return the sum of two numbers."
arg1 [number!] "first number"
arg2 [number!] "second number"
/times "multiply the result"
amount [number!] "how many times"
][
either times [arg1 + arg2 * amount][arg1 + arg2]
]
The amount is only valid when the times refinement is true. Here is an example:
4440
Do not forget to check the refinement word before using the additional arguments.
If a refinement argument is used without the refinement being specified, it will have
a none value.
Local Variables 0
A local variable is a word whose value is defined within the scope of a function.
Changes to a local variable only affect the function in which the variable is defined.
If the same word is used outside of the function, it will not be affected by the
changes to the local variable of the same name.
Argument variables and refinements are local variables. Their values are defined
within the scope of the function. By convention, additional local variables can be
specified with the /local refinement. The /local refinement is followed by a list of
words that are used as local variables within the function.
average: func [
block "Block of numbers"
/local total length
][
total: 0
length: length? block
foreach num block [total: total + num]
either length > 0 [total / length][0]
]
Here the total and length words are local to the function.
Another method of creating local words is to use the function function, which is
identical to func, but accepts a separate block that contains the local words:
average: function [
block "Block of numbers"
][
total length
][
total: 0
length: length? block
foreach num block [total: total + num]
either length > 0 [total / length][0]
]
In this example, notice that the /local refinement is not used with the function
function. The function function creates the refinements for you.
If a local variable is used before its value has been set within the body of its
function, it will have a none value.
you will be using the same string each time and each time the function is used the
pervious name will appear within the result.
*test*
*thistest*
Returning a Value 0
As you know from the “Expressions” Chapter, blocks return their last value when
they return from evaluation:
do [1 + 3 5 + 7]
12
This is also true for functions. The last value is returned as the value of the function:
sum: func [a b] [
print a
print b
a + b
]
123
321
444
In addition, the return function can be used to stop the evaluation of a function at
any point and return a value:
probe find-value [1 2 3 4] 3
[3 4]
In the example, if the value is found, the function returns the series at the position
of the match. Otherwise, the function returns none.
To stop a function evaluation without returning a value, use the exit function:
source: func [
"Print the source code for a word"
’word [word!]
][
prin join word ": "
if not value? word [print "undefined" exit]
either any [
native? get word op? get word action? get word
][
print ["native" mold third get word]
][print mold get word]
]
To return more than one value from a function, use a block. You can do this easily
by returning a block that has been reduced.
For example:
The function returns a block that holds the series and the index value where the
value was found.
probe find-value [1 2 3 4] 3
[[3 4] 3]
The reduce is necessary to create a block of values from the block of words that it
is given. Do not return the local variables themselves. That is not a supported mode
of operation (currently).
To easily set variables to the return value of the function, use set:
3 4
print index
Nested Functions H
Functions can define other functions. The sub-functions can be global, local, or
returned as a result, depending on their purpose.
For example, to create a global function from within a function, assign it to a global
variable:
The timer function only exists during the period when the do-timer function is
being evaluated.
WARNING: You should avoid using variables that are local to the top level function as
an unevaluated part of the nested function. For example:
Unnamed Functions H
Furthermore, functions do not require names. You can create a function and
immediately evaluate it, store it in a block, pass it as an argument to a function, or
return it as a result from a function. Such functions are unnamed.
funcs: []
repeat n 10 [
append funcs func [t] compose [t + (n * 100)]
]
print funcs/1 10
110
print funcs/5 10
510
Functions can also be created and passed to other functions. For instance, when you
use sort with your own comparison, you provide a function as an argument:
Conditional Functions H
Because functions are created dynamically by evaluation, you can determine how
you want a function created, based on other information.
For instance, you may want to create a debugging version of a function that prints
additional information:
test-mode: on
Here you will create one of two functions, based on the test-mode you are running.
Function Attributes H
Function attributes provide control over specific function behaviors, such as the
method a function uses to handle errors or to exit. The attributes are an optional
block of words within the interface specifications.
Error messages typically are displayed when they occur within the function. If the
catch attribute is specified, errors that are thrown within the function are caught
automatically by the function. The errors are not displayed within the function but
at the point where the function was used. This is useful if you are providing a
function library (mezzanine functions) and don’t want the error to be displayed
within your function, but where it was called:
square-root num
]
root 4
root -4
Notice that in this example, the error occurs where root was called even though
the actual error was generated in the body of the function. This is because the catch
attribute was used.
Without the catch attribute, the error would occur within the root function:
The user may not know anything about the internals of the root function. So the
error message would be confusing. The user only knows about root, but the error
was in square-root.
Do not get the catch attribute mixed up with the catch function. Although they are
similar, the catch function can be applied to any block that is evaluated. [!See the
Expressions chapter].
The throw attribute allows you to write your own control functions, such as for,
foreach, if, loop, and forever, by allowing your functions to pass the return and
exit operations. For example, this loop function:
evaluates a block until a specific time has been reached or passed. This loop can
then be used within a function:
Now, what happens when the [return none] block is evaluated? Because this
block is evaluated by the loop-time function, the return occurs in that function,
not in do-job.
The throw attribute causes a return or exit that has occurred within the block to
be thrown up to the previous level, which is the next function causing do-job to
return.
Forward References H
Sometimes a script needs to refer to a function before it has been defined. This can
be done as long as the variable for the function is not evaluated before it is defined.
Scope of Variables H
The context of variables is called their scope. The broad scope of variables is that
of global and local. REBOL uses a form of static scoping, which is called
definitional scoping. The scope of a variable is determined when its context is
defined. In the case of a function, it is determined by when the function is defined.
All of the local variables defined within a function are scoped relative to that
function. Nested functions and objects are able to access their parent’s words.
a: 11
b: 10
a: 11
21
Note here that the b-func has access to the a-func variable.
Words that are bound outside of a function maintain those bindings even when
evaluated within a function. This is the result of static scoping, and it allows you
to write your own block evaluation functions (like if, while, loop).
For example, here is a signed if function that evaluates one of three blocks based on
the sign of a conditional value:
ifs: func [
"If positive do block 1, zero do block 2, minus do 3"
condition block1 block2 block3
][
if positive? condition [return do block1]
if negative? condition [return do block3]
return do block2
]
night
The blocks passed may contain the same words used within the ifs function
without interfering with the words defined local to the function. This is because the
words passed to the function are not bound to the function.
The next example passes the words block1, block2 and block3 to ifs as
pre-defined words. The ifs function does not get confused between the words
passed as arguments and the words of the same name defined locally:
evening time
Reflective Properties H
The specification of all functions can be obtained and manipulated during run-time.
For example, you can print the specification block for a function with:
[
"If condition is TRUE, evaluates the block."
condition
then-block [block!]
/else "If not true, evaluate this block"
else-block [block!]
]
[
head either only [insert/only tail series :value
] [
insert tail series :value
]
]
Functions can be dynamically queried during evaluation. This is how the help and
source functions work and how errors messages are formatted.
In addition, this feature is useful for creating your own unique versions of existing
functions. For example, a user-defined print function can be created that has exactly
the same specification as print, but sends its output to a string rather than the
display:
The name of the argument used for print-str is obtained from the interface
specification for print. You can examine that specification with:
[
"Outputs a value followed by a line break."
value "The value to print"
]
Useful information about all functions of the system can be retrieved with the help
function:
help send
USAGE:
SEND address message /only /header header-obj
DESCRIPTION:
Send a message to an address (or block of
addresses)
SEND is a function value.
ARGUMENTS:
address -- An address or block of addresses
(Type: email block)
message -- Text of message. First line is subject.
(Type: any)
REFINEMENTS:
/only -- Send only one message to multiple addresses
/header -- Supply your own custom header
header-obj -- The header to use (Type: object)
All of this information comes from the definition of the function. Help can be
obtained for all types of functions, not just natives or built-in functions. The help
function can also be used for user-defined functions. The documentation that is
displayed about a function is provided when the function is defined.
You can also search for help on functions that contain various patterns. For
instance, at the command prompt, you could type
Help "path"
clean-path (function)
lit-path! (datatype)
lit-path? (action)
path! (datatype)
path? (action)
set-path! (datatype)
set-path? (action)
split-path (function)
to-lit-path (function)
to-path (function)
to-set-path (function)
To view a list of all functions available in REBOL, type what at the command
prompt.
Another technique for learning about REBOL and for saving time in writing your
own function is to look at how many of the REBOL mezzanine functions are
defined. You can use the source function to do this.
source source
source: func [
"Prints the source code for a word."
'word [word!]
][
prin join word ": "
if not value? word [print "undefined" exit]
either any [native? get word op?
get word action? get word] [
print ["native" mold third get word]
] [print mold get word]
]
Here the source function is used to print its own source code.
Note that you cannot see the source code for native functions because they exist
only as machine code.
This chapter introduces the use of objects in REBOL. It includes the following
information:
9- 1
Objects
Overview
Overview I
Objects group values into a common context. An object can include scalar values,
series, functions, and other objects. Objects are useful in dealing with complex
structures as they allow related data and code to be encapsulated and passed as a
single value to functions.
Making Objects I
New objects are created with the make function. The make function requires two
arguments and returns a new object. The format of the make function is:
The first argument, parent-object, is the parent object from which the new
object is made. If no parent object is available, as when defining an initial object,
use the object! data type, as shown below:
The example object has two variables that hold two integers.
The block is evaluated, so it can include any type of expression to compute the
values of the variables:
Once an object has been made, it can serve as a prototype for creating new objects:
The above example makes a second instance of the example object. The new object
is a clone of the first object. New values for the second object are set in the block:
In the example above, the example2 object has different values than the original
example object for two of its variables.
The example2 object can also extend the object definition by adding new variables
to it:
The result is an object that has five variables: Three that came from the original
object, example, and two new ones.
The process of extending the definition of an object can be repeated any number of
times.
You can also create an object that contains variables that are initialized to some
common value. This can be done using a cascaded set of word definitions:
In the example above, the four variables are set to none within the new object.
■ Use make to create a new object based on a parent object or the object! data
type.
■ Add any new variables that are defined in the block to the new object.
■ Evaluate the block, which causes the variables defined in the block to be set to
the values in the new object.
Cloning Objects 0
When you use a parent object to make a new object, the parent object is cloned
rather than inherited. This means that if the parent object is modified, it has no
effect on the child object.
As an example, the following code creates a bank account object, whose variables
are blank:
To use the new object, values can be provided to create an account for a customer:
Since new accounts are made on a regular basis, it helps to use a function and some
global variables to create them:
last-account: 89431
bank-bonus: $10.00
make-account: func [
"Returns a new account object"
f-name [string!] "First name"
l-name [string!] "Last name"
start-balance [money!] "Starting balance"
][
last-account: last-account + 1
make bank-account [
first-name: f-name
last-name: l-name
account: last-account
balance: start-balance + bank-bonus
]
]
Accessing Objects I
Variables within objects are accessed with paths. The path consists of the object
name followed by the name of the variable. For example, the following code
accesses the variables in the example object:
example/var1
example/var2
print luke/last-name
Lakeswimmer
print fred/balance
$510.00
fred/balance: $1000.00
print fred/balance
$1000.00
You can use the in function to access object variables by fetching their words from
within their object context:
balance
The balance word returned has the object fred as its context. You can get the
value it holds by using get:
$1000.00
The second argument to the in function is a literal word. This allows you to
dynamically change words depending on what is needed:
Fred
Smith
$1000.00
Each word in the block is used to obtain its value in the object.
$20.00
If a word is not defined within an object, the in function returns none. This is
useful for detecting when a variable exists within an object.
Object Functions I
An object can contain variables that refer to functions that are defined within the
context of the object. This is useful because the functions are encapsulated within
the context of the object, and can access the other variables of the object directly,
without a need for a path.
As a simple example, the example object can include functions for computing new
values within the object:
Notice in the example that the functions are able to refer to the variables of the
object directly, rather than as paths. That is possible because the functions are
defined within the same context as the variables they access.
example/set-time
This example evaluates the function that sets var3 to the current time.
example/calculate 100
print example/var2
110
In the case of the bank-account object, the functions for deposit and
withdraw can be added to the current definition:
In the example, notice that the functions are able to refer to the balance directly
within the object. That’s because the functions are part of the object’s context.
Now if a new account is made, it will contain functions for depositing and
withdrawing money. For example:
print lily/balance
$1010.00
lily/deposit $100
print lily/balance
$1110.00
lily/withdraw $2000
print lily/balance
-$890.00
lily/withdraw $2.10
Prototype Objects I
Any object can serve as a prototype for making new objects. For instance, the lily
account object previously defined can be used to make new objects with a line such
as:
This makes an instance of an object. The object is a copy of the customer object and
has identical values:
print lily/balance
-$890.00
print maya/balance
-$890.00
You can modify the new object while making it by providing the new values within
the definition block:
print maya/balance
$10000.00
maya/deposit $500
print maya/balance
$10500.00
print maya/first-name
Maya
The lily object serves as a prototype for creating the new object. Any words that
are not redefined for the new object continue to have the values of the old object:
print maya/last-name
Lakeswimmer
Referring to Self I
Every object includes a predefined variable called self. Within the context of an
object, the self variable refers to the object itself. It can be used to pass the object
to other functions or to return it as a result of a function.
example/show
16-Jul-2000/11:08:37-7:00
Another example of using the self variable is a function that clones itself:
print lulu/days-old
7366
Encapsulation I
An object provides a good way to encapsulate a group of variables that should not
appear at the global level. When function variables are defined as globals, they can
unintentionally be modified by other functions.
The solution to this problem of global variables is to wrap an object around both
the variables and the function. When that is done, the function can still access the
variables, but the variables cannot be accessed globally. For example:
last-account: 89431
bank-bonus: $10.00
In this example, the variables are safe from accidental modification. Notice that the
make-account function was set to a variable using the set function, rather than
using a variable definition. This was done to make it a global function. The
function can be used in the same way as functions set with a variable definition,
but does not require an object path:
Reflective Properties I
As with many other REBOL data types, you can access the components of objects
in a manner that allows you to write useful tools and utilities for creating,
monitoring, and debugging them.
The first and second functions allow you to access the components of an object.
The first function returns the words defined for an object. The second function
returns the values that the objects are set to. The following diagram shows the
relationship between the return values of first and second:
first second
first-name "Luke"
account 89431
balance $1204.52
The advantage to using first is that it allows you to obtain a list of the words for the
function without knowing anything else about the function:
In the above example, notice that the list contains the word, self, which is a
reference to the object itself. You can exclude self when getting an object’s word
list by using next:
Now you have a way to write a function that can probe the contents of an object:
probe-object fred
first-name: Luke
last-name: Lakeswimmer
account: 89431
balance: $1204.52
When accessing objects in this fashion, care should be taken to avoid infinite loops.
For instance, if you attempt to probe certain objects that contain references to
themselves, your code may begin an endless loop. This is the reason why you
cannot probe the system object directly. The system object contains many
references to itself.
This chapter describes the operation and evaluation of math functions in REBOL,
as well as a list of valid data types. It includes the following information:
10- 1
Math
Overview
Overview J
The following are a few examples that show a range of math operations over the
scalar data types. Notice that operators produce useful results for each data type.
print 2 + 1
3
print 2 - 1
1
print 2 * 10
20
print 20 / 10
2
print 21 // 10
1
print 2.2 + 1
3.2
print 2.2 - 1
1.2
print 2.2 * 10
22
print 2.2 / 10
0.22
print random 10
5
print 1-Jan-2000 + 1
2-Jan-2000
print 1-Jan-2000 - 1
31-Dec-1999
print 1-Jan-2000 + 31
1-Feb-2000
print 1-Jan-2000 + 366
1-Jan-2001
birthday: 7-Dec-1944
print ["I’ve lived" (now/date - birthday) "days."]
I’ve lived 20305 days.
print random 1-1-2000
29-Apr-1695
print $2.20 + $1
$3.20
print $2.20 + 1
$3.20
print $2.20 + 1.1
$3.30
print $2.20 - $1
$1.20
print $2.20 * 3
$6.60
print $2.20 / 2
$1.10
print $2.20 / $1.10
2
print $2.21 // 2
$0.21
print random $10.00
$6.00
Evaluation Order J
print 1 + 2 * 3
In the example above, notice that the result is not seven, as would be the case if
multiplication took precedence over addition.
If you need to evaluate in some other order, reorder the expression or use
parentheses:
print 2 * 3 + 1
print 1 + (2 * 3)
When functions are mixed with operators, the operators are evaluated first, then the
functions:
In the above example, the addition is performed first, and its result is provided to
the absolute function.
print 10 + sine 30 + 60
11
30 + 60 => 90
sine 90 => 1
10 + 1 => 11
To change the order such that the sine of 30 is done first, use parentheses:
70.5
print 10 + 60 + sine 30
70.5
This section describes the standard math functions and operators used in REBOL.
absolute 0
absolute value
value
10
1.2
$1.20
10:20
10x20
add 0
value1 + value2
Works with integer, decimal, money, time, tuple, pair, date, char data types.
print 1 + 2
4.6
4.6.8
print $1 + $2
$3.00
5:00
40x60
print #"A" + 10
print add 1 2
complement 0
complement value
print complement 10
-11
-11
155.155.155
divide 0
value1 / value2
Works with integer, decimal, money, time, tuple, pair, char data types.
print 10 / 2
print 1.2 / 3
0.4
print 11.22.33 / 10
1.2.3
print $12.34 / 2
$6.17
print 1:20 / 2
0:40
print 10x20 / 2
5x10
print divide 10 2
multiply 0
value1 * value2
Works with integer, decimal, money, time, tuple, pair, char data types.
print 10 * 2
20
4.08
3.8.15
print $10 * 2
$20.00
print 1:20 * 3
4:00
print 10x20 * 3
30x60
print multiply 10 2
20
negate 0
value
negate value
Works with integer, decimal, money, time, pair, char data types.
print - 10
-10
print - 1.2
-1.2
print - $10
-$10.00
print - 1:20
-1:20
print - 10x20
-10x-20
print negate 10
-10
random 0
random value
Note that for integers random begins at 1, not 0, and is inclusive of the value given.
This allows random to be used directly with functions like pick.
When a decimal is used the result is a decimal data type rounded to an integer.
The /seed refinement restarts the random generator. Use the /seed refinement with
random first it if you want unique random number generation. You can use the
current date and time to make the seed more random:
random/seed now
Works with integer, decimal, money, time, tuple, pair, date, char data types.
print random 10
79.95.66
$32.00
6:37:33
2x4
27-Dec-1171
remainder 0
value1 // value2
Works with integer, decimal, money, time, tuple, pair data types.
print 11 // 2
print 11.22.33 // 10
1.2.3
print 11x22 // 2
1x0
print remainder 11 2
subtract 0
value1 - value2
Works with integer, decimal, money, time, tuple, pair, date, char data types.
print 2 - 1
2.2
2.2.2
print $2 - $1
$1.00
2:20
20x20
print #"Z" - 1
print subtract 2 1
Type Conversion J
When math operations are performed between data types, normally the non-integer
or non-decimal data type is returned. When integers are combined with decimals,
a decimal data type is returned.
Comparison Functions J
equal 0
value1 = value2
Works with integer, decimal, money, time, date, tuple, char and series data types.
true
true
true
true
greater 0
Returns true if the first value is greater than the second value.
Works with integer, decimal, money, time, date, tuple, char and series data types.
true
true
true
true
greater-or-equal 0
Returns true if the first value is greater than or equal to the second value.
Works with integer, decimal, money, time, date, tuple, char and series data types.
true
true
true
print greater-or-equal? [b c d e] [a b c d]
true
lesser 0
Works with integer, decimal, money, time, date, tuple, char and series data types:
print 25 < 50
true
true
true
true
lesser-or-equal 0
Returns true if the first value is less than or equal to the second value.
Works with integer, decimal, money, time, date, tuple, char and series data types.
print 25 <= 25
true
true
true
true
not equal to 0
Returns true if the first and second values are not equal.
Works with integer, decimal, money, time, date, tuple, char and series data types.
print 26 <> 25
true
true
true
true
same 0
value1 =? value2
Returns true if two words refer to the same value. For instance, when you want to
see if two words are referencing the same index in a series.
reference-one: "abcdef"
reference-two: reference-one
print same? reference-one reference-two
true
false
true
false
strict-equal 0
value1 == value2
Returns true if the first and second values are strictly the same. Can be used as a
case-sensitive version of the equal? (=) operator for strings and to differentiate
between integers and decimals when their values are the same.
false
true
true
false
true
true
strict-not-equal 0
Returns true if the first and second values are strictly not the same. Can be used
as a case-sensitive version of the not-equal? (<>) operator for strings and to
differentiate between integers and decimals when their values are the same.
true
false
false
true
false
false
Logarithmic Functions J
exp 0
exp value
log-10 0
log-10 value
log-2 0
log-2 value
log-e 0
log-e value
power 0
value1 ** value2
square-root 0
square-root value
Trigonometric Functions J
The trigonometric functions deal in degrees. Use the /radians refinement with any
of the trigonometric functions to operate in and return radians.
arccosine 0
arccosine value
arcsine 0
arcsine value
arctangent 0
arctangent value
cosine 0
cosine value
sine 0
sine value
tangent 0
tangent value
Logic Functions J
Logic functions can be performed on logic values and on some scalar values
including integer, char, tuple, and bitset. When working with logic values, the
logic functions return boolean values. When working with other types of values,
the logic functions on the bits.
and 0
The and function compares two logic values and returns true if they are both
true:
true
false
When used with integers, the and function compares bit for bit and returns 1 if both
bits are 1, or 0 if neither bit is 1:
print 3 and 5
or 0
The or function compares two logic values and returns true if either of them are
true or false or if both are false:
true
true
false
When used with integers, or compares bit for bit and returns 1 if either bit is 1 or
0 if both bits are 0:
print 3 or 5
xor 0
The xor function compares two logic values and returns true if and only if one of
the values is true and the other is false.
false
true
false
When used with integers, xor compares bit for bit and returns 1 if and only if one
bit is 1 and the other 0. Otherwise, it returns 0:
print 3 xor 5
complement 0
false
print complement 3
-4
not 0
For a logic value not returns true if the value is false and false if the value is
true. It does not perform numerical bitwise operations.
false
true
Errors J
1 / 0
An attempt was made to process a number too large for REBOL to handle.
1E+300 + 1E+400
An attempt was made to process a negative number with a math operator that
accepts only positive numbers.
log-10 -1
An attempt was made to process incompatible data types. The data type of the
second argument in the operation is returned as listed.
10:30 + 1.2.3
This chapter explains how to manipulate files and directories in REBOL. It includes
the following information:
11- 1
Files
Overview
Overview K
File Names 0
In scripts, file names and paths are written with a percent sign (%) followed by a
sequence of characters:
%examples.r
%big-image.jpg
%graphics/amiga.jpg
%/c/plug-in/video.r
%//sound/goldfinger.mp3
The percent sign is necessary to prevent file names from being interpreted as words
within the language.
Although it is not a good practice, spaces can be included in file names by enclosing
the file name in double quotes (“ “). The double quotes prevent the file name from
being interpreted as multiple words:
%"this file.txt"
%"cool movie clip.mpg"
The standard Internet convention of using a percent sign (%) and a hex code is also
allowed for character encoding. When this is done, quotes are not required. The
above file names could also be written as:
%this%20file.txt
%cool%20movie%20clip.mpg
Note that the standard file suffix for REBOL scripts is .r. On systems where this
convention collides with another file type, a .reb suffix can be used instead.
Path Strings 0
File paths are written with a percent sign (%) followed by a sequence of directory
names that are each separated by a forward slash (/).
%dir/file.txt
%/file.txt
%dir/
%/dir/
%/dir/subdir/
%../dir/file.txt
The standard character for separating directories is the forward slash (/), not the
backslash (\). If backslashes are found they are converted to forward slashes:
probe %\some\cool\movie.mpg
%/some/cool/movie.mpg
File paths that do not begin with a forward slash (/) are relative paths.
%docs/intro.txt
%docs/new/notes.txt
%"new mail/inbox.mbx"
The standard convention of using double dots (..) to indicate a parent directory or
a single dot (.) to refer to the current directory is also supported. For example:
%.
%./
%./file.txt
%..
%../
%../script.r
%../../plans/schedule.r
File paths use the standard Internet convention of beginning absolute paths with a
forward slash (/). The forward slash indicates to start at the top level of the file
system. (Generally, absolute paths should be avoided to ensure
machine-independent scripts.) The example:
%/home/file.txt
would refer to a disk volume or partition named home. Other examples are:
%/ram/temp/test.r
%/cd0/scripts/test/files.r
To refer to the C volume that is often used by Windows, the notation is:
%/C/docs/file.txt
%"/c/program files/qualcomm/eudora mail/out.mbx"
Notice in the above lines that the disk volume, C, is not written as:
%c:/docs/file.txt
The above example is not a machine independent format and causes an error.
If the first directory name is absent, and the path begins with double forward
slashes (//), then the file path is relative to the current volume:
%//docs/notes
Case Sensitivity 0
In REBOL, file names are not case-sensitive by default. However, when new files
are created by the language, they keep the case they were typed in:
The above example creates the file name with the S and F in uppercase.
In addition, when file names are read from directories, the case is preserved:
For case-sensitive systems, such as UNIX, REBOL finds the closest case match to the
specified file. For example, if a script asks to read %test.r, but only finds
%TEST.r, the %TEST.r file is read. This behavior is necessary to allow
machine-independent scripts.
Various functions are provided to help you create file names and paths. These are
listed below in Table 11-1.
Table 11-1. File Name Functions
Function Description
to-file Converts strings and blocks into a file name or file path.
split-path Splits a path into its directory part and its file name.
clean-path Returns the absolute path that is equivalent to any given path
containing double dot (..) or dot (.).
what-dir Returns the absolute path to the current directory.
Reading Files K
Files are read as a series of text characters or as binary bytes. The source of the file
is either a local file on your system or a file from the network.
The read function returns a string that holds the entire text of the file. In the above
example, the variable text refers to that string.
Within the string returned by read, line terminators are converted to newline
characters, regardless of what style of line termination is used on your operating
system. This allows you to write scripts that search for newline without concern
for what particular character or characters constitute a line termination.
A file can also be read as separate lines that are stored in a block:
See the “Line Conversion” section for more information about newline and
reading lines.
To read a file a piece at a time, use the open function as described in the “Ports”
Chapter.
To view the contents of a text file, you can read it using read and print it using print:
The read/binary function returns a binary series that holds the entire contents of
the file. In the above example, the variable data refers to the binary series. No
conversion of any type is done to the file.
To read a binary file a piece at a time, use the open function as described in the
“Ports” Chapter..
Files can be read from a network. For example, to view a text file from a network
using the HTTP protocol:
Hello
there
new
user!
In the write process the file will have its line termination converted to that which is
used by your operating system.
To read and save a binary file, such as an image, use the following line:
write %image.jpg
read/binary http:/www.rebol.com/image.jpg
Refer to the chapter on “Network Protocols” for more information and examples of
accessing files across networks.
Writing Files K
You can write a file as a series of text characters or as binary bytes. The location of
the file can be either a local file on your system or a file on a network.
If a file contains newline characters, they will be converted to those used by your
local file system. This allows you to deal with files in a consistent manner, but write
them out using the convention that is standard to your file system.
For instance, the following line converts any text file from one line termination
format (UNIX, Macintosh, PC, Amiga) to that which is used by your local system:
The above line reads the entire file while converting its line termination to the
REBOL standard, then writes the file converting it to the local operating system
format.
A file can also be written from separate lines that are stored in a block.
To write a file a piece at a time, use the open function as described in the “Ports”
Chapter.
The write/binary function creates the file if it does not exist or overwrites the file
if it already exists. No conversion of any type is done to the file.
To write a binary file a piece at a time, use the open function as described in the
“Ports” Chapter.
Files can also be written to a network. For example, to write a text file to a network
using FTP, use:
The file can be read locally and written to the net with a line such as:
In the process, the file has its line termination converted to the standard CRLF
format.
To write a binary file, such as an image, to the network, use the following lines of
code:
write/binary ftp://ftp.domain.com/file.txt/image.jpg
read/binary %image.jpg
Refer to the chapter on “Network Protocols” for more information and examples of
accessing files from networks.
Line Conversion K
When a file is read as text, all line terminators are converted to newline (line feed)
characters. Line feeds (used as line terminators on Amiga, Linux, and UNIX
systems), carriage returns (used as line terminators on Macintosh), and the CR/LF
combination (PC and Internet) are all converted to the equivalent newline
characters.
When a file is written, the newline character is converted to the line termination
style standard for the operating system being used. For instance, the newline
character is converted to a CRLF on the PC, LF on UNIX or Amiga, or CR for a
Macintosh. Network files are written with CRLF.
The following function converts any text file with any terminator style to that used
by the local operating system:
The file is read and all line terminators are converted, then the file is written and
newline characters are converted to the local operating system style.
Line conversion can be disabled by reading the file as binary. For instance, the
following line:
Blocks of Lines K
Text files can be easily accessed and managed as individual lines of text, rather than
as a single series of characters. For example, to read a file as a block of lines:
The above example returns a block containing a series of strings (one for each line)
without line terminators. Empty lines are represented by empty strings.
To print all of the lines of a file, use the following line of code:
To print all of the lines that contain the string gold, use the following line of code:
You can write the text file out as lines using the write function:
write/lines %output.txt [
"line one"
"line two"
"line three"
]
In fact, the functions read/lines and write/lines can be combined to process files
one line at a time. For example the following code removes all of the comments from
a REBOL script:
NOTE: The sample script in the previous example is for demonstration purposes
only. In addition to removing comments, the sample script would also remove valid
semicolons in quoted strings.
new
The /lines refinement can be used with the open function to read a line at a time
from console input. See the chapter on “Ports” for more information.
In addition /lines can be used with /append to append lines from a block to a file.
There are a number of functions that provide useful information about a file, such
as whether it exists, its file size in bytes, when it was last modified, and whether it
is a directory.
Directory Check 0
false
print dir? %.
true
true
File Existence 0
File Size 0
To obtain the last modification date of a file, use the modified? function:
30-Jun-2000/14:41:55-7:00
Not all operating systems keep track of the creation date of a file, so to keep REBOL
scripts operating system independent only the last modification date is accessible.
Directory Information 0
The info? function obtains all file directory information at the same time. The
information is returned as an object:
make object! [
size: 306
date: 30-Jun-2000/14:41:55-7:00
type: ’file
]
Directories K
Reading a Directory 0
Directories are read in the same manner as files. The read function returns a block
of file names rather than text or binary data.
To read all the file names from the current directory, use the following line of code:
read %.
The above example reads the entire directory and returns a block of file names.
To print the names of all files in a directory, use the following line of code:
Within the returned block, names of directories are indicated with a trailing forward
slash. To print each file name on a separate line, use:
CVS/
history.t
intro.t
overview.t
quick.t
Here is an easy way to print just the directories that were found:
CVS/
If you want to read a directory from the network, be sure to include a forward slash
at the end of the URL to indicate to the protocol that you are referring to a directory:
Making a Directory 0
The make-dir function makes a new directory. The new name for the directory can
be relative to either the current directory or an absolute path.
make-dir %new-dir
make-dir %local-dir/
make-dir %/work/docs/old-docs/
Internally, the make-dir function calls open with the /new refinement. The line:
also creates a new directory. The trailing slash is important in this example,
indicating that a directory is to be created rather than a file.
If you use the make-dir function to create a directory that already exists, an error
will occur. The error can be caught with the try function. The directory can be
checked in advance with the exists? function.
The old file name may include a complete path to the file, but the new file name
must not include a path. This is because the rename function is not intended to
move files between directories (various operating systems do not provide this
function).
If the old file name is a directory (indicated by a trailing slash), the rename function
renames the directory:
If the file cannot be renamed, an error will occur. The error can be caught with the
try function.
delete %file
delete %source/docs/file.txt
A group of files can be deleted using a wildcard character and the /any refinement:
delete/any %file*
delete/any %secret.?
The asterisk (*) wildcard character matches all characters, and the question mark
(?) wildcard character matches a single character.
delete %dir/
delete %../docs/old/
If the file cannot be deleted, an error will occur. The error can be caught with the
try function.
Current Directory 0
print what-dir
/work/REBOL/
The what-dir function refers to the current script’s directory path, as found in
system/script/path.
change-dir %new-path/to-dir/
list-dir
The number of columns used to show the directory is dependent on the console
window size and the maximum file name length.
12- 1
Network Protocols
Overview
Overview L
REBOL includes several of the primary Internet service protocols built-in. These
protocols are easy to use within your scripts; they require no extra libraries or
include files, and many useful operations can be done with only a single line of
source code.
Protocol Description
In addition, you can create handlers for other Internet protocols or make your own
custom protocols.
Modes of Operation 0
There are two basic modes of network operation: atomic and port-based.
Atomic network operations are those that are accomplished in a single function. For
instance, you can read an entire Web page with a single call to the read function.
There is no need to separately open a connection or set up the read. All of that is
done automatically as part of the read. For example, you can type:
The host is found and opened, its Web page transferred, and the connection closed.
The port-based mode of operation is one that uses a more traditional programming
approach. It involves opening a port and performing various series operations on
the port. For instance, if you want to read your email from a POP server one
message at a time, you would use this method. Here is an example that reads and
displays all of your email:
The atomic method of operation is easier, but it is also more limited. The port-based
method allows more types of operations, but also requires a greater understanding
of networking.
REBOL provides two approaches for specifying network resources: URLs and port
specifications.
Uniform Resource Locators (URL) are used on the Internet to identify a network
resource, such as a Web page, FTP site, email address, file, or other resource or
service. URLs are integral to the operation of REBOL, and they can be expressed
directly in the language.
scheme:specification
The scheme is often the name of a protocol, such as HTTP, FTP, SMTP, and POP;
however, that is not a requirement. A scheme can be any name that identifies the
method used to access a resource.
scheme://host
scheme://host:port
scheme://user@host
scheme://user:pass@host
scheme://user:pass@host:port
scheme://host/path
scheme://host:port/path
scheme://user@host/path
scheme://user:pass@host/path
scheme://user:pass@host:port/path
Field Description
scheme The name used to identify the type of resource, often the same
as the protocol. For example, HTTP, FTP, and POP.
host The network name or address for a machine. For example,
www.rebol.com, cnn.com, accounting.
port Port number on the host machine for the scheme being used.
Normally there is a default for this, so it is not required most of
the time. Examples: 21, 23, 80, 8000.
user A user name to access the resource.
pass A password to verify the user name.
path A file path or some other method for referencing the resource.
This is scheme dependent. Some schemes include patterns and
script arguments (such as CGI).
Another way to identify a resource is with a REBOL port specification. In fact, when
a URL is used, it is automatically converted into a port specification. A port
specification can accept many more arguments than a URL, but it requires multiple
lines to express.
A port specification is written as an object block definition that provides each of the
parameters necessary to access the network resource. For instance, the URL to
access a Web site is:
read http://www.rebol.com/developer.html
read [
scheme: 'HTTP
host: "www.rebol.com"
target: %/developer.html
]
read ftp://bill:[email protected]:8000/file.txt
read [
scheme: 'FTP
host: "ftp.example.com"
port-id: 8000
target: %/file.txt
user: "bill"
pass: "vbs"
]
In addition, there are many other port fields that can be specified, such as timeout,
type of access, and security.
In addition, there are lower level scheme names that are not shown here. For
instance, the TCP and UDP schemes are used for direct, lower level communication.
New schemes can be added to this list. For instance, you can define your own
scheme, called FTP2, that provides special features for FTP access, such as
automatically supplying your username and password so it does not need to be
included in every FTP URL.
Although each protocol is quite different in how it communicates, it does have some
things in common with other protocols. For instance, most protocols require a
network connection to be opened, read, written, and closed. These common
operations are performed by a default handler in REBOL. This handler makes
protocols like finger, whois, and daytime almost trivial to implement.
Scheme handlers are written as objects. The default handler serves as the root
object for all the other handlers. When a handler requires a particular field, such
as a timeout value to use for reading data, if the value is not defined in the specific
handler, it will be provided by the default handler. Hence, handlers overlay one
another with their fields and value. You can also create handlers that use other
handlers for default values. For instance, you can create an FTP2 handler that looks
for missing fields first in the FTP handler, then in the default handler.
The source code to handlers can be obtained from the system/scheme object. This
can be useful if you want to modify the behavior of a handler or build your own
handler. For instance, to view the code for the whois handler, type:
Note that what you are seeing is a composite of the default handler with the whois
handler. The actual source code that is used to create the whois handler is only a
few lines:
make Root-Protocol [
open-check: [[any [port/user ""]] none]
net-utils/net-install Whois make self [] 43
]
Monitoring Handlers
For debugging purposes, you can monitor the actions of any handler. Each handler
has its own debugging output to indicate what operations are being performed. To
enable network debugging, turn network tracing on with the line:
trace/net on
trace/net off
Here is an example:
read pop://carl:[email protected]
Initial Setup L
REBOL networking is built-in. To create scripts that use the network protocols you
do not need any special include files or libraries. The only requirement is that you
provide the basic information necessary to enable protocols to connect to servers or
through firewalls and proxies. For instance, to send an email, the SMTP protocol
needs an SMTP server name and a reply email address.
When you run REBOL the first time, you re prompted for the necessary network
settings, which is stored in the user.r file. REBOL uses this file to load the
required network settings each time it is started. If a user.r is not created and
REBOL cannot find an existing user.r file in its paths, no settings are loaded. See
the chapter on “Operation” for more information.
To change the network settings, type set-user at the prompt. This runs the same
network configuration script that ran when REBOL first started. This script is
loaded from the rebol.r file. If that file cannot be found, or if you want to edit
the setting directly, you can use a text editor on the user.r file.
Within the user.r file the network settings are found in a block that follows the
set-net function. At a minimum the block should contain two items:
■ Your email address for use in the from and reply fields of email and for
anonymous FTP login
You can also add lines after the set-net function to configure other protocol values.
For instance you can set the timeout values for protocols, set the FTP passive mode,
set the HTTP user-agent identifier, set up separate proxies for different protocols,
and more.
The first field specifies your email from address, and the second field indicates your
default server (notice that it does not need quotes here). For most networks, this is
enough and no other settings are necessary (unless you require a proxy). Also your
default server is used whenever a specific server is not provided.
In addition, if you use a POP server (for incoming email) that is different from your
SMTP server (for outgoing email), you can specify that as well:
set-net [
[email protected]
mail.server.dom
pop.server.dom
]
However, if your SMTP and POP servers are the same, then this is not necessary.
Proxy Settings 0
If you use a proxy or firewall, you can provide the set-net function with your proxy
settings. This can include the proxy server name or address, a proxy port number
to access the server, and an optional proxy type. For example:
set-net [
email@addr
mail.example.com
pop.example.com
proxy.example.com
1080
socks
]
This example would use a proxy called proxy.example.com on its TCP port 1080
with the socks proxy method. To use a socks4 proxy server, use the word socks4
rather than socks. To use the generic CERN server, use the word generic.
You can also set the proxy to be different machines for different schemes
(protocols). Each protocol has its own proxy object where you can set the proxy
values for just that scheme. Here is an example of setting a proxy for FTP:
system/schemes/ftp/proxy/host: "proxy2.example.com"
system/schemes/ftp/proxy/port-id: 1080
system/schemes/ftp/proxy/type: 'socks
In this case, only FTP uses a special proxy server. Notice that the machine name
must be a string and the proxy type must be a literal word.
Here are two more examples. The first example sets the proxy for HTTP to be the
generic (CERN) proxy method:
system/schemes/http/proxy/host: "wp.example.com"
system/schemes/http/proxy/port-id: 8080
system/schemes/http/proxy/type: 'generic
If you want to disable the proxy settings for a particular scheme, you can set the
proxy fields to false.
system/schemes/smtp/proxy/host: false
system/schemes/smtp/proxy/port-id: false
system/schemes/smtp/proxy/type: false
In the above example, all outgoing email does not go through a proxy. The false
value prevents even the default proxy from being used. If you set these fields to
none, then the default proxy is used if it is configured.
If you want to bypass the proxy settings for particular machines, such as those on
your local network, you can provide a bypass list. Here is a bypass list for the
default proxy:
system/schemes/default/proxy/bypass:
["host.example.net" "*.example.com"]
Note that the asterisk (*) and question mark (?) characters can be used for pattern
matching. The asterisk (*) as used in the example above bypasses any machine that
ends with example.com.
system/schemes/http/proxy/bypass:
["host.example.net" "*.example.com"]
Other Settings 0
In addition to proxy settings, you can set network timeout values for all of the
schemes (in the default) or for specific schemes. For instance, to increase the
timeout for all schemes, you can write:
system/schemes/default/timeout: 0:05
If you want to increase the timeout just for SMTP, you would write:
system/schemes/smtp/timeout: 0:10
Some schemes have custom fields. For instance, the FTP scheme allows you to set
passive mode for all transfers:
system/schemes/ftp/passive: on
FTP passive mode is useful because FTP servers that are set to passive mode do not
attempt to connect back through your firewall.
When making HTTP accesses to Web sites, you may want to use a different
user-agent field in the HTTP request to get better results on a few sites that detect
the browser type:
system/schemes/http/user-agent: "Mozilla/4.0"
Access to Settings 0
Each time REBOL is started, it reads the user.r file to find its network settings.
These settings are made with the set-net function. Scripts have access to these
settings through the system/schemes object.
Below is a function that returns a block containing the network settings in the same
order as set-net accepts them:
probe get-net
DNS is the network service that translates domain names to their associated IP
address. In addition, you can use DNS to find a machine and domain name from
an IP address.
The DNS protocol can be used in three ways: you can lookup the primary IP
address of a machine name, you can lookup the domain name for an IP address,
and you can find the name and IP address of your local system.
207.69.132.8
You can also obtain the domain name that is associated with a particular IP address:
rebol.com
Note that it is not unusual for this reverse DNS lookup to return a none. There are
machines that do not have host names.
none
To find your system’s host name, read an empty DNS URL of the form:
crackerjack
The data returned here depends on the type of machine. It may be the unqualified
host name, as shown above, but it can also be the fully-qualified host name,
crackerjack.example.com. This depends on the operating system and the
network configuration in the operating system.
Here’s an example that looks up and prints the IP addresses for a number of Web
sites:
domains: [
www.rebol.com
www.rebol.org
www.mochinet.com
www.sirius.com
]
Whois Protocol L
The whois protocol retrieves information about domain names from a central
registry. The whois service is provided by the organizations that run the Internet.
Whois is often used to retrieve registration information about an Internet domain
or server. It can tell you who owns the domain, how their technical contact can be
reached, along with other information.
To obtain information, use the read function with a whois URL. This URL should
contain the domain name and a whois server name separated by an at sign (@).
For example to obtain information about example.com from the Internic registry:
Domain names in the .com, .net, and .org domains can now
be registered with many different competing registrars. Go
to http://www.internic.net for detailed information.
NOTE: The above code is only an example. The details of the information being
returned and the servers that support whois change over time.
If instead of a domain name you provide a word, all entries that match that word
are returned:
Domain names in the .com, .net, and .org domains can now
be registered with many different competing registrars. Go
to http://www.internic.net for detailed information.
EXAMPLE.512BIT.ORG
EXAMPLE.ORG
EXAMPLE.NET
EXAMPLE.EDU
EXAMPLE.COM
NOTE: The whois protocol does not accept URLs, such as www.example.com,
unless the URL is part of the registrant’s company name.
Finger Protocol L
The finger protocol retrieves user-specific information stored in the user log file.
To request user information from a server it must be running the finger protocol.
The information is requested by reading a finger URL that contains a username and
a domain name in an email style format:
Notice that finger reports when the user last logged in from a machine, and whether
the user has mail waiting. If the user reads email from this account, finger
sometimes reports when mail was received and when the user last retrieved email:
The finger server can also report the contents of a plan file and a project file if
they exist. Users can include any information they want in a plan or project file.
It is also possible to retrieve information about users using their real first name or
their last name. Some finger servers require that you capitalize the names exactly
as they appear in the login file or in the file used by the online finger server, to
retrieve user information. Other finger servers are more liberal about capitalization.
A finger server will respond to real name queries by returning all listings that match
the query criteria. For instance, if there are several users on a host that have the first
name zaphod, then entering the query
will retrieve all such users whose first or last name is Zaphod.
Some finger servers return a listing of users when the user name is omitted. For
example,
retrieves a list of all users who are logged onto the machine, if the finger service
installed on the hosting machine allows it.
Some host machines limit finger services for security reasons. They may require a
valid username and only return information regarding that user. If you finger such
a server without providing user information, the server will report that it requires
specific user information.
If a system does not support the finger protocol, REBOL reports an access error:
The daytime protocol retrieves the current day and time. To connect to a daytime
server use read with a daytime URL. The URL contains the name of the server to
read the date from:
The format of the information returned by servers may vary, depending on the
server. Notice that the time zone may not be present.
If the server you choose does not support daytime, REBOL returns an error:
The world wide Web is driven by two fundamental technologies: HTTP and HTML.
HTTP is the Hypertext Transfer Protocol that controls how Web servers and Web
browsers communicate with each other. HTML is the Hypertext Markup Language
that defines the structure and contents of a Web page.
To retrieve a Web page, the browser sends a request to a Web server using HTTP.
On receiving the request, the server interprets it, sometimes using a CGI script (see
“CGI - Common Gateway Interface” on page 12-49), and sends back data. This data
can be just about anything, including HTML, text, images, programs, and sound.
To read a Web page, use the read function with an HTTP URL. For example:
This returns the Web page for www.rebol.com. Note that a string that contains
the HTML code for the page is returned by the read. No graphics or other
information are fetched. To do so you would need to provide additional reads. The
page can be displayed as HTML code using print, it can be written to a file with
write, or it can be sent as email using send.
print page
For instance, to search a Web page for all occurrences of the word REBOL, you can
write:
A Web server can provide more than just HTML scripts. Web servers are quite
useful for supplying REBOL scripts as well.
You can load REBOL scripts directly from a Web server with load:
You can also evaluate scripts directly from a server with do:
data: do http://www.rebol.com/code.r
NOTE: Do this with care. Evaluating arbitrary scripts on open Internet servers is
asking for trouble. Evaluate a script only if you completely trust its source, have
fully inspected its source, or have kept your REBOL security settings on maximum.
In addition, Web pages that contain HTML can contain embedded REBOL scripts,
and they can be run with:
data: do http://www.rebol.com/example.html
To determine if a script exists on a page before evaluating it, use the script?
function.
NOTE: The script? function reads the page from the Web site and returns the page at
its REBOL header position.
HTML and XML pages can be quickly converted to a REBOL block with the
load/markup function. This function returns a block that consists of all the tags
and strings found within the page. All spacing and line breaks are left intact.
To filter out all of the tags for a Web page and just print its text, type:
print text
You could then search this text for string patterns. It will contain all of the spaces
and line breaks of the original HTML file.
Here’s another example that checks all links found on a Web page to make sure that
the pages they reference exist:
REBOL []
page: http://www.rebol.com/developer.html
set [path target] split-path page
system/options/quiet: true ; turn off connection msgs
tag-text: load/markup page
links: make block! 100
print links
Other Functions 0
To check if a Web page exists, use the exists? function, which returns true if the
page exists.
if exists? http://www.rebol.com [
print "page still there"
]
Note: It is usually faster to just read the page rather than checking first to see if it
exists. Otherwise the script must contact the server twice, and that can be time
consuming.
To request the date on which a Web page was last modified, use the modified?
function:
However, note that not all Web servers provide modification date information.
Dynamically generated Web pages typically do not return a modification date.
Another way to determine if a Web page has changed is poll it every so often and
check it. A handy way to verify that a Web page has changed is by using the
checksum function. If the previously calculated checksum of a Web page differs
from its current value, then the Web page has been modified since it was last
checked. Here is an example that uses this technique. It checks a page every eight
hours.
forever [
page: read http://www.rebol.com
page-sum: checksum page
if any [
not exists? %page-sum
page-sum <> (load %page-sum)
][
print ["Page changed" now]
save %page-sum page-sum
send [email protected] page
]
wait 8:00
]
Normally, REBOL identifies itself to a server when it reads from a Web site.
However, some servers are programmed to respond to particular browsers only. If
a request to a server does not produce the correct Web page, you can change the
request to make it look like it came from some other type of Web browser.
Pretending to be a Web browser is done by many programs to get Web sites to
respond correctly. However, this practice does end up defeating the purpose behind
the browser identification.
To change HTTP requests to look as though they are being sent by Netscape 4.0,
you can modify the user-agent within the HTTP handler:
system/options/http/user-agent: "Mozilla/4.0"
HTTP CGI requests can be posted in two ways. You can include the CGI request
data in the URL or you can provide the request data through an HTTP post
operation.
The URL CGI request uses a normal URL. The example below sends the CGI script
test.r the data value of 10.
read http://www.example.com/cgi-bin/test.r?data=10
The post CGI request requires that you supply the CGI data as part of a custom
refinement to the read function. The example below shows how data is posted to
CGI:
read/custom http://www.example.com/cgi-bin/test.r [
post "data: 10"
]
The post method is useful for easily sending REBOL code and data to a web server
that runs CGI. The following example illustrates this:
The mold function will produce the proper REBOL string to be sent to the server.
The Simple Mail Transport Protocol (SMTP) controls the transfer of email messages
on the Internet. SMTP defines the interaction between Internet hosts that
participate in forwarding email from a sender to its destination.
Sending Email 0
Email is sent through SMTP by using the send function. This function can send an
email message to one or more email addresses.
For send to operate correctly, your networking must be set up. The send function
requires that you specify your email From address and your default email server.
See “Initial Setup” on page 12-9 above.
The send function takes two arguments: an email address and a message. For
example:
The first argument must be an email or block data type. The second argument can
be any data type.
Each of these simple email messages can be interpreted on the receiver's side (with
REBOL) or viewed with a normal email program.
You can send an entire file by reading the file and passing it as the second argument
to the send function:
When the message is received, the file can be extracted by using the do function.
Multiple Recipients 0
In this case, each message is individually addressed with only the recipient's email
name appearing in the To field (similar to BCC addressing).
The block of email addresses can be any size or even a file that you load. Just be
sure that they are valid addresses, not strings. Strings are ignored.
friends: [
[email protected]
[email protected]
[email protected]
[email protected]
...
]
Bulk Mail 0
If you are sending email to a large group, you can reduce the load on your server
by delivering everyone in the group a single message. This is the purpose of the
/only refinement. It uses a feature of SMTP to send only one message to multiple
email addresses. Using the friends list from the previous example:
The messages are not individually addressed. You may have seen this mode in some
of the bulk email that you receive. When you receive bulk email, your address does
not appear in the To field.
NOTE: The bulk email mode of SMTP should be used for email lists and not for
sending spam. Spam email is not proper network etiquette, it is illegal in some
countries and states, and spam will get you banned from your ISP and from other
sites.
By default the send function uses the first line of a message as the subject line. To
provide your own subject line, you need to supply an email header to the send
function. In addition to a subject line, you can provide an organization, date, CC,
and even your own custom fields.
To include a header, use the /header refinement of the send function and include
a header object. The header object must be made from the
system/standard/email object. For example:
Notice that the standard fields, such as the From address, are not required and are
supplied automatically by the send function.
The email above is sent using the custom header for each message.
When testing email scripts, it is advised that you send email to yourself first, before
sending it to others. Examine your test email carefully to make sure that it is what
you want. It is common to have errors such as sending a file name rather than the
file contents. For instance, you might write:
This sends the name of the file, not the file itself.
The Post Office Protocol (POP) allows you to fetch email that is waiting in a mail
server mailbox. POP defines a number of operations for how to access and store
email on your server.
Reading Email 0
You can read all of your email in a single line without removing it from the email
server: This is done by reading from a POP URL in which you provided your
username, password, and email host.
The messages are returned as a block of strings which you can handle one message
at a time using code such as:
To read individual email messages from the server, you need to open a port
connection to the server and handle each message one at a time. To open the POP
port:
To determine the number of mail messages residing on the server, use the length?
function.
37
In addition, you can find out the total size of all messages and the individual sizes
of messages with:
print mailbox/locals/total-size
print mailbox/locals/sizes
To display the first, second, and last messages, you can write:
You can fetch and display each message from the oldest to the newest using a loop
that is identical to that used for other types of series:
You can also read your email from newest to oldest with a loop such as:
When you are done, be sure to close the mailbox. This can be done with a line such
as:
close mailbox
Removing Email 0
As with series, the remove function can be used to delete a single message, and the
clear function can be used to delete all of the messages from the current position
to the end of the mailbox.
For example, to read a message, save it to a file, and remove it from the server:
The message is removed from the server when the close is done.
To remove the 22nd email message from the server, you can write:
user:[email protected]
remove at mailbox 22
close mailbox
You can remove a number of messages by using the /part refinement with the
remove function:
remove/part mailbox 5
To remove all of the messages in your mailbox, use the clear function:
The clear function can also be used at different positions within the mailbox to
remove messages to the end of the mailbox.
Email messages always include a header. The header holds information such as the
sender, recipient, subject, date, and other fields.
In REBOL email headers are handled as objects that contain all of the necessary
fields. To convert email message to a header object you can use the import-email
function. For example:
You can easily write a filter that scans your email for messages that begin with a
particular subject line:
close mailbox
Here is another example that informs you when email is received from a group of
friends:
]
]
This spam filter removes all messages from the server that do not contain your
email name anywhere within the message:
close mailbox
Here is a simple email list server that receives messages and sends them to a group.
The server only accepts email from people in the group.
close mailbox
The File Transfer Protocol (FTP) is used widely on the Internet for transferring files
to and from a remote host. FTP is commonly used for uploading pages to a Web
site and for providing online file archives.
Using FTP 0
In REBOL FTP file operations are handled in much the same way as local file
operations. Functions such as read, write, load, save, do, open, close, exists?,
size?, modified?, and others are used with FTP. REBOL distinguishes between local
files and files accessible by FTP through the use of an FTP URL.
Access to FTP servers can be open or closed. Open access allows anyone to login
to the site and download files. This is called anonymous access and it is used
frequently for public file archives. Closed access requires that you provide a
username and password to download and upload files. This is the mode of
operation for uploading Web pages to a Web site.
Although FTP does not require your REBOL networking to be configured, if you
wish to use anonymous access, an email address is required. This address is found
in the system/user/email object. Normally, when you boot REBOL, this field
is set from your user.r file. See “Initial Setup” on page 12-9 for more detail.
If you are using FTP through a proxy server or firewall, FTP may need to operate in
passive mode. Passive mode does not require reverse connections from the FTP
server to the client for data transfers. This mode only makes outgoing connections
from your machine and allows a greater level of security. To enable passive mode
you need to set a flag in the FTP protocol handler:
system/schemes/ftp/passive: true
If you do not know if it is necessary, try FTP first without it. If that does not work,
try setting the passive flag.
FTP URLs 0
ftp://user:pass@host/directory/file
For anonymous access the username and password can be left out:
ftp://host/directory/file
Most of the examples in this section use this form for simplicity; however, they also
work with a username and password.
To access a remote directory, end the URL with a slash, such as:
ftp://user:pass@host/directory/
ftp://host/directory/
ftp://host/
It is convenient to put the URL in a variable and use paths to provide the file names.
This allows you to refer to the URL with just a word. For example:
site: ftp://ftp.rebol.com/pub/
read site/readme.txt
FTP distinguishes between text files and binary files. When transferring text files,
FTP converts the line break characters. This is not desirable for binary files.
To read a text file, supply the read function with an FTP URL:
This puts the contents of the file into a string. To write the file locally, use this line:
Many of the refinements of read can also be used. For instance, you can use
read/lines with:
This example returns a block of lines for the file. See the “Files” chapter for more
information about the refinements to the read function.
The write function can also include refinements. See the “Files” chapter.
As with normal text file transfers, all line termination will be properly converted
during FTP transfers.
site: ftp://wwwuser:[email protected]/pages
This should not be used for transferring graphics or sound files, as they are binary.
Use the technique shown in “Transferring Binary Files” on page 12-39.
In addition to the read and write functions, you can use the load, save, and do
functions with FTP.
do ftp://ftp.site.com/scripts/test.r
To avoid the line termination conversion when transferring binary files (images,
archives, executable files), use the /binary refinement. For instance, to read a
binary file from an FTP server:
site: ftp://user:[email protected]/www/graphics
Appending to Files 0
FTP also allows you to append text and data to an existing file. To do so, use the
write/append refinement as described in the “Files” chapter.
write/binary/append ftp://ftp.site.com/pub/log.txt
read/binary %datafile
Reading Directories 0
To read the file names of an FTP directory, follow the directory name with a forward
slash:
The ending forward slash (/) indicates that this is a directory access not a file
access. The forward slash is not always required, but it is recommended when you
know you are accessing a directory.
The block of files that is returned includes all of the files in the directory. Within
that block, directory names are indicated with a forward slash following their
names. For example:
readme.txt
rebol.r
rebol.exe
library/
docs/
You can also use the dir? function on a file to determine if it is a directory.
File Information 0
The same functions that provide information about files also provide information
about FTP files. This includes the modified?, size?, exists?, dir?, and info?
functions.
if exists? ftp://ftp.site.com/pub/log.txt [
print "Log file is there"
]
This works for directories too, but include the forward slash at the end of the
directory name:
if exists? ftp://ftp.site.com/pub/rebol/ [
print read ftp://ftp.site.com/pub/rebol/
]
if dir? ftp://ftp.site.com/pub/text [
print "It's a directory"
]
You can obtain all this information in a single access by using the info? function:
probe file-info
print file-info/size
forall files [
file: first files
info: info? file
print [file info/date info/size info/type]
]
Making Directories 0
make-dir ftp://user:[email protected]/newdir/
Deleting Files 0
With appropriate permission settings, files can be deleted from a remote FTP server
by using the delete function:
delete ftp://user:[email protected]/upload.txt
delete ftp://user:[email protected]/newdir/
Renaming Files 0
To rename a directory on an FTP site be sure to follow the directory name with a
slash:
About Passwords 0
The above examples include the password within their URLs, but if you plan on
sharing your script, you probably don't want that information to be known. Here's
a simple way to prompt for a password and build the correct URL:
Or, you can ask for both the username and password:
You can also open FTP connections by using a port specification rather than a URL.
This allows you to use any password, even ones containing special characters that
are not easily written in URLs. An example of a port specification to open an FTP
connection is:
ftp-port: open [
scheme: ‘ftp
host: "ftp.site.com"
user: ask "Username? "
pass: ask "Password? "
]
See “Specifying Network Resources” on page 12-4 above for more detail.
Transferring large files requires special considerations. You may want to transfer
the file in chunks to reduce the memory required by your computer and to provide
user feedback while the transfer is happening.
Be sure to use the /direct refinement, otherwise the entire file will be buffered
internally by REBOL. The read-io and write-io functions allow reuse of the buffer
memory that has already allocated. Other functions such as copy would allocate
additional memory.
If the transfer fails, you can restart FTP from where it left off. To do so, examine
the output file or the size variable to determine where to restart the transfer. Open
the file again with a custom refinement that specifies restart and the location from
which to start the read. Here is an example of the open function to use when the
total variable indicates the length already read:
inp: open/binary/direct/custom
ftp://ftp.site.com/big-file.bmp
reduce ['restart total]
You should note that restart only works for binary transfers. It cannot be used with
text transfers because the line terminator conversion that takes place will cause
incorrect offsets.
The Network News Transfer Protocol (NNTP) is the basis for tens of thousands of
newsgroups that provide a public forum for millions of Internet users. REBOL
includes two levels of support for NNTP.
The built-in support for NNTP that provides very limited functionality and access.
This is the NTTP scheme.
To retrieve the list of all newsgroups from a specific news server, use the read
function with an NNTP URL such as:
This may take a while, depending on your connection; there are thousands of
newsgroups.
If you are using a fast connection, you can read all of the pending messages for a
newsgroup with:
To read single messages, open NNTP as a port and use series functions to access
messages. This is similar to how you read email from a POP port. For example:
You can use the length? function to determine the number of messages that are
available in the newsgroup:
To create a simple loop that scans all messages for a keyword, use:
forall group [
if find msg: first first group "REBOL" [
print msg
]
]
Remember that when the loop returns, the group series is positioned to the tail. If
you need to return to the head of the group:
close group
News messages always include a header. The header holds information such as the
sender, summary, keywords, subject, date, and other fields.
Headers are handled as objects. To convert a news message to a news header object
you can use the import-email function. For example:
Different newsgroups and newsgroup clients use different fields in their header. To
view the fields available for a specific message display the first item of the header
object:
Before you can send a news message, you need to create a header for it. Here is a
generic header that can be used for news:
Before you can send it, you need to create a unique global identification number for
it. Here is a function that does that:
make-id: does [
rejoin [
"<"
system/user/email/user
"."
checksum form now
"."
random 999999
"@"
read dns://
">"
]
]
Now you can combine the header with the message. They must be separated by at
least one blank line. The content of the message is read from a file.
NOTE: Keep in mind that whenever you post to newsgroups you may get spammed
by news crawlers that use newsgroups as a source for valid email addresses.
The common gateway interface is used with many Web servers to provide
processing beyond the normal HTTP Web interface. CGI requests are submitted
from Web browsers to Web servers. When a server receives a CGI request, it
typically executes a script to process the request and return a result to the browser.
These CGI scripts can be written in a variety of languages, and REBOL provides one
of the easier ways of handling CGI.
Setting up CGI access is different for every Web server. See the instructions
provided with your server.
Typically a server has an option for enabling CGI operation. You need to enable this
option and provide a path to the directory where your CGI scripts reside. A common
directory for CGI scripts is in cgi-bin.
On Apache servers, the ExecCGI option enables CGI scripts, and you can provide
a directory (cgi-bin) for your scripts. This is normally set up by default
installation of Apache.
To configure CGI for Microsoft IIS, go to the properties for cgi-bin and click on the
configuration button. On the configuration panel click add and enter the path to
your rebol.exe file. The format for this is:
C:\rebol\rebol.exe -cs %s %s
The two %s symbols are required for correctly passing the script and command line
arguments to REBOL. Add the extension for REBOL files (.r) and set the last field
to PUT, DELETE. The script engine does not need to be selected.
The –cs option that is provided to REBOL enables CGI operation and allows the
script to access all files. (!!See notes below on how scripts can limit file access to
selected directories).
With Web servers other than those described above, the server requires
configuration to execute the REBOL executable for .r extension files and run
REBOL with the required option -cs.
CGI Scripts 0
Before a script can be executed on most CGI servers, it needs to have the correct file
permissions. On UNIX-type systems or those that use the Apache server you need
to change the permissions to enable the script to be readable and executable by all
users. This can be done with the chmod function. If you are new to this concept,
you should read your operating system manual or talk with your system
administrator before changing file permissions.
For Apache and various other Web servers to run REBOL scripts, you need to
provide the correct header at the top of each script file. The header specifies the
path to the REBOL executable file and the -cs option. This can be followed by the
normal REBOL script header. Here is a simple CGI script that prints the string,
hello!.
#!/path/to/rebol -cs
print "Hello!"
There are many things that prevent a CGI script from running correctly. Get this
simple script working first before you try more complex scripts. If your script does
not work, here are a few items to check:
The first line begins with a #! and the correct path to REBOL.
The script has the correct file permissions (readable and executable by all).
The script contains the correct line break characters. Some servers do not run
scripts that contain the CR character for line breaks. You may need to convert the
file. (Use REBOL to do this in one line: write file, read file).
The script does not contain errors. Test it without CGI to make sure that the script
loads (does not have syntax errors) and functions properly. Provide some sample
data and test it.
All files that are accessed by the script have the correct file permissions.
Often one or more of the above items is wrong and prevent your script from
running. You may see an error when viewing the Web page. If it says “Server Error”
or “CGI Error” then it is typically something to do with the permissions or setup of
the script. If it shows a REBOL error message, then the script is running, but you
have an error within the script.
In the example script shown above, the Content-Type line is critical. It is part of
the HTTP header that is returned to the browser, and it tells the browser the type of
content being delivered. This is followed by a blank line to separate it from the
actual content.
Many different types of content can be delivered. The previous example was plain
text, but you can also deliver HTML as is shown in the next example. (See your
Web server manual for more information about content types.)
The content type and blank line can be combined into a single line. The caret
forward slash (^/) symbol provides an additional line break to separate it from the
content.
It is a good practice to always print this line immediately from your script. This
allows error messages to be seen by the browser if your script encounters an error.
#!/path/to/rebol -cs
There are as many ways to create HTML content as there are ways to create strings.
This page creates a page that displays a page hit counter:
#!/path/to/rebol -cs
print [
{<HTML><BODY><H2>Web Counter Page</H2>
You are visitor} count {to this page!<P>
</BODY></HTML>}
]
The script in the example above loads and saves to a counter text file. For this file
to be accessible, it will require the appropriate permissions be set to allow access
by all users.
CGI Environment 0
When a CGI script is run the server provides information to REBOL about the CGI
request and its arguments. All of this information is provided as an object within
the system/options object. To view the fields of the object, type:
probe system/options/cgi
make object! [
server-software: none
server-name: none
gateway-interface: none
server-protocol: none
server-port: none
request-method: none
path-info: none
path-translated: none
script-name: none
query-string: none
remote-host: none
remote-addr: none
auth-type: none
remote-user: none
remote-ident: none
Content-Type: none
content-length: none
other-headers: []
]
Of course, your script will ignore most of this information, but some of it could be
of use. For instance, you may want to create a log file that records the network
address of the system that made the request, or check the type of browser being
used.
#!/path/to/rebol -cs
probe system/options/cgi
If you want to use this information in a log, you can write it to a file. For example,
to log the addresses of visitors to your CGI page you could write:
write/append/lines %cgi.log
system/options/cgi/remote-addr
The /append and /lines refinements causes the write to be at the tail of the file and
include a line-break. Here’s another approach that puts multiple items on the same
line:
CGI Requests 0
There are two methods for CGI to provide request data to your scripts: GET and
POST.
The GET method encodes CGI data into the URL. This is used to provide
information to the server. You may have noticed before that some URLs look like
this:
http://www.example.com/cgi-bin/test.r?&data=test
The string that follows the question mark (?) provides the arguments to CGI. At
times they can be quite long. This string is provided to your script when it is run.
It can be obtained from the cgi/query-string field. For instance, to print the
string from a script:
print system/options/cgi/query-string
The data within the string can include whatever data you require. However,
because the string is part of a URL, data must be encoded. There are restrictions
on the characters that are allowed.
The POST method provides the CGI data as a string. The data does not need to be
encoded. It can be in any format you desire and can even be binary. Post data is
read from the standard input device. You will need to read it from the input with a
line such as:
This would read up to the first 2000 bytes of POST data and put it in a string.
A good format for POST data is to use a REBOL dialect and create a simple parser.
The POST data can be loaded and parsed as a block. See the “Parsing” chapter.
WARNING: It is not a good idea to pass REBOL blocks that are directly evaluated
because this can present a security risk. For instance, someone could POST a block
that reads or deletes your files.
Here is an example script that displays the post data in your browser:
#!/path/to/rebol -cs
print [
<HTML><BODY>
{Here is the posted data.}
<HR><PRE>data</PRE>
</BODY></HTML>
]
CGI is often used for processing HTML forms. The forms accept input from various
fields and submit them to the Web server as an HTML get or post method.
Here is an example that uses the CGI get to process a form and send an email as the
result. There are two parts to this: the HTML page and the CGI script.
<HTML><BODY>
<FORM ACTION="http://example.com/cgi-bin/send.r"
METHOD="GET">
<H1>CGI Emailer</H1><HR>
</FORM>
</BODY></HTML>
When the above script is submitted, it needs a CGI script to handle its results. Here
is an example of such a script. This example script decodes the form data and sends
the email. It returns a confirmation page.
#!/path/to/rebol -cs
print {</BODY><HTML>}
This script should be named send.r and stored in the cgi-bin directory. It’s
permissions must be set to being readable and executable by all.
When the form has been submitted by a browser, this script will run. It decodes
the CGI query string into a cgi object. The object now has email and message
variables that are used for the send function. Before send is done, the email field
is converted from a string to an email datatype.
The send function is placed within a try block to catch errors if they occur while
sending the email. The failed variable is set to true if an error occurred, and the
appropriate message is generated.
In addition to those protocols previously described, you can create your own
network servers and clients with the transmission control protocol, TCP.
Creating Clients 0
TCP ports can be opened in the same way as other REBOL protocols, using the TCP
URL. To open a TCP connection to an HTTP (Web) server on TCP port number 80:
http-port: open [
scheme: 'tcp
host: "www.example.com"
port-id: 80
Since ports are series, you can use the same series functions for sending and
receiving data. The example below queries the HTTP server opened in the previous
example. It uses the insert function to put data into the port series which sends it
to the server:
The two newline characters are used to tell the sever that the header has been sent.
The server processes the HTTP request and returns a result to the port series. To
read the result, use the copy function:
This loop will continue to fetch data until a none is returned from copy. This
behavior differs between protocols. A none is returned because the server closes
the connection. Other protocols may send a special character to indicate the end of
the transfer.
Now that all the data has been received, HTTP port should be closed:
close http-port
This example uses the /lines refinement. The connection will now be line oriented.
Data will be written and read as lines. To read the first line from the server:
Because the port is operating in line mode, a line terminator is sent after the insert.
The server response can be read with with:
first pop
close pop
Creating Servers 0
To create a server you need to wait for connections and respond to them as they
occur. To set up a port on your machine that can be used to wait for incoming
connections:
Notice that you do not supply a host name, only a port number. This type of port is
called a listen port. The system now accepts connections on port number 8001.
To wait for a connection from another machine, you wait on the listen port.
wait listen
This function does not return until a connection has been made.
NOTE: There are other options available for wait. For instance, you can wait on
multiple ports or for a timeout as well.
You can now open the connection port from the machine that has contacted your
system:
This returns the connection that has been made to the listen port. It is a port like
all others and can now be used to receive and send data using the insert, copy, first,
and other series functions:
close connection
You are now ready for the next connection on the listen port. You can wait again
and use first again to get the connection.
When you are done with serving, you can close the listen port with:
close listen
A Tiny Server 0
Here is a useful REBOL server that only requires a few lines of code. This server
evaluates whatever REBOL code is sent to it. Lines of REBOL are read from the
client until an error occurs. Each line must be a complete REBOL expression. They
can be of any length but must be a single line.
forever [
connection-port: first server-port
until [
wait connection-port
error? try [do first connection-port]
]
close connection-port
]
close server-port
If an error occurs, the connection is closed and the server waits for the next
connection.
Here is an example of a client script that allows you to enter REBOL command lines
remotely:
Here the query is used to determine if the connection was been closed due to an
error.
To test your server code, connect from your own machine, rather than requiring
both a server and a client. This can be done from two separate REBOL processes
or even from the same process.
To connect to your local machine, you can use a line such as:
Here is an example that makes two ports connect to each other in line mode. This
is a sort of echo port since you're sending data to yourself. It provides a good test of
your code and networking:
The User Datagram Protocol is another transport layer protocol that provides a
connectionless method of communicating between machines. It allows you to send
datagrams, packets, between machines.
The operation of UDP is much different than TCP. UDP is simpler, but it is
essentially unreliable. There is no guarantee that a packet will ever reach its
destination. In addition, UDP has no flow control. If you send messages too
quickly, packets may be lost.
Like TCP, the wait function can be used to wait for the next packet to arrive and the
copy function is used to return the data. If there is no data, copy waits until there
is. Note, however, that insert never waits.
The messages inserted here by the server are sent to the client the server last
received a message from. This allows responses to be sent for incoming messages.
However, unlike TCP you do not have a continuous connection between the
machines. Each packet transfer is a separate exchange.
The client script to communicate with the above server would be:
You should know that the maximum UDP packet size depends on the operating
system. 32 KB and 64 KB are common values. In order to send larger amounts of
data, you will need to buffer the data, chopping it into smaller pieces. However,
careful programming is required to make sure that each piece of the data is received.
Remember that with UDP, there are no guarantees.
This chapter explains the types of ports and how they are manipulated within
REBOL/Core. It includes the following information:
13- 1
Ports
Overview
Overview M
Ports access external series such as files, networks, consoles, events, databases, data
encoders, and data decoders. Port data is processed using the standard REBOL
series functions as described in the “Series” chapter.
Ports are used for both input and output. The type of data a port handles depends
on how the port is opened. Three types of data are possible:
Table 13-1. Port Data Types
Opening a Port M
The open function initializes access to a port according to specified parameters. The
function can be supplied with a filename, a URL, or an object. In addition, there
are several refinements that will affect the open operation or the access to the port’s
data.
The simplest method of using open is to provide it with a filename or URL as its
argument. In the example below, a file port is opened:
The fp variable refers to the port. If the port did not open, an error will occur.
If necessary, the error can be caught with the try function.
By default the file is opened as buffered. This means that the file is accessed and
modified in memory and changes to the file are not written out until the port is
closed or updated.
For files, the open function will automatically create the file if it does not already
exist.
somefile exists
new data
Once a port is open, the series operations such as copy, insert, remove, clear, first,
next, and length? can be used to access and change the contents the port.
Open Refinements 0
The open function accepts a number of refinements that can be used to modify its
operation:
Table 13-4. Open Refinements
Refinement Description
Closing a Port M
Access to a port is terminated with the close function. All buffered data that has
not been saved will be written to the target file. The example below will close a
port opened earlier:
close fp
If you attempt to close a port that is not open, an error will occur.
A port that is closed can be reopened again with the open function:
open fp
The series copy function is used to read data from an open port:
print copy fp
This function will wait for the port data. If you don’t want to wait for the data, open
the port with the /nowait refinement.
print copy/part fp 35
Note that the second argument to copy can be a length or a position within the port.
You can use the series find and copy functions to read just part of the port’s data:
a: find fp "famine"
print copy/part a find a newline
The first, next, and other positional series functions can also be used on the port:
print first fp
The copy function will return none when all data have been read from a port.
When running in /nowait mode, the copy function will return an empty string if no
data is available for the port.
Writing to a Port M
If the port is buffered, the change will occur externally when the port is closed or
updated (with the update function). If the port is opened with /direct, then the
change will occur immediately.
All of the insert refinements can be used on the port. For example, to write 20
spaces into a port:
You can also use the remove, clear, change, append, replace, and other series
modifying functions on the port.
remove fp
remove/part fp 20
clear fp
Updating a Port M
The update function forces a port to update its status with respect to the external
device. For example, when writing a buffered file, the update function can be used
to force the data buffer out to the file. When reading, the update function can be
used to be certain that any pending data has been read into memory.
update fp
The wait function is essential to programs that need to handle asynchronous data
transfers. With wait, you can wait for data on one or more ports, or for a timeout
to occur.
wait port
The first example will time out in ten seconds. The second example will timeout in
five minutes.
The wait function will return the port that is ready or none if the timeout occurred.
The above example will read data from the first ready port if a timeout did not occur.
To obtain a block of all ports that are ready, use the /all refinement.
This example would append data from all ready ports into a single series.
You can also use the dispatch function to evaluate a block or function based on the
results of a wait on multiple ports.
dispatch [
port1 [print "port1 awake"]
port2 [print "port2 awake"]
10 [print "timeout!"]
]
NOTE: To use wait with most ports, you will need to specify the /nowait and /direct
refinements as part of the open. This indicates that the normal data access
functions should not block and that data is not buffered.
Line Mode 0
The open function allows ports to be opened for line access. In line mode, the first
function will return a line of text, rather than a character. The example below reads
a file one line at a time:
print third fp
The /lines refinement is also useful for Internet protocols that are line oriented.
You can use the /read refinement to open a port as read only:
Changes made to the port’s buffer, are not written back to the file.
File ports opened with the /write refinement will not read the current data upon
opening the port.
Closing, or updating a write only file port will cause existing data in the file to be
overwritten:
The /direct refinement opens an unbuffered port. This is useful to access files a
portion at a time, such as when a file is too large to be held in memory.
Reading the data with a copy function will move the port’s head forward:
print copy/part fp 40
print copy/part fp 40
print head? fp
true
The copy function will return none when the port has reached its end.
Here is an example that uses direct ports to copy a file of any size:
Skipping Data 0
There are two ways to skip data that exists in a port. First, you can open the port
with the /skip refinement. This open function will automatically skip to a point in
the port. For example:
You can also use the skip function on the port. For files that are opened with /direct
and /binary the skip operation is identical to a file system seek operation. Data is
not read into memory. This is not possible in /string mode because the line breaks
interfere with the skip size.
File Permissions M
When files are created by REBOL, default access permissions are set. On Windows
and Macintosh systems files are created with full access privileges. On UNIX
systems files are created with the permissions set to the current umask setting.
When using open or write to access a file the /allow refinement is used to set file
access permissions.
The /allow refinement takes a block as an argument. This block can consist of any
or all of the three words read, write and execute.
NOTE: The /allow refinement will only set permissions on operating systems
supporting the specified permission setting. If the operating system does not
support a permission setting used, the setting will be ignored. For instance, files on
UNIX systems may be set as executable (execute), but the Windows and Macintosh
operating systems don’t support this. When dealing with UNIX systems,
permissions set using /allow will only set the user permissions. Using / allow will
cause all access permissions to be removed for users and others.
To make a file read only, use open/allow, or write/allow with a read block.
To prevent any access to a file (for operating systems where this would make a
difference) provide an empty permissions block:
write/allow %file.txt []
Directory Ports M
Directory ports allow you to open direct access to file directories. Within the
system, this is how most other directory functions are created.
When you open a directory, you gain direct access to the directory as a block of
filenames:
CVS/
history.t
intro.t
overview.t
quick.t
close mydir
You can advance to a specific position within a directory series and remove a file
with code such as:
dir: open %.
remove next dir
close dir
remove at dir 5
clear dir
To delete all files that contain with the word “junk”, you can write:
The changes made to a directory are made when the directory is closed or when it
is updated. To force the action to occur immediately use a line such as:
update dir
The method of directory access can also be used for changing the names of files.
After the open, the line:
will rename the third file in the directory. Similarly, the names of any of the files in
the directory can be changed.
Here is an example that renames all of the files in a directory by adding the word
REBOL to their names:
This chapter describes the features of parse within REBOL/Core. It includes the
following information:
14- 1
Parsing
Overview
Overview N
Parsing splits a sequence of characters or values into smaller parts. It can be used
for recognizing characters or values that occur in a specific order. In addition to
providing a powerful, readable, and maintainable approach to regular expression
pattern matching, parsing enables you to create your own custom languages for
specific purposes.
The series argument is the input that is parsed and can be a string or a block. If
the argument is a string, it is parsed by character. If the argument is a block, it is
parsed by value.
The rules argument specifies how the series argument is parsed. The rules
argument can be a string for simple types of parsing or a block for sophisticated
parsing.
The parse function also accepts two refinements: /all and /case. The /all
refinement parses all the characters within a string, including all delimiters, such as
space, tab, newline, comma, and semicolon. The /case refinement parses a string
based on case. When /case is not specified, upper and lower cases are treated the
same.
Simple Splitting N
The parse function splits the input argument, string, into a block of multiple
strings, breaking each string wherever it encounters a delimiter, such as a space,
tab, newline, comma, or semicolon. The none argument indicates that no other
delimiters other than these. For example:
Similarly,
In the example above, notice that the commas and semicolons have been removed
from the resulting strings.
You can specify other delimiters in the second argument to parse, which are
combined with the default delimiters (space, tab, newline, comma, semicolon).. For
example, the following code parses a telephone number adding dash (-) to the
delimiters:
The next example adds equal (=) and double quote (“) to the to the delimiters:
To disable the default delimiters, use the /all refinement. With the /all refinement,
only the delimiters passed in the second argument are used.
The next example parses a string based on commas only; any other delimiters are
ignored. Consequently, the spaces within the strings are not removed:
You can parse strings that contain null characters as separators (such as certain
types of data files):
Grammar Rules N
The parse function accepts grammar rules that are written in a dialect of REBOL.
Dialects are sub-languages of REBOL that use the same lexical form for all data
types, but allow a different ordering of the values within a block. Within this dialect
the grammar and vocabulary of REBOL is altered to make it similar in structure to
the well known BNF (Backus-Naur Form) which is commonly used to specify
language grammars, network protocols, header formats, etc.
To define rules, use a block to specify the sequence of the inputs. For instance, if
you want to parse a string and return the characters "the phone", you can use
a rule:
To allow any number of spaces or no spaces between the words, write the rule like
this:
You can indicate alternate rules with a vertical bar (|). For example:
the phone
a radio
A rule can contain blocks that are treated as sub-rules. The following line:
a phone
a radio
the phone
the radio
For increased readability, write the sub-rules as a separate block and give them a
name to help indicate their purpose:
[3 "a" 2 "b"]
aaabb
[1 3 "a" "b"]
ab aab aaab
[0 3 "a" "b"]
b ab aab aaab
Use some to specify that one or more characters are matched. Use any to specify
that zero or more characters are matched. For example, some used in the following
line:
The words some and any can also be used on blocks. For example:
The none is useful for specifying optional patterns or for catching error cases when
no pattern matches.
Skipping Input N
Use skip to skip a single character, or use it with a repeat to skip over multiple
characters:
["a" to "b"]
The previous example starts parsing at a and ends at b but does not include b.
The following rule finds the title of an HTML page and prints it:
REBOL Technologies
The first thru finds the title tag and goes immediately past it. Next, the input string
is copied into a variable called text until the ending tag is found (but it doesn’t go
past it, or the text would include the tag).
Match Types N
When parsing strings, these data types and words can be used to match characters
in the input string:
Table 14-1. Match Types
To use all of these words (except bitset, which is explained below) in a single rule,
use:
<B>excellent!</B>
<B>incredible!</B>
The end specifies that nothing follows in the input stream. The entire input has
been parsed. It is optional depending on whether the parse function’s return value
is to be checked. Refer to the “Evaluation” section below for more information.
The bitset data type deserves more explanation. Bitsets are used to specify
collections of characters in an efficient manner. The charset function enables you
to specify individual characters or ranges of characters. For example, the line:
defines a character set that contains digits. This allows rules like:
707-467-8000
A character set can also specify ranges of characters. For instance, the digit
character set could have be written as:
Character sets can also be modified with the insert and remove functions, or
combinations of sets can be created with the union and intersect functions. This
line copies the digit character set and adds a dot to it:
Recursive Rules N
Here is an example of rule set that parses mathematical expressions and gives a
precedence (a priority) to the math operators used:
Now we can parse many types of math expressions. The following examples return
true, indicating that the expressions were valid:
true
true
Notice in the examples that some of the rules refer to themselves. For instance, the
expr rule includes expr. This is a useful technique for defining repeating
sequences and combinations. The rule is recursive —it refers to itself.
When using recursive rules, care is required to prevent endless recursion. For
instance:
creates an infinite loop because the first thing expr does is use expr again.
Evaluation N
Normally, you parse a string to produce some result. You want to do more than just
verify that the string is valid, you want to do something as it is parsed. For instance,
you may want to pick out substrings from various parts of the string, create blocks
of related values, or compute a value.
Return Value 0
The examples in previous chapters showed how to parse strings, but no results were
produced. This is only done to verify that a string has the specified grammar; the
value returned from parse indicates its success. The following examples show this:
true
false
The parse function returns true only if it reaches the end of the input string. An
unsuccessful match stops the parse of the series. If parse runs out of values to
search for before reaching the end of the series, it does not traverse the series and
returns false:
false
true
true
Expressions in Rules 0
Within a rule, you can include a REBOL expression to be evaluated when parse
reaches that point in the rule. Parentheses are used to indicate such expressions:
found phone
true
The example above parses the string a phone and prints the message found
phone after the match is complete. If the strings a or phone are missing and the
parse can not be done, the expression is not evaluated.
Expressions can appear anywhere within a rule, and multiple expressions can occur
in different parts of a rule. For instance, the following code prints different strings
depending on what inputs were found:
parse string [
"a" | "the"
to "phone" (print "answer") |
to "radio" (print "listen") |
to "tv" (print "watch")
]
answer
parse string [
"a" | "the"
to "phone" (print "answer") |
to "radio" (print "listen") |
to "tv" (print "watch")
]
listen
Here is an example that counts the number of times the HTML pre-format tag
appears in a text string:
count: 0
page: read http://www.rebol.com/dictionary.html
parse page [any [thru <pre> (count: count + 1)]]
print count
777
The most common action done with parse is to pick up parts of the string being
parsed. This is done with copy, and it is followed by the name of a variable to which
you want to copy the string. The following example parses the title of a web page:
REBOL/Core Dictionary
The example works by skipping over text until it finds the <title> tag. That’s
where it starts making a copy of the input stream and setting a variable called text
to hold it. The copy operation continues until the closing </title> tag is found.
The copy action also can be used with entire rule blocks. For instance, for the rule:
the heading string contains the entire H1, H2, or H3 string. This also works for large
multi-block rules.
The copy action makes a copy of the substring that it finds, but that is not always
desirable. In some cases, it is better to save the current position of the input stream
in a variable.
NOTE: The copy word as used in parse is different from the copy function used in
REBOL expressions. Parse uses a dialect of REBOL, and copy has a different
meaning within that dialect.
In the following example, the begin variable holds a reference to the page input
string just after <title>. The ending refers to the page string just before
</title>. These variables can be used in the same way as they would be used
with any other series.
parse page [
thru <title> begin: to </title> ending:
(change/part begin "Word Reference Guide" ending)
]
You can see the above parse expression actually changed the contents of the title:
Here is another example that marks the position of every table tag in an HTML file:
NOTE: The current position in the input string can also be modified. The next section
explains how this is done.
Now that you know how to obtain the position of the input series, you also can use
other series functions on it, including insert, remove, and change. To write a script
that replaces all question marks (?) with exclamation marks (!), write:
The skip at the tail advances the input over the new character, which is not
necessary in this case, but it is a good practice.
As another example, to insert the current time everywhere the word time appears
in some text, write:
str: "at this time, I’d like to see the time change"
parse str [
some [to "time"
mark:
(remove/part mark 4 mark: insert mark now/time)
:mark
]
]
print str
Notice the :mark word used above. It sets the input to a new position. The insert
function returns the new position just past the insert of the current time. The word
:mark is used to set the input to that position.
Using Objects 0
When parsing large grammar from a set of rules, variables are used to make the
grammar more readable. However, the variables are global and may become
confused with other variables that have the same name somewhere else in the
program.
The solution to this problem is to use an object to make all the rule words local to
a context. For instance:
Debugging 0
As rules are written, there are times debugging is needed. Specifically, you may
want to know how far you got in the parsing of a rule.
The trace function can be used to watch the parse operation progress, but this can
output thousands of lines that are difficult to review.
A better way is to insert debugging expressions into the parse rules. As an example,
to debug the rule:
insert a the print function after key sections to monitor your progress through the
rule:
Another approach is to print out part of the input string as the parse happens:
[
to "<IMG" here: (print here)
"SRC" "=" here: (print here)
filename here: (print here) ">"
]
[
to "<IMG" here
"SRC" "=" here
filename here ">"
]
The copy function can also be used to indicate what substrings were parsed as the
rule was handled.
The parse function normally ignores all intervening whitespace between patterns
that it scans. For instance, the rule:
abc
a bc
ab c
a b c
a b c
To enforce a specific spacing convention, use parse with the /all refinement. In the
preceeding example, this refinement causes parse to only match the first case (abc).
Specifying the /all refinement forces every character in the input stream to be dealt
with, including the default delimiters, such as space, tab, newline.
To handle spaces in your rules, create a character set that specifies the valid space
characters:
For more sophisticated grammars, create a character set that lets you scan a string
up to a space character.
The preceding example builds a block of all of its words. The complement function
inverts the character set. Now it contains everything except the spacing characters
you defined earlier. The non-space character set contains all characters except
space characters. The to-space rule accepts one or more characters up to a space
character or the end of the input stream. The main rule expects to begin with a
word, copy that word up to a space, then skip the space character and begin the
next word.
Blocks are parsed similar to strings. A set of rules specify the order of expected
values. However, unlike the parsing of strings, the parsing of blocks is not
concerned with characters or delimiters. Parsing of blocks is done at the value level,
making the grammar rules easier to specify and operation many times faster.
Block parsing is the easiest way to create REBOL dialects. Dialects are
sub-languages of REBOL that use the same lexical form for all data types but allow
a different ordering of the values within a block. The values do not need to conform
to the normal order required by REBOL function arguments. Dialects are able to
provide greater expressive power for specific domains of use. For instance, the
parser rules themselves are specified as a dialect.
Matching Words 0
When parsing a block, to match against a word specify the word as a literal:
’name
’when
’empty
You can match a value of any data type by specifying the data type word. See
Table 14-2 below.
Table 14-2. Data Type Matches
NOTE: Don’t forget the "!" that is part of the name or an error will be generated.
The parse operations allowed for blocks are those that deal with specific characters.
For instance, a match cannot be specified to the first letter of a word or string, nor
to spacing or newline characters.
Dialect Examples 0
Notice that a specific word can be matched by using its literal word in the rule (as
in the case of ’when). A data type can be specified rather than a value, as in the
lines above containing time!. In addition, a variable can be set to a value with the
set operation.
rule: [some [
’when set time time! |
’where set place string! |
’who set persons [word! | block!]
]]
parse [
who Fred
where "Downtown Center"
when 9:30
] rule
print [time place persons]
This example could have used variable assignment, but it illustrates how to provide
alternate input ordering.
rule: [
set count integer!
set str string!
(loop count [print str])
]
parse [3 "great job"] rule
parse [3 "hut" 1 "hike"] [some rule]
rule: [
set action [’buy | ’sell]
set number integer!
’shares ’at
set price money!
(either action = ’sell [
print ["income" price * number]
total: total + (price * number)
][
print ["cost" price * number]
total: total - (price * number)
]
)
]
total: 0
parse [sell 100 shares at $123.45] rule
print ["total:" total]
total: 0
parse [
sell 300 shares at $89.08
buy 100 shares at $120.45
sell 400 shares at $270.89
] [some rule]
print ["total:" total]
Parsing Sub-blocks 0
fails and into looks for alternates or exits the rule. If the next value is a block, the
parser rule that follows the into word is used to begin parsing the sub-block. It is
processed in the same way as a sub-rule.
rule: [
set date date!
set info into [string! time!]]
]
data: [10-Jan-2000 ["Ukiah" 10:30]]
print parse data rule
print info
probe items
General Forms
Table 14-3. General Forms
Operator Description
| alternate rule
[block] sub-rule
(paren) evaluate a REBOL expression
Specifying Quantity
Table 14-4. Specifying Quantity
Operator Description
Skipping Values
Table 14-5. Skipping Values
Operator Description
Getting Values
Table 14-6. Getting Values
Operator Description
Using Words
Table 14-7. Using Words
Value Matches (examples, any data type is valid - block parsing only)
Table 14-8. Value Matches
Operator Description
This appendix gives a listing of the value types used in REBOL and their use. It
includes the following information:
A- 1
Values
Number Values
Number Values A
Decimal A
Concept
The decimal! data type includes 64-bit standard IEEE floating point numbers. They
are distinguished from integer numbers by a decimal point.
Format
Decimal values are a sequence of numeric digits, followed by a decimal point,
which can be a period (.) or a comma (,), followed by more digits. A plus (+) or
minus (-) immediately before the first digit indicates sign. Leading zeros before the
decimal point are ignored. Extra spaces, commas, and periods are not allowed.
1.23
123.
123.0
0.321
0.123
1234.5678
A comma can be used in place of a period to represent the decimal point (which is
the custom in some countries):
1,23
0,321
1234,5678
Use a single quote (‘) to separate the digits in long decimals. Single quotes can
appear anywhere after the first digit in the number, but not before the first digit.
100’234’562.3782
100’234’562,3782
1.23E10
1.2e007
123.45e-42
56,72E300
-0,34e-12
0.0001e-001
Creation
Use the to-integer function to convert a string!, integer!, block!, or a decimal!
data type to a decimal number:
123.45
123
-1.23E+47
1.23E-43
-123.8
12.3
probe 1.2 + 2
3.2
probe 2 + 1.2
3.2
true
false
Related
Use decimal? to determine whether a value is an decimal! data type.
true
Use the form, print, and mold functions with an integer argument to print a
decimal value in its simplest form:
For example,
123.4
2.22222222222222E+15
print 1.00001E+5
100001
Single quotes (‘) and a leading plus sign (+) do not appear in decimal output:
print +1’100’200.222’112
1100200.222112
Integer A
Concept
The integer! data type includes 32-bit positive and negative numbers and zero.
Unlike decimal numbers, integers do not contain a decimal point.
Format
Integer values consist of a sequence of numeric digits. A plus (+) or minus (-)
immediately before the first digit indicates sign. (There cannot be a space between
the sign and the first digit.) Leading zeros are ignored.
2’147’483’647
Creation
Use the to-integer function to convert a string!, logic!, decimal!, or integer! data
type to an integer:
123
123
123
-123
probe 1.2 + 2
3.2
probe 2 + 1.2
3.2
true
true
Related
Use integer? to determine whether a value is an integer! data type.
true
Use the form, print, and mold functions with an integer argument to print a integer
value as a string:
123
123
print 123
123
Integers that are out of range or cannot be represented in 32 bits are flagged as an
error.
Series Values A
Binary A
Concept
Binary values hold binary data of any arbitrary type. Any sequence of bytes can be
stored, such as an image, audio, executable file, compressed data, and encrypted
data. The source format for binary data can be base-2 (binary), base-16 (hex), and
base-64. The default base for binary data in REBOL is base-16.
Format
Binary strings are written as a number sign (#) followed by a string enclosed in
braces. The characters within the string are encoded in one of several formats as
specified by an optional number prior to the number sign. Base-16 is the default
format.
Spaces, tabs and newlines are permitted within the string. Binary data can span
multiple lines.
probe #{
3A
18
92
56
}
#{3A189256}
Strings that are missing the correct number of characters to create a correct binary
result are padded on the right.
Creation
The to-binary function converts data to the binary! data type at the default base
set in system/options/binary-base:
#{313233}
#{746F64617920697320746865206461792E2E2E}
#{01}
#{0B}
Converting a series of integers into a binary, returns the bit conversion for each
integer concatenated into a single binary value:
probe to-binary [1 1 1 1]
#{01010101}
Related
Use binary? determine whether a value is an binary! data type.
true
true
Closely related to working with binary! data types are the functions enbase and
debase. The enbase function converts strings to their base-2, base-16 or base-64
representations as strings. The debase function converts enbased strings to a binary
value of the base specified in system/options/binary-base.
Block A
Concept
Blocks are groups of values and words. Blocks are used everywhere, from a script
itself to blocks of data and code provided in a script.
Block values are indicated by opening and closing square brackets ([]) with any
amount of data contained between them.
woodsmen: [
"Paul" "Bunyuan" [email protected]
"Grizzly" "Adams" [email protected]
"Davey" "Crocket" [email protected]
]
Blocks are also a type of series, and thus anything that can be done with a series
can be done with a block value.
[
"Grizzly" "Adams" [email protected]]
append woodsmen [
"John" "Muir" [email protected]
]
probe woodsmen
[
"Paul" "Bunyuan" [email protected]
"Grizzly" "Adams" [email protected]
"Davey" "Crocket" [email protected]
"John" "Muir" [email protected]
]
data in a block
blks: [
[print "block one"]
[print "block two"]
[print "block three"]
]
foreach blk blks [do blk]
block one
block two
block three
Format
Blocks can contain any number of values or no values at all. They can extend over
multiple lines and can include any type of value, including other blocks.
An empty block:
[ ]
A block of integers:
[24 37 108]
A REBOL header:
REBOL [
Title: "Test Script"
Date: 31-Dec-1998
Author: "Ima User"
]
false
Blocks allow any number of lines, spaces, or tabs. Lines and spaces can be placed
anywhere within the block, so long as they do not divide a single value.
Creation
The to-block function converts data to the block! data type:
Related
Use block? to determine whether a value is an block! data type.
true
As blocks are a subset of the series! pseudotype, use series? to check this:
true
Using form on a block value creates a string from the contents contained in the
block:
123 10:30
Using mold on a block value creates a string from the block value and it’s contents,
thus allowing it to be reloaded as a REBOL block value:
[123 10:30]
Closely related data types are hash! and list!. They are used in much the same way
as block values, but have special capabilities. List values are designed to handle
modification of lists more quickly than block values, and hash values are designed
handle data lookup and hash indexing of data. These are useful when dealing with
large data sets.
Email A
Concept
An email address is a data type. The email! data type allows for easy expression of
email addresses:
emails: [
[email protected]
[email protected]
[email protected]
[email protected]
]
mesg: {poetry reading at 8:00pm!}
foreach email emails [send email mesg]
Email is also one of the series! data types, so the same rules that apply to series
apply to emails:
Format
The standard format of an email address is a name, followed by an at sign (@),
followed by a domain. An email address can be of any length, but must not include
any of restricted characters, such as square brackets, quotes, braces, spaces,
newlines, etc..
[email protected]
[email protected]
[email protected]
Access
Refinements can be used with an email value to get the user name or domain. The
refinements are:
email: [email protected]
probe email/user
luke
probe email/host
rebol.com
Creation
The to-email function converts data to the email! data type:
probe to-email [user some long domain name out there dom]
Related
Use email? to determine whether a value is an email! data type.
true
As emails are a subset of the series! pseudotype, use series? to determine whether
the value is a series:
true
#"@"
File A
Concept
The file! data type can be a file name, directory name, or directory path.
%file.txt
%directory/
%directory/path/to/some/file.txt
File values are a subset of series, and thus can be manipulated as a series:
%path2/file.txt
f: %dir/path/file.txt
probe head remove/part (find f "path/") (length? "path/")
%dir/file.txt
Format
Files are designated with a percent sign (%)followed by a sequence of characters:
load %image.jpg
prog: load %examples.r
save %this-file.txt "This file has few words."
files: load %../programs/
probe %cool%20movie%20clip.mpg
%cool%20movie%20clip.mpg
print %cool%20movie%20clip.mpg
%cool%20movie%20clip.mpg
The standard character for separating directories in a path is the forward slash (/),
not the backslash (\). However, the REBOL language automatically converts
backslashes found in file names to forward slashes:
probe %\some\path\to\some\where\movieclip.mpg
%/some/path/to/some/where/movieclip.mpg
Creation
The to-file function converts data to the file! data type:
%testfile
When passed a block, elements in the block are concatenated into a file path with
the final element used as the file name:
%some/path/to/a/file/the-file.txt
Related
Use file? to determine whether a value is an file! data type.
true
As files are a subset of the series! pseudotype, use series? to check this:
true
Hash A
Concept
Hash is a block that is specially organized to make finding data faster. When
searching is performed on a hash block, the search is performed by using a hash
table for lookup. For large blocks, this can speed searches by hundreds of times.
Format
Hash blocks must be constructed by using make or to-hash. They have no lexical
format.
Creation
Use make to initialize a hash block:
Convert a block:
two
Related
Use hash? to test the data type.
true
As hashes are a subset of the series! pseudotype, use series? to check this:
true
Forming a hash value creates a string from the contents contained in the hash:
Molding a hash value creates a string of the hash value itself and its contents, thus
allowing it to be reloaded as a REBOL hash value:
Image A
Concept
The image! data type is a series that holds RGB images. This data type is used with
REBOL/View.
The image formats supported are GIF, JPEG, and BMP. The loaded image can be
manipulated as a series.
Format
Images are normally loaded from a file. However, they can be expressed in source
code as well by making an image. The block provided includes the image size and
its RGB data.
Creation
Empty images can be created using make or to-image:
Images can also be made from snapshots of a face object. This is also done using
make or to-image:
Use load to load an image file. If the image’s format is not supported, it will fail to
load.
Loading an image:
Related
Use image? to determine whether a value is the image! data type:
Use the /size refinement to return the pixel size of an image as a pair value:
probe img/size
The pixel values of an image are obtained using pick and changed using poke. The
value returned by pick is an RGB tuple value. The value replaced with poke also
should be a tuple value.
Issue A
Concept
An issue! is a series of characters used to sequence symbols or identifiers for things
like telephone numbers, model numbers, serial numbers, and credit card numbers.
Issue values are a subset of series, and thus can be manipulated as series:
#555
Format
Issues start with a number sign (#) and continue until the first delimiting character
(such as a space) is reached.
#707-467-8000
#A-0987654321-CD-09876
#1234-5678-4321-8765
#MG82/32-7
Values that contain delimiting characters should be written as strings rather than
issues.
Creation
The to-issue function converts data to the issue! data type:
#1234-56-7890
Related
Use issue? to determine whether a value is an issue! data type.
true
As issues are a subset of the series pseudotype, use series? to check this:
true
The form function returns an issue as a string without the number sign (#):
1234-56-7890
The mold function returns an issue as a string that can be read by REBOL as an
issue value:
#1234-56-7890
The print function prints an issue to standard output after doing a reform on it:
print #1234-56-7890
1234-56-7890
List A
Concept
Lists are linked list blocks that allow for faster and more efficient insertion and
removal of their values. They can be used in cases where a large number of
insertions or removals are being performed on large blocks.
Format
List blocks must be constructed by using make or to-list. They have no lexical
format.
Lists values are not a direct substitute for blocks. There are a couple of differences
between blocks and lists:
Inserting into a list modifies its reference to just after the point of insertion.
Removing the element currently referenced in a list causes the reference to reset to
the tail of the list
The following examples show the difference in behavior between inserting into a
list and a block.
blk: [1 2 3]
lst: to-list [1 2 3]
insert blk 0
insert lst 0
Looking at the word after the block and list after insertion. Notice blk points to
the head, as before the insertion of 0, but lst points to just after the point of
insertion:
print blk
0 1 2 3
print lst
1 2 3
0 1 2 3
blk: [1 2 3]
lst: to-list [1 2 3]
remove blk
remove lst
Looking at the word after removal of the value. Notice lst now points to the tail
of the series:
print blk
2 3
true
2 3
If you don’t want the word to be at the tail after removing a value, step forward and
remove the value behind the current index. The following examples depicts this.
Initializing a list:
lst: to-list [1 2 3]
Stepping forward and removing the value behind the current index:
probe lst
make list! [2 3]
Creation
Use make to initialize a list value:
Convert a block:
Related
Use list? to determine whether a value is an list! data type.
true
Since lists are a subset of the series! data type, use series? to check whether a list
is a series:
true
Using form on a list value creates a string from the contents contained in the list:
Using mold on a list value creates a string of the list value itself and it’s contents,
thus allowing it to be reloaded as a REBOL list value:
Paren A
Concept
A paren! data type is a block that is immediately evaluated. It is identical to a block
in every way, except that it is evaluated when it is encountered and its result is
returned.
When used within an evaluated expression, a paren! allows you to control the order
of evaluation:
print 1 + (2 * 3)
print 1 + 2 * 3
The value of a paren! can be accessed and modified in the same way as any block.
However, when referring to a paren!, care must be taken to prevent if from being
evaluated. If you store a paren in a variable, you will need to use a get-word form
(:word) to prevent it from being evaluated.
Parens are a type of series, thus anything that can be done with a series can be done
with paren values.
paren!
(10 + 5 * 1 + 2 * 3 / 4)
print paren
12.75
Format
Parens are identified by their open and closing parenthesis. They can span multiple
lines and contain any data, including other paren values.
Creation
The make function can be used to allocate a paren value:
print :paren
20 + 10
print paren
30
(123 456)
(123 456)
Related
Use paren? to test the data type.
(3 + 3)
true
As parens are a subset of the series! pseudotype, use series? to check this:
true
Using form on a paren value creates a string from the contents contained in the
paren:
3 + 3
Path A
Concept
Paths are a collection of words and values delineated with forward slashes (/). Paths
are used to navigate to or find something. The words and values of a path are called
refinements, and they are combined to provide a means of navigating through a
value or function.
Paths can be used on blocks, files, strings, lists, hashes, functions, and objects.
How a path operates depends on the data type being used.
Paths can be used to select values from blocks, pick characters from strings, access
variables in objects, refine the operation of a function:
The example below shows the simplicity of using a path to access a mini-database
created from a few blocks:
towns: [
Hopland [
phone #555-1234
web http://www.hopland.ca.gov
]
Ukiah [
phone #555-4321
web http://www.ukiah.com
email [email protected]
]
]
print towns/ukiah/web
http://www.ukiah.com
Table A-1 shows the relationship of paths corresponding with type words, type
tests, and conversions:
Table A-1. Path Relationship
Examples of Paths
Evaluate an object’s function:
hello! hello!
Function refinements:
hello again!
USA: [
CA [
Ukiah [
population 15050
elevation "610 feet"
]
Willits [
population 9935
elevation "1350 feet"
]
]
]
print USA/CA/Ukiah/population
15050
print USA/CA/Willits/elevation
1350 feet
Pick elements from series and embedded series by their numeric position:
string-series: "abcdefg"
block-series: ["John" 21 "Jake" 32 "Jackson" 43 "Joe" 52]
block-with-sub-series: [ "abc" [4 5 6 [7 8 9]]]
probe string-series/4
#"d"
probe block-series/3
Jake
probe block-series/6
43
probe block-with-sub-series/1/2
#"b"
probe block-with-sub-series/2/2
probe block-with-sub-series/2/4/2
The words supplied as paths are symbolic and therefore unevaluated. This is
necessary to allow the most intuitive form for object referencing. To use a word’s
reference, an explicit word value reference is required:
city: ’Ukiah
probe USA/CA/:city
[
population 15050
elevation "610 feet"
]
Paths in blocks, hashes, or objects are evaluated by matching the word at the top
level of the path, and verifying the word as a block!, hash! or object! value. Then
the next word in the path is sought as a word expressed in the block, hash or object
and an implicit select is performed. The value following the word matched is
returned. When the returned value is a block, hash, or object, the path can be
extended:
probe USA/CA
[
Ukiah [
population 15050
elevation "610 feet"
]
Willits [
population 9935
elevation "1350 feet"
]
]
probe USA/CA/Willits
[
population 9935
elevation "1350 feet"
]
probe USA/CA/Willits/population
9935
When a word is used in a path that does not exist at the given point in the structure,
an error is produced:
probe USA/CA/Mendocino
** Script Error: Invalid path value: Mendocino.
** Where: probe USA/CA/Mendocino
[
population 9935
elevation "1 foot, after the earthquake"
]
make object! [
text: "yes, I do believe in magic."
]
too many
hello again
Paths are a type of series, thus anything that can be done with a series can be done
with path values:
root/sub1/sub2/word
In the previous example, the :path notation was used to get the path itself, not
the path’s value:
probe path
sub2/word
root/sub1/sub2/num
probe path
55
Format
Paths are expressed relative to a root word by providing a number of refinements,
each separated by a forward slash (/). These refinements can be words or values.
Their specific interpretation vary depending on the data type of the root value.
The words supplied as refinements in paths are symbolic and are not evaluated.
This is necessary to allow the most intuitive form for object referencing. To use a
word’s reference, an explicit word value reference is required:
root/:word
This example uses the value of the variable, rather than it name.
Creation
You can make an empty path of a given size with:
test/this
root/sub
root/sub
The to-set-word function converts other values to the set-word data type.
root/sub:
The to-lit-word function converts other values to the lit-word data type.
’root/sub
Related
Use path?, set-path?, and lit-path? to determine the data type of a value.
false
it is set
true
As paths are a subset of the series! pseudotype, use series? to check this:
true
root/sub
Use mold on a path value creates a string of the path value itself, thus allowing it
to be reloaded as a REBOL path value:
root/sub
String A
Concept
Strings are a series of characters. All operations performable on series values can be
performed on strings.
Format
String values are written as a sequence of characters surrounded by double quotes
“ “ or braces {}. Strings enclosed in double quotes are restricted to a single line and
must not contain unprintable characters.
Strings enclosed in braces are used for larger sections of text that span multiple
lines. All of the characters of the string, including spaces, tabs, quotes, and newlines
are part of the string.
Braces are counted within the string, so a string can include other braces as long as
the number of closing braces matches the number of opening braces.
{
This is another long string of text that would
never fit on a single line. This string also
includes braces { a few layers deep { and is
valid because there are as many closing braces }
as there are open braces } in the string.
}
You can include special characters and operations in strings by prefixing them with
a caret (^). Special characters include:
Table A-1. Special Characters
Character Definition
Character Definition
Creation
Use make to create a pre-allocated amount of space for an empty string:
The to-string function converts data of other data types to a string! data type:
"29-Feb-2000"
"123456.789"
"888-555-2341"
Converting a block of data to a string with to-string has the effect of doing a rejoin,
but without evaluating the block’s contents:
"123456"
"225.225.225.0nonetrueword"
Related
Use string? or series? to determine whether a value is an string! data type:
true
true
The functions form and mold are closely related to strings, as they create strings
from other data types. The form function makes a human readable version of a
specified data type, while mold makes a REBOL readable version.
Tag A
Concept
Tags are used in HTML and other markup languages to indicate how text fields are
to be treated. For example, the tag <HTML> at the beginning of a file indicates
that it should be parsed by the rules of the Hypertext Markup Language. A tag
with a forward slash (/), such as </HTML>, indicates the closing of the tag.
<img src="mypic.jpg">
Format
A valid tag is any text that begins with an open angle bracket (<).
<a href="index.html">
<img src="mypic.jpg" width="150" height="200">
</a>
Creation
The to-tag function converts data to the tag! data type:
<title>
Use build-tag to construct tags, including their attributes. The build-tag function
takes one argument, a block. In this block, the first word is used as the tag name
and the remaining words are processed as attribute value pairs:
<a href="http://www.rebol.com/">
probe build-tag [
img src %mypic.jpg width 150 alt "My Picture!"
]
Related
Use tag? to determine whether a value is an tag! data type.
true
As tags are a subset of the series pseudotype, use series? to check this:
true
{<a href="http://www.rebol.com/">}
{<a href="http://www.rebol.com/">}
The print function prints a tag to standard output after doing a reform on it:
<a href="http://www.rebol.com/">
URL A
Concept
URL is an acronym for Uniform Resource Locator, an Internet standard used to
access resources such as web pages, images, files, and email across the network.
The best known URL scheme is that used for web locations such as
http://www.REBOL.com.
URL values are a subset of series, and thus can be manipulated as series:
url: http://www.rebol.com/reboldoc.html
probe to-file find/reverse (tail url) "rebol"
%reboldoc.html
Format
The first part of a URL indicates its communications protocol, called a scheme. The
language supports several schemes, including: web pages (HTTP:), file transfer
(FTP:), newsgroups (NNTP:), email (MAILTO:), files (FILE:), finger
(FINGER:), whois (WHOIS:), small network time (DAYTIME:), post office
(POP:), transmission control (TCP:) and domain name service (DNS:).
These scheme names are followed by characters that are dependent on which
scheme being used.
http://host.dom/path/file
ftp://host.dom/path/file
nntp://news.some-isp.net/some.news.group
mailto:name@domain
file://host/path/file
finger://[email protected]
whois://[email protected]
daytime://everest.cclabs.missouri.edu
pop://user:[email protected]/
tcp://host.dom:21
dns://host.dom
Some fields are optional. For instance, the host can be followed by a port number
if it differs from the default. An FTP URL supplies a default password if one is not
specified:
ftp://user:[email protected]/path/file
probe http://www.somes-
ite.dom/odd%28dir%29/odd%7Bfile%7D.txt
http://www.somesite.dom/odd%28dir%29/odd%7Bfile%7D.txt
print http://www.somes-
ite.dom/odd%28dir%29/odd%7Bfile%7D.txt
http://www.somesite.dom/odd(dir)/odd{file}.txt
Creation
The to-url function converts blocks to the url! data type, the first element in the
block is the scheme, the second element is the domain (with or without
user:pass and port) the remaining elements are the path and file:
http://www.rebol.com/reboldoc.html
http://www.rebol.com/examples/websend.r
http://usr:[email protected]:80/%28path%29/index.html
Related
The data type word is url!.
true
As urls are a subset of the series pseudotype, use series? to check this:
true
Other Values A
Character A
Concept
Characters are not strings; they are the individual values from which strings are
constructed. A character can be a printable, unprintable, or a control character.
Format
A char! value is written as a number sign (#) followed by a string enclosed in
double quotes. The number sign is necessary to distinguish a character from a
string:
Characters can include escape sequences that begin with a caret(^)and are followed
by one or more characters of encoding. This encoding can include the characters
#"^A" to #"^Z" for control A to control Z (upper and lower case are the
same):
#"^A" #"^Z"
Character Definition
Creation
Characters can be converted to and from other data types with the to-char function:
#"a"
#"z"
probe to-char 65
#"A"
probe to-char 52
#"4"
#"4"
Another method of obtaining a character is to get the first character from a string:
#"A"
While characters in strings are not case sensitive, individual characters are case
sensitive:
true
false
Related
Use char? to determine whether a value is a char! data type.
false
true
Use the form function to print a character without the number sign:
"A"
Use mold on to print a character with the number sign and double quotes (and
escape sequences for those characters that require it.):
{#"A"}
Date A
Concept
Around the world, dates are written in a variety of formats. However, most
countries use the day-month-year format. One of the few exceptions is the
United States , which commonly uses a month-day-year format. For
example, a date written numerically as 2/1/1999 is ambiguous. The month
could be interpreted as either February or January. Some countries use a dash
(-), some use a forward slash (/), and others use a period (.) as a separator.
Finally, computer people often prefer dates in the year-month-day (ISO) format
so they can be easily sorted.
Format
The REBOL language is flexible, allowing date! data types to be expressed in a
variety of formats. For example, the first day of March can be expressed in any of
the following formats:
probe 1/3/1999
1-Mar-1999
probe 1-3-1999
1-Mar-1999
1-Mar-1999
The year can span up to 9999 and down to 1. Leap days (February 29) can only be
written for leap years:
probe 29-2-2000
29-Feb-2000
The fields of dates can be separated with forward slashes (/) or dashes (-). Dates
can be written in either a year-month-day format or a day-month-year format:
probe 1999-10-5
5-Oct-1999
probe 1999/10/5
5-Oct-1999
probe 5-10-1999
5-Oct-1999
probe 5/10/1999
5-Oct-1999
Because the international date formats that are not widely used in the USA, a month
name or month abbreviation can also be used:
probe 5/Oct/1999
5-Oct-1999
probe 5-October-1999
5-Oct-1999
probe 1999/oct/5
5-Oct-1999
When the year is the last field, it can be written as either a four digit or two digit
number:
probe 5/oct/99
5-Oct-1999
probe 5/oct/1999
5-Oct-1999
However, it is preferred to write the year in full. Otherwise, problems occur with
date comparison and sorting operations. While two digits can be used to express a
year , the interpretation of a two-digit year is relative to the current year and is only
valid for 50 years in the future or in the past:
28-Feb-1966
12-Mar-2020
11-Mar-2045
To represent dates in the first century (which is rarely done because the Gregorian
calendar did not exist), use leading zeros to represent the century (as in
9-4-0029).
Dates can also include an optional time field and an optional time zone. The time
is separated from the date with a forward slash (/). The time zone is appended
using a plus (+) or minus (-), and no spaces are allowed. Time zones are written
as a time shift (plus or minus) from GMT. The resolution of the time zone is to the
half hour. If the time shift is an integer, it is assumed to be hours:
probe 4/Apr/2000/6:00+8:00
4-Apr-2000/6:00+8:00
probe 1999-10-2/2:00-4:00
2-Oct-1999/2:00-4:00
probe 1/1/1990/12:20:25-6
1-Jan-1990/12:20:25
10 - 5 - 99
Access
Refinements can be used with a date value to get any of its defined fields:
Table A-3. Date Value Refinements
Refinement Description
Refinement Description
some-date: 29-Feb-2000
probe some-date/day
29
probe some-date/month
probe some-date/year
2000
Tue
When a time is present, the time related refinements can be used. The /hour,
/minute and /second refinements are used with the /time refinement that isolates
the time segment of the date value for them to work on:
lost-time: 29-Feb-2000/11:33:22.14-8:00
probe lost-time/time
11:33:22.14
probe lost-time/time/hour
11
probe lost-time/time/minute
33
probe lost-time/time/second
22.14
probe lost-time/zone
-8:00
Creation
Use the to-date function to convert values to a date!:
5-Oct-1999
5-Oct-1999/10:30
5-Oct-1999
5-Oct-1999/10:30-8:00
[!Note When converting to a date!, the year must be specified as four digits.
probe 5-Oct-1999 + 1
6-Oct-1999
probe 5-10-1999 - 10
25-Sep-1999
6-Oct-1999/4:00
Related
Use date? to determine whether a value is a date! data type.
true
The related function to-idate returns a standard Internet date string. The Internet
date format is day, date, month, year, time (24-hour clock), and time zone offset
from GMT.
The now function returns the current date and time in full format including the time
zone offset:
probe now
30-Jun-2000/14:42:26-7:00
Logic A
Concept
The logic! data type consists of two states representing true and false. They are
often returned from comparisons such as:
age: 100
probe age = 100
true
time: 10:31:00
probe time < 10:30
false
true
The logic! data type is most commonly used as parameters to conditional functions
such as if, while, and until:
Centennial human
Format
Normally, logic values are retrieved from the evaluation of comparison expressions.
However, words can be set to a logic value and used to turn the word on or off:
print-me: false
print either print-me ["turned on"]["turned off"]
turned off
print-me: true
print either print-me ["turned on"]["turned off"]
turned on
The false value is not equivalent to integer zero or none. However, in conditional
expressions false and none have the same effect:
print-me: none
print either print-me ["turned on"]["turned off"]
turned off
Just about any value assigned to a word has the same effect as true:
turned on
print-me: 11-11-1999
print either print-me ["turned on"]["turned off"]
turned on
true
on ;same as true
yes ;same as true
false
off ;same as false
no ;same as false
So, instead of true and false, when it makes sense, the words on and off, or yes and
no can be used instead:
print-me: yes
print either print-me ["turned on"]["turned off"]
turned on
print-me: no
print either print-me ["turned on"]["turned off"]
turned off
print-me: on
print either print-me ["turned on"]["turned off"]
turned on
print-me: off
print either print-me ["turned on"]["turned off"]
turned off
Creation
The to-logic function converts integer! or none! values to the logic! data type:
probe to-logic 0
false
true
false
probe to-logic []
true
true
false
Related
Use logic? to determine whether a value is a logic! data type.
probe logic? 1
false
probe logic? on
true
true
Use the functions form, print, and mold to print a logic value:
true
false
print true
true
Money A
Concept
There is a wide variety of international symbols for monetary denominations. Some
symbols are used before the amount and some after. As a standard for representing
international monetary values, the REBOL language uses the United States
monetary format , but allows the inclusion of specific denominations.
Format
The money! data type uses standard IEEE floating point numbers allowing up to 15
digits of precision including cents.
The language limits the length to 64 characters. Values that are out of range or
cannot be represented in 64 characters are flagged as an error.
$123
-$123
$123.45
US$12
US$12.34
-US$12.34
$12,34
-$12,34
DEM$12,34
To break long numbers into readable segments, a single quote (‘) can be placed
anywhere between two digits within the amount, but not before the amount.
probe $1’234.56
$1234.56
probe $1’234’567,89
$1234567.89
The money! data type is a hybrid data type. Conceptually money is scalar—an
amount of money. However, because the currency designation is stored as a string,
the money! data type has two elements:
To demonstrate this, the following money is specified with the USD prefix:
my-money: USD$12345.67
USD
12345.67
none
my-money: $12345.67
""
12345.67
my-money: DKM$12’345,67
DKM
12345.67
Creation
Use the to-money function to convert money from a string!, integer!, decimal!, or
block!.
$123.00
$123.00
$12.34
DEM$12.34
USA$12.34
Money can be added, subtracted, and compared with other money of the same
currency. An error occurs if a different currency is used for such operations
(automatic conversions are not currently supplied).
$110.00
$50.00
true
Money can be multiplied and divided by integers and decimals. Money can also be
divided by money, resulting in an integer or decimal.
probe $100 + 11
$111.00
probe $100 / 4
$25.00
probe $100 * 5
$500.00
$79.50
probe 10 + $1.20
$11.20
probe 10 - $0.25
$9.75
$20.00
probe 10 * $0.75
$7.50
Related
Use money? to determine whether a value is an money! data type.
true
Use the form, print, and mold functions with a money argument to print a money
value with the currency designator and dollar sign ($), as a decimal number with
two digits of decimal precision.
USD$12.34
USD$12.34
print USD$12.34
USD$12.34
None A
Concept
The none! data type contains a single value that represents nothing or no value.
The concept of none is not the same as an empty block, empty string, or null
character. It is an actual value that represents non-existence.
A none! value can be returned from various functions, primarily those involving
series (for example, pick and find).
The REBOL word none is defined as a none! data type and contains a none! value.
The word none is not equivalent to zero or false. However, none is interpreted as
false by many functions.
A none! value has many uses such as a return value from series functions like pick,
find and select:
email-database: [
"Bobby" [email protected] 40
"Linda" none 23
"Sara" [email protected] 33
]
secure none
Format
The word none is predefined to hold a none value.
none
Creation
The to-none function always returns none.
Related
Use none? to determine whether a value is an integer! data type.
print none? 1
false
true
The form, print, and mold functions print the value none when passed a none
argument.
none
none
print none
none
Pair A
Concept
A pair! data type is used to indicate spatial coordinates, such as positions on a
display. They are used for both positions and sizes. Pairs are used primarily in
REBOL/View.
Format
A pair is specified as integers separated by an x character.
100x50
1024x800
-50x200
Creation
Use to-pair to convert block or string values into a pair data type:
p: to-pair "640x480"
probe p
640x480
800x600
Related
Use pair? to determine whether a value is a pair! data type:
true
true
100x200 + 10x20
10x20 * 2x4
100x30 / 10x3
100x100 * 3
10x10 + 3
pair: 640x480
probe first pair
640
480
All pair values support the /x and /y refinements. These refinements allow the
viewing and manipulation of individual pair coordinates.
probe pair/x
640
probe pair/y
480
pair/x: 800
pair/y: 600
probe pair
800x600
Time A
Concept
The REBOL language supports the standard expression of time in hours, minutes,
seconds, and subseconds. Both positive and negative times are permitted.
The time! data type uses relative rather than absolute time. For example, 10:30 is
10 hours and 30 minutes rather than the time of 10:30 A.M. or P.M.
Format
Times are expressed as a set of integers separated by colons (:).. Hours and minutes
are required, but seconds are optional. Within each field, leading zeros are ignored:
10:30
0:00
18:59
23:59:50
8:6:20
8:6:2
The minutes and seconds fields can contain values greater than 60. Values greater
than 60 are automatically converted. For instance 0:120:00 is the same as 2:00.
probe 00:120:00
2:00
Subseconds are specified using a decimal in the seconds field. Use either a period
or a comma as the decimal point. The hours and minutes fields become optional
when the decimal is present. Subseconds are encoded to the nano-second, or one
billionth of a second:
probe 32:59:29.5
32:59:29.5
probe 1:10,25
0:01:10.25
probe 0:0.000000001
0:00:00.000000001
probe 0:325.2
0:05:25.2
probe 10:20PM
22:20
probe 3:32:20AM
3:32:20
Times are output in a standard hours, minutes, seconds, and subseconds format,
regardless of how they are entered:
probe 0:87363.21
24:16:03.21
Access
Time values have three refinements that can be used to return specific information
about the value:
Table A-4. Time Value Refinements
Refinement Description
lapsed-time: 91:32:12.14
probe lapsed-time/hour
91
probe lapsed-time/minute
32
probe lapsed-time/second
12.14
Times with time zones can only be used with the date! .
Creation
Times can be converted using the to-time function:
10:30
10:30
0:10:30
10:30:20.5
In the previous examples, the values are not evaluated. To evaluate values as
mathematical expressions, use the reduce function:
10:35
In various math operations involving time values, the time values, integers, or
decimals are converted as shown below:
probe 10:30 + 1
10:30:01
probe 10:00 - 10
9:59:50
probe 0:00 - 10
-0:00:10
probe 5:10 * 3
15:30
0:00:00.0015006
probe 8:40:20 / 4
2:10:05
0:00:20
Related
Use time? to determine whether a value is a time! data type:
true
false
Use the now function with the /time refinement to return the current local date and
time:
print now/time
14:42:15
If a value is a time! data type, wait delays for that period of time. If a value is a
date!/time!, wait waits until the indicated date and time. If the value is an integer!
or decimal!, the function waits the indicated number of seconds. If the value is a
port, the function will wait for an event from that port. If a block is specified, it will
wait for any of the times or ports to occur. It returns the port that caused the wait
to complete or returns none if the timeout occurred. For example,
probe now/time
14:42:16
wait 0:00:10
probe now/time
14:42:26
Tuple A
Concept
It is common to represent version numbers, Internet addresses, and RGB color
values as a sequence of three or four integers. These types of numbers are called a
tuple! (as in quintuple) and are represented as a set of integers separated by
periods.
Format
Each integer field of a tuple! data type can range between 0 and 255. Negative
integers produce an error.
Three to ten integers can be specified in a tuple. In the case where only two integers
are given, there must be at least two periods, otherwise the value is treated as a
decimal.
1.2
decimal!
1.2.3
1.2.0
tuple!
Creation
Use the to-tuple function to convert data to the tuple! data type:
12.34.56
12.34.56
Related
Use tuple? to determine whether a value is a tuple! data type.
true
1.2.3.4
Use the mold function to convert a tuple into a string that can be read back into
REBOL as a tuple:
1.2.3.4
Use the print function to print a tuple to standard output after using the reform
function:
print 1.2.3.4
1.2.3.4
Words A
Concept
Words are the symbols used by REBOL. A word may or may not be a variable,
depending on how it is used. Words are often used directly as symbols.
REBOL has no keywords, there are no restrictions on what words are used or how
they are used. For instance, you can define your own function called print and
use it instead of the predefined function for printing values.
There are four different formats for using words, depending on the operation
required.
Table A-5. Word Use Formats
Format
Words are composed of alphabetic characters, numbers, and any of the following
characters:
? ! . ’ + - * & | = _ ~
A word cannot begin with a number, and there are also some restrictions on words
that could be interpreted as numbers. For instance, -1 and +1 are numbers, not
words.
[ ] ( ) { } " : ; /
[test]
@ # $ % ^ ,
Words can be of any length, but cannot extend past the end of a line.
this-is-a-very-long-word-used-as-an-example
image-files l’image
++ -- == +-
***** *new-line*
left&right left|right
blue
Blue
BLUE
all refer to the same word. The case of the word is preserved when it is printed.
Words can be reused. The meaning of a word is dependent on its context, so words
can be reused in different contexts. You can reuse any word, even predefined REBOL
words. For instance, the REBOL word if can be used in your code differently than
how it is used by the REBOL interpreter.
Creation
The to-word function converts values to the word! data type.
test
test:
:test
’test
Related
Use word?, set-word?, get-word?, and lit-word? to test the data type.
true
it is set
true
true
This appendix gives basic information on error types and how to use them in
REBOL. It includes the following information:
B- 1
Errors
Overview
Overview B
Errors are exceptions that occur when certain irregular conditions occur. These
conditions range from syntax errors to file or network access errors. Here are a few
examples:
12-30
1 / 0
read %nofile.r
Errors are processed within the system as values of the error! datatype. An error is
an object that, if evaluated, will print an error message and halt. You can also catch
errors and handle them in your script. Errors can be passed to functions, returned
from functions, and assigned to variables.
Error Categories B
Syntax Errors B
Syntax errors occur when a script uses REBOL syntax incorrectly. For instance, if a
closing bracket is missing or a string is missing its closing quote, a syntax error will
occur. These errors only occur during the load or evaluation of a file or string.
Script Errors B
Script errors are general run-time errors. For instance, an invalid argument to a
function will cause a script error.
Math Errors B
Math errors occur when a math operation cannot be processed. For instance, when
attempting to divide by zero an error will occur.
Access Errors B
Access errors occur when a problem occurs with a file, port or network access. For
example, an access error will occur when attempting to read a file that does not
exist.
User Errors B
User errors are generated explicitly by a script by creating an error value and
returning it.
Internal Errors B
Catching Errors B
You can catch errors with the try function. The try function is similar to the do
function. It evaluates a block, but always returns a value, even when an error
occurs.
When no error occurs, try returns the value of a block. For example:
10
the error is returned from the try and the print function cannot handle it.
To handle errors in a script, you must prevent REBOL from evaluating the error. You
can prevent an error from being evaluated by passing it to a function. For instance,
the error? function will return true when it is passed an error:
true
You can also print the data type of the value returned from a try:
error!
The disarm function converts an error to an error object that can be examined. In
the example below, the error variable holds an error object:
When an error is disarmed, it will be an object! data type, not an error! datatype.
Evaluating the disarmed object will not cause an error:
make object! [
code: 400
type: 'math
id: 'zero-divide
arg1: none
arg2: none
arg3: none
near: [100 / 0]
where: none
]
Error values can be set to a word before they are disarmed. To set a word to an error,
it must be preceded by a function that prevents the error from propagating further.
For example:
Setting a variable enables you to access the value of the block later. The example
below will print an error or non-error value:
Error Object B
make object! [
code: 400
type: 'math
id: 'zero-divide
arg1: none
arg2: none
arg3: none
near: [100 / 0]
where: none
]
Field Description
code The error code number. These are obsolete and should not be
used.
type The type field identifies the error category. It is always a word
data type of syntax, script, math, access, user and
internal.
id The id field is the name for the error. It identifies the specific
error that occurred within the error category.
arg1, arg2, arg3 These fields hold the arguments to the error message. For
instance, they may include the data type of the value that
caused the error.
near The near field is a code fragment that shows where the error
occurred.
where The where field is reserved.
You can write code that checks any of the error object fields. In this example, the
error is printed only when the error id indicates a divide by zero error:
The error id word also provides the error block that will be printed by the
interpreter. For example:
Generating Errors B
User errors can be generated. The simplest way to generate an error is make it. Here
is an example:
Any of the existing errors can be generated by making the error with a block
argument. This block contains the error category name and the error message id
name. If the error requires arguments, the arguments follow the message id name.
The arguments are what define the arg1, arg2 and arg3 values in the error
object. Here is an example:
Custom errors can be entered into the system/error object’s user category. This
is done by making a new user category with new entries. These entries are used
when generating errors. For instance, the following example enters an error into the
user category:
make object! [
code: 803
type: ’user
id: ’my-error
arg1: none
arg2: none
arg3: none
near: [make error! [user my-error]]
where: none
]
To create more informative errors, define an error that uses data available when it
is generated. This data is included in the disarmed error object and printed as part
of the error message. For instance, to use all three argument spaces in an error
object:
make object! [
code: 803
type: ’user
id: ’my-error
arg1: [this]
arg2: "that"
arg3: ’my-function
near: [make error! [user my-error [this] "that"
my-function]]
where: none
]
The error message generated for my-error can be printed without stopping the
script:
A new library category may be created if there is a need to group a series of errors
together by making a new category in system/error:
The type defined in the error object will be the error type printed when the error is
generated. The following example illustrates generating an error from both error1
and error2 in the my-error category.
a simple error
Finally, the description that returns the errors defined in my-errors may be
obtained with:
My Error Category
Error Messages B
Listed below is a list of all errors defined in the system/error object error catalog.
Syntax Errors B
Data could not be translated into a valid REBOL datatype. In other words, a
malformed value was evaluated.
Message:
Example:
Message:
Example:
An attempt was made to evaluate a file as a REBOL script and the file did not have
a REBOL header.
Message:
Example:
Script Errors B
Message:
Example:
An attempt was made to define a word to nothing. A set-word was used without an
argument.
Message:
Example:
A function was evaluated without providing it with all the arguments it was
expecting.
Message:
Example:
f: func [b][probe b]
filter-error try [f]
Message:
Example:
f: func [b [block!]][probe b]
filter-error try [f "string"]
Two series values were used together in a way that was not compatible. For
instance, when trying to do a union between a string and a block.
Message:
Example:
This is a generic error for handling values that were used improperly. For instance,
when a set-word is used inside of a function’s specification block.
Message:
Example:
An attempt was made to use an operator that had been redefined. The operator used
is no longer a valid operator.
Message:
Example:
A math or comparison operator was used without providing the second argument.
Message:
Example:
filter-error try [1 +]
A function expecting a block to return a value did not return anything. For instance,
when using the while or until function.
Message:
Examples:
10
** Script Error: Block did not return a value
** Where: while [print 10] [probe "ten"]
filter-error try [
until [print 10] ; block returns nothing
]
10
** Script Error: Block did not return a value
** Where: until [print 10]
Message:
An attempt was made to use a function refinement that didn’t exist for that
function.
Message:
Example:
An attempt was made to access a block or object value using a path that did not
exist within that block or object.
Message:
Example:
Message:
Example:
An attempt was made to alias a word that had already been aliased.
Message:
Example:
Message:
Example:
blk: [1 2 3]
filter-error try [poke blk 5 "five"]
An attempt was made to access series data beyond the length of the series.
Message:
Example:
blk: [1 2 3]
filter-error try [print fourth blk]
Message:
Message:
Example:
An attempt was made to decompress a binary value that was corrupt or not a
compressed format.
Message:
Example:
Message:
An attempt was made to run a script that needed either a new version of REBOL or
a file that couldn’t be found. This information will be found in the script’s REBOL
header.
Message:
An attempt was made to modify a protected word. The word will have been
protected with the protect function.
Message:
Example:
my-word: "data"
protect ’my-word
filter-error try [my-word: "new data"]
A function was evaluated that had multiple occurrences of a word defined in its
specification block. For instance, if the word arg was defined as both argument one
and two.
Message:
Example:
Access Errors B
A file could not be accessed. This could be a local or network file. Most common
reason for this error is a nonexistent directory.
Message:
Example:
Message:
Example:
p: open %file.txt
close p
filter-error try [copy p]
Message:
Example:
p: open %file.txt
filter-error try [open p]
An attempt was made to close a port that had already been closed.
Message:
Example:
p: open %file.txt
close p
filter-error try [close p]
An attempt was made to create a port with make using a specification that a port
could not be built from.
Message:
Example:
Message:
A connection to another host failed. This is generic error covering a range of reasons
for the connection failure. When more information is known about the reason for
the connection failure, a more specific error will be thrown.
Message:
Example:
An attempt was made to delete a file that was either locked or protected.
Message:
Example:
p: open %file.txt
filter-error try [delete %file.txt]
An attempt was made to rename a file that was either locked or protected.
Message:
Example:
p: open %file.txt
filter-error try [rename %file.txt %new-name.txt]
An attempt was made to create a directory in a file path that did not exist or was
write protected.
Message:
Example:
The timeout period elapsed while waiting to for a response from another host. This
timeout is set in the port’s timeout attribute.
Message:
Network timeout
An attempt was made within a script to change the security to a lower level of
security that was denied. This is to say, whenever a script requests a lower security
setting and the user denies the request, this error is thrown.
Message:
Example:
secure quit
filter-error try [secure none] ; denied request
secure none
A security violation occurred. This will happen when an attempt is made to access
a file or the network when the secure setting is set to throw.
Message:
Example:
secure throw
filter-error try [open %file.txt]
secure none
Message:
Example:
Internal Errors B
Message:
Example:
Message:
Message:
["Stack overflow"]
Example:
The maximum allowable number of defined global words has been exceeded.
Message:
This appendix gives basic information on using, configuring and directly accessing
the console in REBOL. It includes the following information:
C- 1
Console
Command Prompt
Command Prompt C
The default command line prompt is >>. You can change the prompt with code
such as:
Input:
The prompt can be a block that is evaluated each time. This line prints the current
time:
10:30 >>
The default result indicator is == and can be modified with a line such as:
These settings can be placed in the user.r file to make them permanent.
History Recall C
Each line typed into REBOL at the prompt is stored in a history block, and it can be
recalled later using the up and down arrow keys. For instance, pressing the up arrow
once recalls the prior input line.
The history block containing all input lines is accessed from the system console
object:
probe system/console/history
These lines can be put in the user.r file to save and reload your history
between REBOL sessions.
Busy Indicator C
When REBOL waits for a network operation to complete, a busy indicator appears
on screen to indicate that something is happening. You can change the indicator
with a line like:
system/console/busy: "123456789-"
Whe REBOL is running in quiet mode, te busy indicator will not be displayed.
The console provides "virtual terminal" capability that allows you to perform
operations such as cursor movement, cursor addressing, line editing, screen
clearing, control key input, and cursor position querying.
The console control sequences follow the ANSI standard. These features provide
you with the capability to write your own platform-independent terminal programs
such as text editors, email clients, or telnet emulators.
The console features apply to both input and output. On input, function keys will
be converted to multiple-character escape sequences. On output, multiple-character
escape sequences can be used to control the display of text in the console window.
Both the input and output sequences begin with the ANSI escape character, 27
decimal (1B hex). The next character in the sequence indicates the control keys on
input or the terminal control operation on output.
NOTE: The ANSI control characters are case-sensitive and normally require an upper
case character.
The special keys and second character in the sequence are included in the following
table:
There are several variations in the terminal control output character sequences.
Some command codes are preceded by a number (sent in ASCII) indicating that the
operation is to be performed the specified number of times. For example the cursor
motion command may be preceded by two numbers separated by a semicolon to
indicate the row and column position to move to. The cursor command characters
(upper case required) are included in the following table:
Table C-1. Terminal Output Sequence Examples
The following example moves the cursor to the right ten spaces:
print "^(1B)[10CHi!"
Hi
This example moves the cursor to the left seven spaces and clears the remainder of
the line:
To find the current console window size, you can use this example:
The above example opens the console, sends a control character to the input buffer
and copies the return value. It reads the value (screen dimensions) that is returned
after the control character and closes the console. The return value is the height and
width separated by a semicolon (;) and followed by an R. In the above example,
the screen is 33 high by 105 wide.
NOTE: Printing a character to the bottom-right corner of some terminals will cause a
new line, which will scroll the screen. Others will not. This inconsistency between
console terminal types must be considered when writing REBOL scripts intended to
be cross-platform.