REBOL

Rebol для программистов

Концепции, методы и примеры приложений R2 для разработчиков с другим опытом программирования
By: Nick Antonaccio
перевод: pochinok@bk.ru

Contents:

1. Установка и использование Rebol
1.1 Использование консоли Rebol
1.2 Встроенный редактор кода Rebol
1.3 Настройка параметров
2. Основы языка Rebol
2.1 Функции
2.2 Запуск полных программ в файлах и в консоли
2.3 Сохранение данных
2.4 Переменные
2.5 Условные оценки
2.6 Обработка ошибок
2.7 Конкатенация и многострочные строки
2.8 Списки
2.9 Циклы
2.10 Пользовательские интерфейсы
2.11 Пользовательские функции
2.12 Объекты
3. Диалекты и другие особенности Rebol
4. Некоторые практические примеры диалекта, файлов и списков графического интерфейса в Rebol
4.1 Создание базового приложения для контактов CRUD (create (создание), read (чтение), update (обновление), delete (удаление))
5. Ещё несколько примеров приложений
5.1 Калькулятор чаевых
5.2 Дни между двумя датами
5.3 Эффекты изображения
5.4 Отправить электронное письмо
5.5 Игра в плитку
5.6 Универсальный калькулятор
5.7 Орёл-решка
5.8 Дополнительные примеры приложений для изучения
6. Графика
6.1 Основы Rebol "Draw"
6.2 Несколько коротких приложений для рисования
7. Подробнее о серии - добавление дополнительных функций в приложение "Контакты"
7.1 Встроенная справка
8. Ещё несколько коротких приложений, использующих конструкции последовательностей и циклов
8.1 Слайд-шоу изображений
8.2 Гистограмма
8.3 Отчет Paypal
8.4 Игра Tric Trac
8.5 Список покупок и список дел
8.6 Календарь
8.7 Генератор Pig Latin
8.8 Марширующая армия пришельцев с логотипом
8.9 Игра Поймайка
8.10 Инструмент для гитарных аккордов и гамм
8.11 Дополнительные серии приложений для изучения
9. Создание веб-приложений с использованием REBOL CGI
9.1 HTML-формы и серверные скрипты - базовая модель CGI
9.2 -Стандартный шаблон компьютерной графики для запоминания
10. Примеры приложений CGI
10.1 Общее приложение CGI с HTML-формой
10.2 Фотоальбом CGI
10.3 -CGI текстовый чат
10.4 Типичное приложение с раскрывающимся списком
11. Больше основ Rebol
11.1 Типы данных
11.2 Разнообразие дополнительных примеров работы коротких серий
11.3 Строки
11.4 Управление файлами и чтение/запись из/в различные источники данных/протоколы
11.5 Подробнее о пользовательских функциях
11.6 Управление событиями с графическим интерфейсом
11.7 Больше различных примеров графического интерфейса, методов, виджетов (некоторые сетки) и т.д.
11.8 Встраивание файлов (изображений, звуков, двоичных исполняемых файлов и т.д.) в код
11.9 Запуск приложений командной строки
12. Порты
12.1 Порты электронной почты
12.2 Порты консоли
12.3 Звуковые и другие аппаратные порты
12.4 Сетевые порты
13. Файлы с общим кодом (DLL, So, библиотеки Dylib и т.д.)
14. Сторонние библиотеки
14.1 PDF
14.2 Конструктор Flash (.swf)
14.3 RebGUI
14.4 Меню Cyphre и панель вкладок
14.5 Henrik Listview
14.6 Система меню Ensel
14.7 r3D
14.8 MySQL
14.9 SQLite
14.10 Doc's Captcha
14.11 Irwin / Ensel Снимок экрана
14.12 XML и XML-RPC
14.13 Библиотека графиков и диаграмм Q-Plot
14.14 Rebzip
15. Функция синтаксического анализа Parse
16. Привязка меток слов к контекстам
17. Многозадачность (у Rebol нет потоков)
18. Подробнее о встроенной справке
19. Узнать больше - Интернет-ресурсы
19.1 Ссылки R3
19.2 Rebolforum.com
19.3 Rebol.org
19.4 Форумы и сообщество AltME

1. Установка и использование Rebol

Скачайте и установите интерпретатор Rebol/View по ссылке:

http://www.rebol.com/download-view.html

На всех платформах этот интерпретатор R2 (Rebol версия 2) меньше 1 мегабайта и требует менее минуты для настройки.

Используйте любой текстовый редактор для написания кода (например, Блокнот, Textmate, Emacs и т.д.). Интерпретатор R2 также имеет простой встроенный редактор кода.

Все программы Rebol должны начинаться с заголовка "REBOL []". Вставьте следующий код в пустой текстовый документ и сохраните его в файле с именем, заканчивающимся на ".r":

REBOL []
alert "Hello World"

Если у вас установлен Rebol, любой файл кода с расширением .r будет работать как исполняемая программа. Например, в Windows сохраните указанную выше программу на рабочем столе как "myapp.r", щёлкните значок myapp.r с помощью мыши, чтобы запустить её.

1.1 Использование консоли Rebol

Вы можете вставить простые фрагменты кода прямо в консоль интерпретатора Rebol (REPL):

  1. Щёлкните значок программы Rebol (по умолчанию находится на рабочем столе или в Пуск -> Программы -> Rebol)
  2. Нажмите кнопку "Консоль" в программе Rebol.
  3. Введите или вставьте свой код (текст) в мигающую командную строку.

Когда вы вставляете код в консоль, нет необходимости включать заголовок REBOL []. Однострочник, подобный приведённому выше примеру, можно вставить в консоль следующим образом:

alert "Hello World"

ПОПРОБУЙТЕ: Щёлкните значок программы Rebol. На главном экране Rebol "Viewtop" нажмите "User" (Пользователь) -> снимите флажок "Open Desktop on Startup" (Открывать рабочий стол при запуске) -> нажмите "Save" (Сохранить), и Rebol будет автоматически открываться в консоли при каждом запуске.

1.2 Встроенный редактор кода Rebol

Введите следующий код в консоль Rebol, и появится встроенный мини-текстовый редактор:

editor none

Чтобы отредактировать конкретный файл:

editor %filename.r

Нажмите клавишу [F5] на клавиатуре, и файл кода, который вы редактируете, будет сохранен и выполнен интерпретатором Rebol.

В редактор можно добавить несколько полезных функций, запустив эту строку при запуске консоли Rebol:

do http://re-bol.com/e

1.3 Настройка параметров

Сохраните файл кода как "rebol.r" в той же папке, что и интерпретатор Rebol, и он будет запускаться каждый раз при запуске Rebol. Вы можете создать файл rebol.r для инициализации параметров, таких как электронная почта и другие параметры учетной записи, или для запуска целых сценариев, таких как сценарий улучшения редактора выше, для автоматизации любых общих процедур запуска или для запуска любого другого настраиваемого кода инициализации. Чтобы перенести все свои персональные настройки на другой компьютер, просто скопируйте файл rebol.r.

2. Основы языка Rebol

Rebol не чувствителен к регистру ("print" и "PRINT" относятся к одной и той же функции). Пробел можно вводить где угодно, отступы не требуются, а окончания строк не требуются. Выражения, даже математические выражения, оцениваются слева направо, сверху вниз. Комментарии начинаются с точки с запятой. Блоки кода заключаются в квадратные скобки.

2.1 Функции

Круглые скобки вокруг аргументов функции не требуются:

print "Hello World"
alert "Hello World"  ; функция всплывающего окна с сообщением
request "Continue?"  ; всплывающее окно с запросом да/нет/отмены
request-text         ; функция запроса текста без аргументов
editor none          ; 'none - это версия 'null в Rebol

Поскольку отсутствуют требования к пробелам или окончанию строки, выражения можно размещать рядом друг с другом по желанию, без необходимости в дополнительном синтаксисе разделения:

alert "First function on this line" alert "Second function, same line"
alert "No"  alert "line"  alert "endings"  alert "are"  alert "required"
alert "functions are" editor "automatically grouped with their parameters"

В Rebol некоторые функции имеют необязательные "уточнения", которые позволяют использовать множество потенциально полезных параметров:

request-text/title  "The /title refinement sets this header text"
request-text/default "Default user text" 
request-text/title/default  "Name:"  "John Smith"     ; 2 параметра вместе
request-text/title/offset "/offset repositions the requester" 10x100

request-pass/offset/title 10x100 "title" alert "Processing"  ; 2 функции

request-file/file %temp.txt           ; имя файла по умолчанию
request-file/filter ["*.txt" "*.r"]   ; список файлов только с разширением .txt и .r
request-file/only                     ; ограничить выбор одним файлом
request-file/save                     ; диалог сохранения (вместо открытия)
request-file/save/file/only/filter %temp.txt ["*.txt" "*.r"]   ; 4 уточнения

Порядок вычисления всех функций и выражений Rebol всегда слева направо:

print   10  +  12  /  2   ;  22 / 2 = 11   Математика ВСЕГДА оценивается слева
print  (10  +  12) /  2   ;  22 / 2 = 11   направо. Единственное исключение:
print   10  + (12  /  2)  ;  10 + 6 = 16   Круглые скобки оцениваются первыми.

2.1.1 Возвращаемые значения

Вы можете взять возвращаемое значение любой функции и использовать его как параметр другой функции. Здесь значение, возвращаемое функцией 'now (текущая дата и время), используется в качестве параметра функции 'print:

print now

Точно так же вы можете взять возвращаемое значение функции request-text и сразу же сообщить об этом пользователю:

alert request-text

Обратите внимание, что до того, как функция предупреждения, указанная выше, сможет завершить свою работу, сначала необходимо вернуть значение из функции запроса текста. Из-за этого требования при запуске этого кода функция предупреждения временно приостанавливается, и первое, что видит пользователь, - это всплывающее окно с текстом запроса.

Вот несколько функций, каждая из которых полагается на возвращаемое значение следующей функции:

editor request request-text

2.2 Запуск полных программ в файлах и в консоли

Файлы кода Rebol всегда начинаются с заголовка REBOL [] в первой строке. Сохраните свои программы под любым именем файла с расширением ".r" и щёлкните значок файла, чтобы запустить его, или используйте встроенный редактор Rebol и нажмите F5, чтобы запустить отредактированный сценарий (или используйте сопоставимую функцию "выполнить с помощью" в вашем любимом редакторе/IDE). Вот небольшой пример программы:

REBOL []
print "Hello World!"
print "The current date and time is:"
print now
request-text/title "Enter some text to let me know what you think:"
alert "Thank you for sharing your thoughts!"

Когда вы запускаете простые примеры кода в консоли интерпретатора Rebol, вы увидите, что все возвращаемые значения функции распечатаны (функция "print" печати не требуется в консоли):

now

Чтобы запустить приведенный выше код как программу, сохраненную в файле кода, вы должны включить заголовок REBOL []. И в этом случае вы должны распечатать возвращаемое значение и завершить программу с помощью функции остановки. Функция "halt" останавливает закрытие интерпретатора, чтобы пользователь мог видеть выходные результаты:

REBOL []
print now
halt

2.3 Сохранение данных

Rebol имеет простую встроенную возможность хранить, извлекать и манипулировать данными в простых текстовых файлах. Чтобы сохранить данные на жесткий диск, флэш-накопитель, веб-сервер и т.д., используйте функцию записи "write". Перед именами файлов стоит символ процента (%):

write %mydata "This is some text that I want to save for later."

Чтобы получить текст позже, используйте функцию чтения "read". Вы можете использовать функцию печати "print" для печати форматированных данных, считанных из файла, или функцию проверки "probe" для просмотра необработанных данных без какого-либо форматирования:

print read %mydata

probe read %mydata

Вы можете читать и писать на серверы в Интернете точно так же, как вы читаете и записываете на локальные диски своего компьютера:

write ftp://user:pass@site.com/www/mydata.txt "text saved to a server"

read http://site.com/mydata.txt

Вы можете читать и записывать данные двоичного файла, такие как изображения, звуки, видео и т.д., используя уточнение "/binary":

read/binary http://rebol.com/bay.jpg

Для более сложного форматирования данных используйте функцию сохранения "save":

save %mycontacts ["John" "Bill" "Jane" "Ron" "Sue"]

save/png %myimage.png logo.gif

Чтобы загрузить сохраненные данные, используйте функцию "load" (загрузить):

probe load %mycontacts

probe load %myimage

probe load http://rebol.com/bay.jpg

Вы увидите, что Rebol предоставляет все необходимые возможности для поиска, сортировки, сравнения, комбинирования, добавления, удаления, изменения, загрузки, сохранения и иного управления постоянными данными. Для многих типов простых приложений системы баз данных могут быть заменены крошечным, на 100% портативным набором инструментов Rebol.

2.4 Переменные

В Rebol метки переменных создаются с помощью символа двоеточия:

name: "John"
alert name

Вы можете присвоить переменную (метку слова) данным, возвращаемым любой функцией:

name: request-text/title "Name:"
alert name

data: read %mydata
alert data

2.5 Условные оценки

Конструкция Rebol if/then имеет следующий формат: if (это) истина [делать это]. Скобки вокруг тестового выражения не требуются:

REBOL []
if (now/time = 8:00am) [alert "Time to wake up!"]
if account < $0 [alert "Your account is overdrawn."]

"Either" похож на вычисления if/else в других языках: if (это) истинно [сделай это] [иначе сделай это]. Отступ не требуется:

REBOL []
pass: request-text/title "Enter Password:"
either pass = "secret" [
    alert "Welcome back."
] [
    alert "Incorrect password."
]

"Case" можно использовать для выбора одного из множества действий, в зависимости от ситуации:

REBOL []
name: "john"
case [
    find name "a" [alert {Your name contains the letter "a"}]
    find name "e" [alert {Your name contains the letter "e"}]
    find name "i" [alert {Your name contains the letter "i"}]
    find name "o" [alert {Your name contains the letter "o"}]
    find name "u" [alert {Your name contains the letter "u"}]
    true [alert {Your name doesn't contain any vowels!}]
]

Уточнение "/all" функции case оценивает ВСЕ условия без нарушения:

REBOL []
name: "brian" 
found: false
case/all [
    find name "a" [print {Your name contains the letter "a"} found: true]
    find name "e" [print {Your name contains the letter "e"} found: true]
    find name "i" [print {Your name contains the letter "i"} found: true]
    find name "o" [print {Your name contains the letter "o"} found: true]
    find name "u" [print {Your name contains the letter "u"} found: true]
    found = false [print {Your name doesn't contain any vowels!}]
]

Также доступна структура переключателя "switch":

REBOL []
favorite-day:  request-text/title "What's your favorite day of the week?"
switch/default favorite-day [
    "Monday"    [alert "Monday is the worst!  The work week begins..."]
    "Tuesday"   [alert "Tuesdays and Thursdays are both ok, I guess..."]
    "Wednesday" [alert "The hump day - the week is halfway over!"]
    "Thursday"  [alert "Tuesdays and Thursdays are both ok, I guess..."]
    "Friday"    [alert "Yay!  TGIF!"]
    "Saturday"  [alert "Of course, the weekend!"]
    "Sunday"    [alert "Of course, the weekend!"]
] [alert "You didn't type in the name of a day!"]

"All - ярлык для множества" "and" оценок. "Any - это ярлык для нескольких" "or" оценок:

REBOL []

time: 12:30pm
drank-water: true
if ((time > 12:00pm) and (time < 1:00pm) and (drank-water = true)) [
    alert "You should take this opportunity to go to the bathroom"
]
if all [time > 12:00pm  time < 1:00pm  drank-water = true] [
    alert "You should take this opportunity to go to the bathroom"
]

x: 2  y: 3  z: 4
if ((x = 4) or (y = 4) or (z = 4)) [alert "One of the the values is 4"]
if any [x = 4  y = 4  z = 4] [alert "One of the the values is 4"]

2.6 Обработка ошибок

Для обработки ошибок используйте "if error? try". Поместите тестовый код в блок и следуйте за ним другим блоком кода для выполнения при возникновении ошибки:

if error? try [0 / 0] [alert "Divide by 0 error"]

Структура 'attempt запускает следующий блок, если в тестовом блоке нет ошибки:

if attempt [1 / 1] [alert "Successful"]

Функция "attempt" также может использоваться для полного игнорирования ошибок. В этом примере предпринимается попытка присвоить переменной "x" текст, прочитанный из file.txt. Если файл не существует, значение "x" остается равным пустой строке:

x: copy ""
attempt [x: read %file.txt]

2.7 Конкатенация и многострочные строки

Rebol использует функцию "rejoin" для объединения данных:

REBOL []
alert rejoin ["Current Date and Time: " now]

Многострочные строки заключаются в фигурные скобки:

REBOL []
print rejoin [
    {
        foo 1
        foo 2
    }
    {
        bar 1
        bar 2
    }
]

Чтобы обрезать лишнее пространство, можно использовать функцию обрезки "trim" и множество её усовершенствований:

REBOL []
print trim/auto rejoin [
    {
        foo 1
        foo 2
    }
    {
        bar 1
        bar 2
    }
]

Тип данных первой переменной используется для остальной части любого связанного блока данных:

REBOL []
name: request-text
birthday: request-date
clr: request-color
fl: request-file
alert rejoin [
    uppercase name ", your birthday, color and file choices were: "
    birthday ", " clr ", " fl ", AFTERNOON: "
    either now/time > 12:00pm ["yep"]["nope"]
]

2.8 Списки

Основная структура списка Rebol называется "сериями", и в Rebol есть ряд функций, которые позволяют добавлять, удалять, изменять, искать, сортировать, сравнивать, комбинировать, загружать, сохранять и иным образом манипулировать данными серий. Rebol использует одни и те же функции последовательностей при работе со списками практически любого типа данных. В Rebol управление символами в строках текста (списки символов), графикой на экране в игре (список изображений и координат в блоке рисования), данными, входящими и исходящими из сетевого порта, файлами на жестком диске, электронной почтой в почтовом ящике и т. д. все требуют знания только одного простого набора функций и единого образа мышления. Подход к работе со списками данных намного более согласован и использует гораздо более простой синтаксис, чем вы найдете в других языках (массивы, связанные списки и т.д.).

Базовая структура кода, используемая для хранения серий элементов данных в Rebol, называется "блоком". Просто заключите список элементов в квадратные скобки и присвойте ему метку переменной. Обратите внимание, что блоки кода обрабатываются как любые другие списки:

REBOL []
names: ["John" "Dave" "Jane" "Bob" "Sue"]
codes: [2804 9439 2386 9823 4217]
dates: [21-dec-2013 1-oct-2012 1-jan-2014]
files: [%employees %vendors %contractors %events]
code:  [print "Hello World!"]  ; список, содержащий 1 функцию и 1 строку

Вы можете выбирать (pick), находить (find), сортировать(sort) и иным образом управлять элементами из списка, используя простые функции и конструкции:

print pick names 3
print names/3
print find names "Dave"
print sort names
print sort codes
print sort dates
do code

Обратите внимание, что в приведенных выше примерах сортировки каждый тип данных автоматически сортируется соответствующим образом (имена по алфавиту, числа по порядку, даты в хронологическом порядке).

Сохраняйте и загружайте блоки данных с помощью функций сохранения "save" и загрузки "load":

REBOL []
names: ["John" "Dave" "Jane" "Bob" "Sue"]
save %mynames names
loaded-names: load %mynames
probe loaded-names

Наиболее часто используемые функции рядов: pick (выбор), find (поиск), at (в), index? (индекс?), length? (длина?), append (добавление), remove (удаление), insert (вставка), extract (извлечение), copy (копирование), replace (замена), select (выбор), sort (сортировка), reverse (реверс), head (начало), next (следующий), back (назад), last (последний), tail (хвост), skip (пропустить), change (изменить), poke (тыкать), clear (очистить), join (объединить), intersect (пересечь), difference (разность), exclude (исключить), union (объединить), unique (уникальный), empty? (пустой?), write (записать), read (прочитать), save (сохранить), load (загрузить).

Освоение функций серий и концепций манипуляции - один из основных навыков, необходимых для овладения Rebol.

2.9 Циклы

"Foreach" - это наиболее часто используемый тип цикла в Rebol:

REBOL []
names: ["John" "Dave" "Jane" "Bob" "Sue"]
foreach name names [alert name]

Как и в других языках, метки переменных в циклах произвольные:

REBOL []
n: ["John" "Dave" "Jane" "Bob" "Sue"]
foreach i n [alert i]

Вы часто будете выполнять условные оценки для выполнения некоторых операций с каждым элементом списка. Ещё раз обратите внимание, что Rebol автоматически распознает и знает, как выполнять соответствующие вычисления для определённых типов данных. Типы данных распознаются по заданному синтаксису ($44,92 - денежное выражение, 12-jan-2014 - дата, 19x38 - пара координат и т.д.):

REBOL []
names: ["John" "Dave" "Jane" "Bob" "Sue"]
foreach name names [
    if find name "j" [alert name]
]


REBOL []
dates: [21-dec-2013 1-oct-2012 1-jan-2014]
foreach date dates [
    if date > 31-dec-2013 [alert form date]
]

Вы можете структурировать данные в списке в виде строк и столбцов. Используйте foreach для перебора последовательно сгруппированных пар или групп любого количества элементов в строке. В приведенном ниже примере строки состоят из 3 столбцов сгруппированных значений, помеченных name (имя), address (адрес) и phone (телефоном) на каждой итерации цикла foreach:

REBOL []
mycontacts: [
    "John Smith" "123 Tomline Lane Forest Hills, NJ" "555-1234"
    "Paul Thompson" "234 Georgetown Pl. Peanut Grove, AL" "555-2345"
    "Jim Persee" "345 Pickles Pike Orange Grove, FL" "555-3456"
    "George Jones" "456 Topforge Court Mountain Creek, CO" ""
    "Tim Paulson" "" "555-5678"
]
foreach [name address phone] mycontacts [
    print name
]

Вы также можете использовать циклы "repeat" (повтор) и "for" (для) для подсчета длины элементов в списке. В этом примере для переменной счетчика "i" устанавливается значение от 1 до длины блока имен, увеличивая значение переменной на 1 каждый раз в цикле:

REBOL []
names: ["John" "Dave" "Jane" "Bob" "Sue"]
repeat i (length? names) [
    alert rejoin ["Name #" i ": " pick names i]
]


REBOL []
names: ["John" "Dave" "Jane" "Bob" "Sue"]
for i 1 length? names 1 [
    alert rejoin [
        "Current Name #" i ": " pick names i
        " Next Name: " pick names (i + 1)
    ]
]

Распознавание типов данных Rebol может быть полезно при запуске циклов for:

for counter 1 10 1 [print counter] 
for counter 10 1 -2 [print counter]   ; счёт в обратном порядке от 10 до 1 с шагом -2
for counter 10 100 10 [print counter] 
for counter 1 5 .5 [print counter] 
for timer 8:00am 9:00pm 0:05 [print timer] 
for dimes $0.00 $1.00 $0.10 [print dimes] 
for date 1-dec-2005 25-jan-2006 8 [print date]
for alphabet #"a" #"z" 1 [prin alphabet]

Цикл "forever" повторяется бесконечно, пока не встретится функция "break":

REBOL []
count: 99
forever [
    print rejoin [count " bottles of beer on the wall"]
    count: count - 1
    if count = 0 [break]
]

Также доступны структуры "While", "until", "loop", "forall", "forskip" и "remove-each", а также такие функции, как "extract" помогут для выполнения общих действий, обычно выполняемых с помощью циклов:

while [now/date < 21-jan-2014] [print "Press [ESC] to quit"]
until [now/date >= 21-jan-2014] [print "It's now January 21, 2014"]
loop 50 [print "REBOL is great!"]
x: [1 2 3 4 5 6 7]
forall x [probe first x]
forskip x 2 [probe first x]
remove-each y x [y > 5]
extract x 2
extract x 3
extract/index x 2 2

2.10 Пользовательские интерфейсы

2.10.1 Фоновые приложения

Приложения могут работать в фоновом режиме без отображения консоли или пользовательского интерфейса (т.е. выполнять запланированное обслуживание файлов, обновлять системные часы и т.д.).

2.10.2 Консольные приложения

Используйте функции "ask" (спросить) и "print" (напечатать), чтобы выполнить простой ввод-вывод с консоли:

REBOL []
user: ask "Username (iwu83):  "
pass: ask "Password (zqo72):  "
either (user = "iwu83") and (pass = "zqo72") [
    print rejoin [newpage "Welcome back"]
] [
    print rejoin [newpage "Incorrect Password"]
    halt
]
print "You're in..."
halt

2.10.3 Приложения с графическим интерфейсом

Окна графического интерфейса пользователя с кнопками, текстовыми полями, выпадающими списками и другими "виджетами" легко создать с помощью Rebol. Простой встроенный диалект кода для создания интерактивных графических интерфейсов пользователя использует слова "view layout" для создания макета окна. Блок содержит описания виджетов:

REBOL []
view layout [
    btn
    field
    text "REBOL is really pretty easy to program."
    text-list
    check
]

Вы можете настроить визуальные характеристики любого виджета в макете, добавив к каждому виджету соответствующие модификаторы:

view layout [
    btn red "Click Me"
    field 400 "Enter some text here"
    text font-size 16 "REBOL is really pretty easy to program." purple
    text-list 400x300 "line 1" "line 2" "another line"
    check yellow
]

Виджеты могут выполнять функции или любой код при нажатии или иным образом активации. Просто поместите функции в другой набор скобок после виджета:

view layout [
    btn "click me" [
        alert "You clicked the button."
    ]
]

Слово "value" (значение) относится к данным, содержащимся в активированном в данный момент виджете:

view layout [
    text "Some action examples.  Try using each widget:"
    button red "Click Me" [
        alert "You clicked the red button."
    ]
    field 400 "Type some text here, then press [Enter] on your keyboard" [
        alert value
    ]
    text-list 400x300 "Select this line" "Then this line" "Now this one" [
        alert value
    ]
    check yellow [alert "You clicked the yellow check box."]
    btn "Quit" [quit]    
]

В этом руководстве на примере будет гораздо больше рассказано о создании графического интерфейса пользователя.

2.10.4 Веб-приложения CGI

Rebol также предоставляет возможности CGI, так что сценарии могут запускаться на веб-сервере, принимать ввод из веб-форм HTML и печатать ответы HTML для отображения в веб-браузере пользователя. Сценарии CGI рассматриваются позже в этом руководстве.

2.11 Пользовательские функции

Создавайте пользовательские функции в Rebol со структурой кода "func". Новым функциям присваивается словесная метка с использованием символа двоеточия. Метки переменных для параметров данных включаются в блок после слова func:

REBOL []

triple: func [x] [
    print 3 * x
]

triple 4
triple 5
triple 6

alert "I just tripled the numbers 4 (12), 5 (15), and 6 (18)"

По умолчанию переменные, установленные в функциях, остаются доступными ГЛОБАЛЬНО:

unset 'y
triple-with-global-y: func [x] [
    y: 3 * x
    print y
]
triple-with-global-y 5
print y                         ; here, y = 15

Используйте уточнение "/local", чтобы сделать переменные локальными для функции:

unset 'y
triple-with-local-y: func [x /local y] [
    y: 3 * x
    print y
]
triple-with-local-y 5
print y                         ; here, y has no value

2.11.1 Возвращаемые значения

Последнее значение в определении функции - это её возвращаемое значение. Приведённая ниже функция проверки принимает список в качестве параметра (здесь помечен как lst) и проверяет, содержит ли он какие-либо плохие слова (здесь слова с символами "--"). Он начинается с установки переменной answer на "safe" (безопасно), затем использует цикл' foreach и 'условие' if, чтобы увидеть, есть ли "--" в каком-либо из элементов. Если в какой-то момент будут обнаружены плохие символы, переменной answer будет присвоено значение "unsafe" (небезопасно). В конце функции возвращается переменная answer. Затем функция запускается для списков names1 и names2, и пользователь получает предупреждение с возвращёнными результатами:

REBOL []
check: func [lst] [
    answer: "safe"
    foreach l lst [
        if find l "--" [answer: "unsafe"]
    ]
    answer
]
names1: ["Joe" "Dan" "Sh--" "Bill"]
names2: ["Paul" "Tom" "Mike" "John"]
alert rejoin ["The list " names1 " is " check names1]
alert rejoin ["The list " names2 " is " check names2]

Слово "return" также может использоваться для остановки функции и возврата значения в любой момент.

2.11.2 Библиотеки

Сохраните коллекции полезных функций в файл и импортируйте их функцией "do" (сделай). Если вы сохраните приведенный выше код функции в файл с именем "myfunctions.r", приведенная выше программа будет выглядеть следующим образом:

REBOL []
do %myfunctions.r
names1: ["Joe" "Dan" "Sh--" "Bill"]
names2: ["Paul" "Tom" "Mike" "John"]
alert rejoin ["The list " names1 " is " check names1]
alert rejoin ["The list " names2 " is " check names2]

Импортированные файлы можно читать из локальных файлов, сетевых URL-адресов, электронных писем, системного буфера обмена, баз данных и других источников данных:

do http://site.com/myfunctions.r
do read clipboard://
do first read pop://user:pass@site.com

Фактически вы можете включать в импортированные файлы любой код (а не только определения функций). Вы можете поместить всю указанную выше программу в файл на своем веб-сайте и запустить её, указав URL-адрес файла. Импорт файла с помощью "do" - это то же самое, что копирование и вставка содержимого файла в ваш код.

2.12 Объекты

Структуры объектного кода содержат коллекции переменных и функций. Определения виджетов GUI Rebol можно найти во встроенной библиотеке объектов "svv". Вы можете проверить объект "svv" с вопросительным знаком:

? svv

Rebol использует обозначение "пути" с косой чертой для обозначения функций и переменных в любом объекте (в большинстве других языков функции называются "методами" и используются символы точки для ссылки на элементы в объекте). Следующий код относится к объекту кнопки внутри части vid-styles библиотеки svv:

? svv/vid-styles/button

Вы можете использовать слово "do" для импорта библиотек объектного кода, находящегося в локальных файлах или по URL-адресам:

do %rebgui.r
do http://re-bol.com/rebgui.r
? ctx-rebgui

Если вы попытаетесь запустить последнюю строку выше перед импортом библиотеки rebgui, вы увидите, что иначе объект ctx-rebgui не существует. (Библиотека rebgui содержит весь язык графического интерфейса с некоторыми дополнительными функциями, которых нет во встроенной библиотеке svv Rebol).

2.12.1 Инкапсуляция кода в объектах

В приведенном ниже коде определены 2 новых объекта с метками "money" (деньги) и "place" (место). Функция "make" используется для создания объектов:

REBOL []
money: make object! [
    var: 1234.56
    bank: func [] [
        print ""
        print rejoin ["Your bank account balance is:  $" var]
        print ""
    ]
]
place: make object! [
    var: "Wabash"
    bank: func [] [
        print ""
        print rejoin [
            "Your favorite place is on the bank of the:  " var]
        print ""
    ]
]

Переменные с меткой "var" и функции с меткой "bank" в каждом вышеупомянутом объекте существуют и работают только в контексте (пространстве имен) каждого объекта. Посмотрите на результат этих строк:

money/bank
money/var
place/bank
place/var

2.12.2 Наследование

Вот пример проекта нового объекта, предназначенного для хранения информации об учетной записи пользователя. Он содержит несколько меток переменных, для которых установлено значение "none", и 2 определения функций, помеченных "email-address" и "display":

REBOL []
account: make object! [
    first-name: last-name: address: phone: none
    email-address: func [] [
        to-email rejoin [
            first-name "_" last-name "@website.com"
        ]
    ]
    display: func [] [
        print ""
        print rejoin ["Name:     " first-name " " last-name]
        print rejoin ["Address:  " address]
        print rejoin ["Phone:    " phone]
        print rejoin ["Email:    " email-address]
        print ""
    ]
]

Обратите внимание, что метка переменной "email-address" изначально назначается функции, которая создает адрес электронной почты по умолчанию, объединяя переменные имени и фамилии объекта с помощью "@website.com". Вы можете использовать либо это унаследованное определение электронной почты по умолчанию, либо переопределить его, назначив фактическое конкретное значение адреса электронной почты. Если вы переопределите значение по умолчанию для "email-address", функция адреса электронной почты больше не существует в этом конкретном объекте - она будет перезаписана указанным значением электронной почты. Ниже приведены некоторые экземпляры указанного выше объекта. Каждый экземпляр создает новый помеченный экземпляр определения объекта "account" выше, заполненный значениями данных по умолчанию и/или указанными значениями:

Dave: make account []

John: make account [
    first-name: "John"
    last-name: "Smith"
    phone:  "555-4321"
]

Bob: make account [
    first-name: "Bob"
    last-name: "Jones"
    address: "4321 Street Place Cityville, USA 54321"
    phone:  "555-1234"
    email-address: "bob@mysite.net"
]

Вы можете распечатать все данные, содержащиеся в каждом объекте, запустив функцию отображения каждого объекта. Обратите особое внимание на значение адреса электронной почты в каждом объекте:

Dave/display
John/display
Bob/display

Взгляните на код объекта "btn" по умолчанию в "svv". Вы увидите, что это просто большая коллекция меток переменных, функций и других определений объектов:

editor svv/vid-styles/btn

Вот объект красной кнопки, созданный из общего объекта svv/vid-styles/btn, описанного выше. Всё в этой кнопке точно такое же, как и в общем объекте "btn" в "svv", за исключением того, что свойство "color" было изменено на красный. Обратите внимание, что функция "make" используется для создания объекта "redbtn" из родительского объекта "btn" в svv/vid-styles:

REBOL []
redbtn: make svv/vid-styles/btn [color: red]
editor redbtn

Вот пример кода, который создает объект "redbtn" выше, добавляет его в "svv" (вместе с меткой "redbtn"), а затем использует новый объект "redbtn" в макете окна:

REBOL []
append svv/vid-styles 'redbtn
redbtn: make svv/vid-styles/btn [color: red]
append svv/vid-styles redbtn
view layout [redbtn]

Вот новый объект коричневой кнопки, который расширяет объект "redbtn" так, что он выполняет одно дополнительное действие, не найденное в исходном определении красной кнопки. Переопределите значение цвета и расширите его определение, добавив к нему новую функцию, используя тот же формат кода, что и выше:

tanbtn: make svv/vid-styles/redbtn [
    color: tan
    size: 400x50
    action: func [] [alert "I've been clicked"]
]

Вот пример программы, которая создает объекты "redbtn" и "bluebtn" выше, добавляет их в svv, а затем использует их в макете окна:

REBOL []

append svv/vid-styles 'redbtn
redbtn: make svv/vid-styles/btn [
    color: red
    size: 200x50
]
append svv/vid-styles redbtn

append svv/vid-styles 'tanbtn
tanbtn: make svv/vid-styles/redbtn [
    color: tan
    size: 400x50
    action: func [] [alert "I've been clicked"]
]
append svv/vid-styles tanbtn

view layout [
    redbtn "Click me and nothing happens"
    redbtn "I'm just another red button object"
    tanbtn "Click me and my default message appears"
    tanbtn "I'm just another tan button object"
]

Код, создающий объекты "redbtn" и "tanbtn", можно сохранить в отдельном файле с именем, например, "newbtns.r":

REBOL []
append svv/vid-styles 'redbtn
redbtn: make svv/vid-styles/btn [
    color: red
    size: 200x50
]
append svv/vid-styles redbtn
append svv/vid-styles 'tanbtn
tanbtn: make svv/vid-styles/redbtn [
    color: tan
    size: 400x50
    action: func [] [alert "I've been clicked"]
]
append svv/vid-styles tanbtn

Затем любой, кто хочет использовать объекты красной и коричневой кнопок, может просто импортировать и использовать такие определения, как это:

REBOL []
do %newbtns.r
view layout [
    redbtn "Click me and nothing happens"
    redbtn "I'm just another red button object"
    tanbtn "Click me and my default message appears"
    tanbtn "I'm just another tan button object"
]

3. Диалекты и другие особенности Rebol

Rebol имеет специальную встроенную возможность создавать "диалекты", чтобы УПРОСИТЬ практически любой вид кодирования. Например, код, который вы видели ранее для создания небольшого макета графического интерфейса, является диалектом Rebol. Он использует специально разработанный синтаксис, который скрывает большую часть сложности объектов, процедур рисования, функций управления событиями (действия, которые происходят при щёлчке мышью, при закрытии экрана и т.д.) В удобном для чтения/написать мини-язык, разработанный специально для создания графических интерфейсов. На самом деле вам не нужно ничего понимать об объектах и ​​структуре функций в svv-объекте Rebol, чтобы создавать полезные экранные изображения. Анализатор диалекта графического интерфейса пользователя преобразует простой код макета в сложный код более низкого уровня, состоящий из объектов и других более сложных структур кода. Например, одна функция диалекта графического интерфейса пользователя позволяет пользователям создавать новые объекты виджетов, используя слово "style" (стиль). На диалекте графического интерфейса Rebol вы создаёте и используете красную кнопку размером 400x50 пикселей, которая всегда предупреждает пользователя о том, что по ней был нажат (для использования этого кода не требуется никакого формального понимания объектов):

REBOL []
view layout [
    style redbtn btn red 400x50 [alert "clicked"]
    redbtn "button 1"
    redbtn "button 2"
]

Этот код действительно настолько лаконичен, насколько это возможно - намного проще, чем беспорядок определений объектов, который вы видели в предыдущем разделе. Внутренне приведённый выше диалектный код преобразуется в более сложные объекты нижнего уровня, функции и переменные конструкции, которые пользователю диалекта никогда не нужно видеть.

Rebol был разработан с учётом создания диалектов как фундаментального подхода к написанию кода. Он предоставляет функцию синтаксического анализа "parse" и набор ключевых языковых функций, которые упрощают создание диалектов, снижающих сложность кода до минимально возможных уровней простоты. Разработчики диалектов могут создавать специализированные структуры кода, которые переводятся в гораздо более сложные внутренние операции под капотом, и выполнять огромные объёмы вычислительной деятельности, используя самый короткий, простой в использовании синтаксис самого высокого уровня. Это одна из основных причин, почему код Rebol всегда кажется настолько коротким и простым по сравнению с примерами на других языках. Встроенная функция синтаксического анализа "parse" позволяет создавать полные мини-языки, которые резко снижают сложность кодирования шаблонов синтаксиса, необходимых для решения проблем, специфичных для предметной области. Диалекты были созданы для решения множества распространённых ситуаций и задач программирования, и Rebol созрел для создания диалектов, связанных с любыми новыми проблемами, которые могут возникнуть в будущем.

Другие функции Rebol включают:

  1. Повсеместный последовательный подход, используемый для управления списками всех типов: файлами, строками, учетными записями электронной почты, данными в сетевых портах и ​​т.д., с использованием одних и тех же функций и образа мышления.
  2. Простые функции сохранения данных, такие как "read" (чтение), "write" (запись), "save" (сохранение) и "load" (загрузка), которые, наряду со всеми стандартными последовательными функциями, устраняют необходимость в системах баз данных сторонних производителей.
  3. Множество встроенных типов данных, которые автоматически распознаются и обрабатываются соответствующим образом. Не только числа и текст, но и даты, время, денежные суммы, координаты, IP-адреса и т.д. могут быть вычислены, отсортированы, оценены и т.д. без какого-либо специального форматирования. Это распознавание сложных типов данных также важно при разработке диалектных правил.
  4. Полное отсутствие всего ненужного синтаксиса (точки с запятой, запятые, отступы, кавычки и т.д.), так что код может читаться более естественно, просто и без беспорядка.
  5. Встроенная способность рисовать графику, отображать изображения и создавать элементы графического интерфейса с событиями, таймерами и т.д.
  6. Собственный доступ к сетевым портам, файлам и другим источникам данных.
  7. Встроенный доступ к Интернет-протоколам, таким как HTTP, FTP, электронная почта и т.д.
  8. Встроенная возможность анализировать такие форматы, как .csv, HTML, XML и другие.
  9. Собственный доступ к системам баз данных.
  10. Естественная интерактивность между всеми этими фундаментальными вычислительными возможностями и возможность создавать новые типы данных (такие как JSON, PDF, Flash и т.п.) и использовать их с простыми последовательными функциями и диалектами, которые построены с использованием шаблонов синтаксиса, которые максимально просты и понятны.

4. Некоторые практические примеры диалекта, файлов и списков графического интерфейса в Rebol

Создайте окно с кнопкой:

rebol []
view layout [
    btn "Click Me"
]

Когда кнопка нажата, сделаем что-нибудь:

rebol []
view layout [
    btn "Click Me" [alert "Hello World"]
]

Окно с кнопкой и полем для ввода текста с надписью "f":

rebol []
view layout [
    btn "Click Me"
    f: field
]

Когда кнопка нажата, предупредите пользователя текстом, который в данный момент находится в поле "f" . Попробуйте ввести что-нибудь в поле и нажмите кнопку:

rebol []
view layout [
    f: field "Type here, then click the button"
    btn "Click Me" [alert f/text]
]

Когда кнопка нажата, запишите содержимое поля в файл mytext.txt, затем предупредите пользователя, что файл был сохранен:

rebol []
view layout [
    f: field "Type here, then click the button"
    btn "Click Me" [
        write %mytext.txt f/text
        alert "Saved"
    ]
]

Добавьте ещё одну кнопку, чтобы прочитать содержимое файла обратно в поле. Теперь вы можете закрыть программу, запустить ее снова и получить сохраненный текст. Обратите внимание, что каждый раз, когда вы меняете что-либо в графическом интерфейсе, вы должны обновить отображение с помощью функции show:

rebol []
view layout [
    f: field 
    btn "Save" [
        write %mytext.txt f/text
        alert "Saved"
    ]
    btn "Load" [
        f/text: read %mytext.txt
        show f
    ]
]

Та же самая программа, за исключением виджета с текстовой областью вместо однострочного поля. Простой текстовый редактор:

rebol []
view layout [
    a: area
    btn "Save" [
        write %mytext.txt a/text
        alert "Saved"
    ]
    btn "Load" [
        a/text: read %mytext.txt
        show a
    ]
]

Здесь текст добавляется к mylist.txt. Вместо того, чтобы каждый раз перезаписывать содержимое файла, каждая новая операция записи добавляет в файл дополнительную строку. Функция "rejoin" объединяет текст и новую строку (возврат каретки), так что каждая запись появляется в отдельной строке в сохраненном файле:

rebol []
view layout [
    f: field "Enter some lines here..."
    btn "Save" [
        write/append %mylist.txt rejoin [f/text newline]
        alert "Saved"
    ]
    a: area "The contents of the file will appear here when loaded..."
    btn "Load" [
        a/text: read %mylist.txt
        show a
    ]
]

Отобразите список в макете графического интерфейса с помощью виджета текстового списка "text-list":

rebol []
mylist: ["John" 2804 "Dave" 9439 "Jane" 2386 "Bob" 9823 "Sue" 4217]
view layout [
    text-list data mylist
]

Создайте пустой список с помощью "copy []". Добавить элементы в список с помощью 'append' - это создает новый список, содержащий только имена из исходного списка:

rebol []
mylist: ["John" 2804 "Dave" 9439 "Jane" 2386 "Bob" 9823 "Sue" 4217]
names: copy []
foreach [n c] mylist [append names n]
view layout [
    t: text-list data names
]

Выбранный элемент в текстовом списке обозначается как "/picked":

rebol []
mylist: ["John" 2804 "Dave" 9439 "Jane" 2386 "Bob" 9823 "Sue" 4217]
names: copy []
foreach [n c] mylist [append names n]
view layout [
    t: text-list data names [alert t/picked]
]

"index" - это числовое расположение элемента в списке:

rebol []
mylist: ["John" 2804 "Dave" 9439 "Jane" 2386 "Bob" 9823 "Sue" 4217]
names: copy []
foreach [n c] mylist [append names n]
view layout [
    t: text-list data names [alert form index? find mylist t/picked]
]

Выберите следующий элемент в списке (в данном случае номер выбранного имени). В приведённом ниже списке примеров каждое числовое значение всегда находится в следующей позиции индекса после имени (т.е. "Джейн" находится в позиции 5 в списке примеров, её номер 2386 находится в позиции 6). В коде это рассматривается как 1 + (позиция Джейн):

rebol []
mylist: ["John" 2804 "Dave" 9439 "Jane" 2386 "Bob" 9823 "Sue" 4217]
names: copy []
foreach [n c] mylist [append names n]
view layout [
    t: text-list data names [
        alert form pick mylist (1 + index? find mylist t/picked)
    ]
]

4.1 Создание базового приложения для контактов CRUD (create (создание), read (чтение), update (обновление), delete (удаление))

Здесь та же идея, что и выше, но с большим количеством полей данных для каждого имени. Значения Name, Address и Phone можно найти в позициях Name, Name + 1 и Name + 2:

rebol []
mycontacts: [
    "John Smith" "123 Tomline Lane Forest Hills, NJ" "555-1234"
    "Paul Thompson" "234 Georgetown Pl. Peanut Grove, AL" "555-2345"
    "Jim Persee" "345 Pickles Pike Orange Grove, FL" "555-3456"
    "George Jones" "456 Topforge Court Mountain Creek, CO" ""
    "Tim Paulson" "" "555-5678"
]
names: copy []
foreach [name address phone] mycontacts [append names name]
view layout [
    t: text-list data names [
        alert rejoin [
            "Name: "
            t/picked
            " Address: "
            pick mycontacts (1 + index? find mycontacts t/picked)
            " Phone: "
            pick mycontacts (2 + index? find mycontacts t/picked)
        ]
    ]
]

Вместо того, чтобы предупреждать некоторый присоединенный текст, отобразите каждый элемент данных в текстовом поле ввода:

rebol []
mycontacts: [
    "John Smith" "123 Tomline Lane Forest Hills, NJ" "555-1234"
    "Paul Thompson" "234 Georgetown Pl. Peanut Grove, AL" "555-2345"
    "Jim Persee" "345 Pickles Pike Orange Grove, FL" "555-3456"
    "George Jones" "456 Topforge Court Mountain Creek, CO" ""
    "Tim Paulson" "" "555-5678"
]
names: copy []
foreach [name address phone] mycontacts [append names name]
view g: layout [
    t: text-list data names [
        n/text: t/picked
        a/text: pick mycontacts (1 + index? find mycontacts t/picked)
        p/text: pick mycontacts (2 + index? find mycontacts t/picked)
        show g
    ]
    text "Name:"
    n: field
    text "Address:"
    a: field
    text "Phone:"
    p: field
]

Добавьте элементы в блок (данные, отображаемые в текстовом списке), введя текст в виджеты полей:

rebol []
contacts: copy []
names: copy []
foreach [name address phone] contacts [append names name]
view g: layout [
    t: text-list data [] [
        n/text: copy t/picked
        a/text: copy pick contacts (1 + index? find contacts t/picked)
        p/text: copy pick contacts (2 + index? find contacts t/picked)
        show g
    ]
    text "Name:"
    n: field
    text "Address:"
    a: field
    text "Phone:"
    p: field
    btn "Add" [
        append contacts reduce [copy n/text copy a/text copy p/text]
        names: copy []
        foreach [name address phone] contacts [append names name]
        t/data: copy names
        show t
    ]
]

Используйте функцию для инкапсуляции дублированного кода:

rebol []
extract-names: func [] [
    names: copy []
    foreach [name address phone] contacts [append names name]
    copy names
]
contacts: copy []
view g: layout [
    t: text-list data [] [
        n/text: copy t/picked
        a/text: copy pick contacts (1 + index? find contacts t/picked)
        p/text: copy pick contacts (2 + index? find contacts t/picked)
        show g
    ]
    text "Name:"
    n: field
    text "Address:"
    a: field
    text "Phone:"
    p: field
    btn "Add" [
        append contacts reduce [copy n/text copy a/text copy p/text]
        t/data: extract-names
        show t
    ]
]

Загрузим список из файла с помощью "load" и присвойте ему метку переменной. Сохраним список в файл с помощью "save". Создаём пустой файл, используя write/append "" (если файл уже существует, ничего не записывается):

rebol [title: "Contacts"]
write/append %contacts ""
contacts: load %contacts
extract-names: func [] [
    names: copy []
    foreach [name address phone] contacts [append names name]
    copy names
]
extract-names
view g: layout [
    t: text-list data names [
        n/text: copy t/picked
        a/text: copy pick contacts (1 + index? find contacts t/picked)
        p/text: copy pick contacts (2 + index? find contacts t/picked)
        show g
    ]
    text "Name:"
    n: field
    text "Address:"
    a: field
    text "Phone:"
    p: field
    across
    btn "Add" [
        append contacts reduce [copy n/text copy a/text copy p/text]
        t/data: extract-names
        show t
    ]
    btn "Save" [save %contacts contacts]
]

Обратите внимание, что заголовок "Contacts" был добавлен в заголовок программы выше, который отображается в строке заголовка окна графического интерфейса пользователя.

Пока что эта программа фактически только создает и читает, но мы скоро добавим к ней дополнительные сведения.

5. Ещё несколько примеров приложений

5.1 Калькулятор чаевых

Это приложение рассчитывает общую сумму, включая чаевые, для оплаты обеда в ресторане:

  1. Создается макет окна. Он содержит 3 виджета текстовых полей, помеченных "f", "t" и "x".
  2. Поля "f" и "t" содержат некоторые значения по умолчанию в деньгах и чаевых (9 долларов и 0,2 (20 процентов)).
  3. Когда значение вводится пользователем в поле "t", текст поля "x" устанавливается равным значению, вычисленному путем умножения денежного значения поля "f" на десятичное значение поля "t" + 1 (т.е. общая сумма для оплаты для банкноты 9 долларов это (9 долларов умножить на 1,2)). Отображение виджета "x" обновляется функцией "show":
REBOL [title: "Tip Calculator"]
view layout [
    f: field "$9"
    t: field ".2" [
        x/text: (to-money f/text) * (1 + (to-decimal t/text))
        show x
    ]
    x: field
]

5.2 Дни между двумя датами

Это приложение отображает количество дней между любыми двумя выбранными датами:

  1. Создается макет окна. Он содержит 2 кнопки, текстовый виджет с текстом "Дни между:" и поле ввода текста с меткой "f".
  2. Когда нажимается первая кнопка, для ее текста устанавливается дата, запрошенная пользователем. Выбранному значению даты также присваивается метка переменной.
  3. При нажатии второй кнопки для текста на лице устанавливается другая дата, запрошенная пользователем. Этому значению также присваивается метка переменной "e". Затем текст поля "f" устанавливается на разницу между двумя датами (e - s), и отображение обновляется функцией "show".
REBOL [title: "Days Between"]
view layout [
    btn 200 "Start" [face/text: s: request-date]
    btn 200 "End" [
        face/text: e: request-date
        f/text: e - s
        show f
    ]
    text "Days Between:"
    f: field
]

5.3 Эффекты изображения

Это приложение позволяет пользователям применять к изображению выбранные эффекты:

  1. Создается макет окна. Он содержит виджет изображения с надписью "pic" и текстовый список.
  2. Данные в текстовом списке представляют собой множество встроенных эффектов, которые Rebol изначально знает, как применять к изображениям.
  3. Когда значение выбирается из текстового списка, для свойства "/effect" изображения "pic" устанавливается это выбранное значение, и изображение обновляется с помощью функции "show".
REBOL [title: "Image Effects"]
view layout [
    pic: image load http://re-bol.com/palms.jpg
    text-list data [
        "Invert" "Grayscale" "Emboss" "Blur" "Sharpen" "Flip 1x1"
        "Rotate 90" "Tint 83" "Contrast 66" "Luma 150" "None"
    ][
        pic/effect: to-block value
        show pic
    ]
]

5.4 Отправить электронное письмо

Эта программа позволяет пользователям отправлять сообщения электронной почты.

  1. Программа запускается с установки 5 необходимых системных переменных: настроек почтового сервера POP и SMTP пользователя, имени пользователя и пароля учётной записи, а также адреса электронной почты. Эти значения должны быть отредактированы, чтобы они содержали правильные настройки учётной записи электронной почты, чтобы электронные письма действительно отправлялись программой.
  2. Создается макет окна. Он содержит поле ввода текста с меткой "f", многострочную текстовую область с меткой "a", кнопку "Send" (отправить) и 2 текстовых виджета, чтобы сообщить пользователю, что вводить в поле, и виджеты области ("Электронная почта:" и "Message:" (сообщение)).
  3. Пользователи вводят адрес электронной почты получателя и сообщение для отправки.
  4. При нажатии кнопки "Send" выполняется функция "send". Параметры функции отправки - это адрес электронной почты, полученный из текста, введенного в поле "f", и многострочный текст, введенный в область "a". После того, как электронное письмо было отправлено, пользователь получает уведомление с текстом "Sent".
REBOL [title: "Send Email"]
system/schemes/pop/host: "pop.server1" 
system/schemes/default/host: "smtp.server1" 
system/schemes/default/user: "username"
system/schemes/default/pass: "password1" 
system/user/email: you@site.com
view layout [
    text "Email:"
    f: field "joe@site.com" 
    text "Message:"
    a: area
    btn "Send" [
        send to-email f/text a/text
        alert "Sent"
    ]
]

Попробуйте отредактировать эту программу так, чтобы она позволяла пользователю устанавливать настройки электронной почты по умолчанию без необходимости редактировать какой-либо программный код (вы можете найти несколько таких рабочих примеров на http://re-bol.com/examples.txt)

5.5 Игра в плитку

Приведённый ниже код создаёт игру с плитками. Щёлкните любой фрагмент плитки, чтобы переместить его в пустое место. Переставьте плитки в порядке возрастания:

  1. Создается макет окна графического интерфейса пользователя.
  2. Слово "style" (стилm) на диалекте графического интерфейса Rebol используется для создания нового красного прямоугольного объекта с меткой "t". Всякий раз, когда пользователь щёлкает виджет "t", происходят три действия: метка "x" устанавливается на текущее "offset" (смещение) (положение координат) бокса, положение координат бокса устанавливается в положение виджета "e" и виджета "e" позиция изменится на позицию "x". Эти три действия вместе эффективно меняют позиции окна, на котором щёлкнули, и виджета "e" (как вы увидите ниже, виджет с меткой "e" - это просто виджет простого окна, который отображается как пустое пространство в макете окна).
  3. Слово "across" (поперёк) на диалекте графического интерфейса Rebol используется для размещения каждого последовательного виджета в окне поперёк экрана (вместо одного под другим, каждый на новых строках, что является поведением по умолчанию, которое вы видели до сих пор в макетах графического интерфейса).
  4. Слово "return" (возврат) на диалекте графического интерфейса Rebol используется для начала новой "строки" виджетов (аналогично тому, как возврат каретки используется для начала новой строки в текстовом документе).
  5. К строкам макета окна добавляется куча виджетов "t box" вместе с последним виджетом "t box" с меткой "e". Каждый раз, когда вы щёлкаете красный прямоугольник, его положение меняется на пустое.
REBOL [title: "Tile Game"] 
view layout [ 
     style t box red [
         x: face/offset
         face/offset: e/offset 
         e/offset: x
     ] 
     across 
     t "8"  t "7"  t "6"  return 
     t "5"  t "4"  t "3"  return 
     t "2"  t" 1"  e: box 
]

5.6 Универсальный калькулятор

Ниже представлено приложение-калькулятор. Большая часть кода должна иметь смысл.

  1. Окно графического интерфейса создается.
  2. Слово "across" (поперёк) используется для размещения каждого последовательного виджета в окне поперёк экрана.
  3. Компоновка окна включает поле с надписью "f". Его размер составляет 225x50 пикселей, а размер шрифта отображаемого на нем текста - 25.
  4. Слово "style" (стилm) используется для создания нового объекта кнопки с именем "b", который имеет размер 50x50 пикселей и который добавляет текст лицевой стороны текущей кнопки к тексту виджета поля "f" при каждом нажатии одной из кнопок "b".
  5. В макет окна добавляется группа кнопок "b", каждая из которых отображает различное число или математический оператор. Слово "return" используется для начала новой строки кнопок.
  6. Кнопка "=" пытается ("attempts") установить для текста поля "f" значение, которое приводит к "выполнению" ("do") (оценке) текущего математического выражения, отображаемого в поле "f".
REBOL [title: "Calculator"]
view layout [ 
     across 
     f: field 225x50 font-size 25  return 
     style b btn 50x50 [append f/text face/text show f] 
     b "1"  b "2"  b "3"  b " + "  return 
     b "4"  b "5"  b "6"  b " - "  return 
     b "7"  b "8"  b "9"  b " * "  return 
     b "0"  b "."  b " / "  b "=" [ 
         attempt [f/text: form do f/text show f] 
     ] 
]

Попробуйте создать то же приложение на любом другом языке программирования, и вы увидите, что нет ничего проще, чем диалектный подход Rebol к созданию оконных программ. Однако идея использования производных объектов виджета GUI, меток переменных, функций рядов и вычисляемых выражений универсальна для создания аналогичного приложения-калькулятора с использованием любого языка/инструмента программирования.

5.7 Орёл-решка

При нажатии кнопки в этом приложении происходит случайное переключение между изображением орла и решки:

  1. Два изображения загружаются с указанных URL-адресов в Интернете. Ярлык "h" присваивается загруженному изображению орла. Ярлык "t" присваивается загруженному изображению решки.
  2. Функция random с уточнением "/seed" используется для запуска генератора случайных чисел Rebol с использованием текущего времени (обычно уникального значения), так что уникальные случайные значения могут быть сгенерированы с помощью функции random. Каждый раз, когда вы хотите сгенерировать случайные числа, текст или другие случайные значения, эту стандартную строку кода следует включить в вашу программу.
  3. Создается макет окна с надписью "g". Он содержит виджет изображения с меткой "i", который первоначально отображает изображение "h" (изображение орла монеты), виджет ввода текстового поля с меткой "f" и кнопку, отображающую текст "Flip". Когда кнопка нажата, она устанавливает текст поля 'f на первый элемент в произвольно упорядоченном списке из 2 текстовых строк "Голова" и "Решка" (подбросить).
  4. Затем выполняется любая условная оценка. Если текст в поле "f" - "Heads" (это случайное состояние было определено на предыдущем шаге), тогда значение изображения виджета "i" устанавливается на изображение "h" (изображение орла). В противном случае (то есть, если текст в поле "f" - "Tails"), тогда изображение в виджете "i" устанавливается в "t" (изображение решки).
  5. Дисплей (помеченный "g") обновляется с помощью функции "show".

REBOL [title: "Coin Flip"] h: load http://re-bol.com/heads.jpg t: load http://re-bol.com/tails.jpg random/seed now view g: layout [

i: image h
f: field
btn "Flip" [
    f/text: first random ["Heads" "Tails"]
    either f/text = "Heads" [i/image: h] [i/image: t] 
    show g
]

]

5.8 Дополнительные примеры приложений для изучения

Вот ещё несколько коротких примеров приложений. Обратите внимание, какие фрагменты кода являются метками переменных, виджетами макета графического интерфейса пользователя, условными оценками и т.д..

Редактор веб-страниц:

REBOL [title: "Web Page Editor"]
view layout [
    f: field 600 "ftp://user:pass@site.com/public_html/page.html"
    a: area 600x350 
    across 
    btn "Load" [a/text: read to-url f/text  show a]
    btn "Save" [write to-url f/text a/text  alert "Saved"]
]

Вот приложение для опроса пользователей по основным математическим фактам. Попробуйте изменить его на вычитание, умножение и деление викторины на выбранные диапазоны случайных чисел (то есть вычитание чисел от 1 до 100 или умножение на числа от 1 до 12):

REBOL [title: "Math Test"]
random/seed now
x: func [] [rejoin [random 10 " + " random 20]]
view layout [
    f1: field x
    text "Answer:"
    f2: field [
        alert either f2/text = form do f1/text ["Yes!"]["No"]
        f1/text: x  show f1  focus f2
    ]
]

Попробуйте изменить это, чтобы генерировать оскорбления:

REBOL [title: "Compliment Generator"]
random/seed now
view layout [
    x: area "brilliant rare unique talented exceptional"
    y: area "genius champion winner success achiever"
    btn "Compliment" [
        alert rejoin [
            "You're a "
            first random parse x/text none " "
            first random parse y/text none "!"
        ]
    ] 
]

Полезный инструмент для веб-разработчиков, который позволяет вам выбирать и редактировать файлы в папке на вашем FTP-сервере:

REBOL [title: "FTP Tool"]
view  layout [
    f: field 600 "ftp://user:pass@site.com/public_html/" [
        either dir? to-url value [
            t/data: sort read to-url value 
            show t
        ][
            editor to-url value
        ]
    ]
    t: text-list 600x400 [editor to-url join f/text value]
]

6. Графика

6.1 Основы Rebol "Draw"

Чтобы рисовать графику, поместите виджет коробки ("box") в макет ("layout") графического интерфейса пользователя, за которым следует блок эффекта ("effect"), содержащий 1 или несколько команд рисования ("draw"):

rebol []
view layout [
    box 400x400 effect [
        draw [
            line 10x39 322x211
        ]
    ]
]

Команды рисования содержатся внутри БЛОКА:

rebol []
view layout [
    box 400x400 black effect [
        draw [
            line 0x400 400x50
            circle 250x250 100
            box 100x20 300x380
            curve 50x50 300x50 50x300 300x300
            spline closed 3 20x20 200x70 150x200
            polygon 20x20 200x70 150x200 50x300
        ]
    ]
]

Так, например, вы можете использовать цикл "foreach" для добавления элементов на экран. Мы добавим команды рисования к блоку "/effect/draw" объекта, помеченного "b" (в данном случае, прямоугольного виджета, на котором рисуется):

rebol [title: "Drawing Animation"]
shapes: [
    [line 0x400 400x50]
    [circle 250x250 100]
    [box 100x20 300x380]
    [curve 50x50 300x50 50x300 300x300]
    [spline closed 3 20x20 200x70 150x200]
    [polygon 20x20 200x70 150x200 50x300]
]
view layout [
    b: box 400x400 black effect [draw []]
    btn "Animate Drawing" [
        foreach g shapes [
            append b/effect/draw g
            show b
            wait 1
        ]
    ]
]

Или используйте виджеты, чтобы внести изменения в данные в блоке рисования. Этот код изменяет значения "x" и "y" переменной "pos" (положение круга), а затем обновляет отображение "b", используя функцию "show":

rebol [title: "Animated Circle"]
pos: 200x200
view layout [
    b: box 400x400 black effect [
        draw [circle pos 20]
    ]
    across
    btn "Up"    [pos/y: pos/y - 10 show b]
    btn "Down"  [pos/y: pos/y + 10 show b]
    btn "Right" [pos/x: pos/x + 10 show b]
    btn "Left"  [pos/x: pos/x - 10 show b]
]

Вот тот же пример снова с использованием клавиш управления курсором:

rebol [title: "Keyboard Controlled Animated Circle"]
pos: 200x200
view layout [
    b: box 400x400 black effect [
        draw [circle pos 20]
    ]
    across
    key keycode [up]    [pos/y: pos/y - 10 show b]
    key keycode [down]  [pos/y: pos/y + 10 show b]
    key keycode [right] [pos/x: pos/x + 10 show b]
    key keycode [left]  [pos/x: pos/x - 10 show b]
]

Цвет может быть добавлен к фигурам в блоке рисования с помощью команды "pen" (перо). Фигуры можно заливать цветом, изображениями и другими графическими элементами с помощью команды "fill-pen". Толщина нарисованных линий задается командой "line-width":

rebol []
view layout [
    box 400x400 black effect [
        draw [
            pen red
            line 0x400 400x50
            pen white
            box 100x20 300x380
            fill-pen green
            circle 250x250 100
            pen blue
            fill-pen orange
            line-width 5
            spline closed 3 20x20 200x70 150x200
            polygon 20x20 200x70 150x200 50x300
        ]
    ]
]

6.2 Несколько коротких приложений для рисования

Создать программу рисования так же просто, как добавить элементы в блок рисования, используя любой контролируемый ввод от пользователя:

rebol [title: "Paint Lines"]
view layout [
    b: box black 400x400 effect [draw []]
    text "line start point:"
    f1: field "0x400"
    text "line end point:"
    f2: field "400x50"
    btn "Add line" [
        append b/effect/draw compose [
            line (to-pair f1/text) (to-pair f2/text)
        ]
        show b
    ]
]

Вот пример цветной рисовалки в которой используются ключевые элементы управления:

rebol [title: "Colorful Etch a Painting"]
pos: 200x200
paint: func [] [
    append b/effect/draw compose [
        pen (random 255.255.255)
        circle (pos) 2
    ]
    show b
]
view layout [
    b: box 400x400 black effect [
        draw [circle pos 10]
    ]
    across
    key keycode [up]    [pos/y: pos/y - 4  paint]
    key keycode [down]  [pos/y: pos/y + 4  paint]
    key keycode [right] [pos/x: pos/x + 4  paint]
    key keycode [left]  [pos/x: pos/x - 4  paint]
]

Как видите, рисование графики в Rebol - это управление этим блоком рисования с помощью функций последовательностей, настройки значений переменных и т.д. таким образом, графическое программирование во многом похоже на создание приложений CRUD, подобных примеру с контактами, который вы видели ранее.

7. Подробнее о серии - добавление дополнительных функций в приложение "Контакты"

Чтобы научиться делать что-либо ещё в Rebol, необходимо больше понимать, как использовать блоки ("серии") для хранения данных и управления ими. Возьмем предыдущий пример контактов:

rebol []
write/append %contacts ""
contacts: load %contacts
extract-names: func [] [
    names: copy []
    foreach [name address phone] contacts [append names name]
]
extract-names
view g: layout [
    t: text-list data names [
        n/text: copy t/picked
        a/text: copy pick contacts (1 + index? find contacts t/picked)
        p/text: copy pick contacts (2 + index? find contacts t/picked)
        show g
    ]
    text "Name:"
    n: field
    text "Address:"
    a: field
    text "Phone:"
    p: field
    btn "Add" [
        append contacts reduce [copy n/text copy a/text copy p/text]
        extract-names
        t/data: copy names
        show t
    ]
    btn "Save" [save %contacts contacts]
]

Если вы хотите удалить контакт, вам понадобится функция для удаления 3 элементов данных из сохраненного списка (имя, адрес и телефон). Давайте добавим кнопку, которая делает это - она использует функцию "remove/part":

rebol []
write/append %contacts ""
contacts: load %contacts
extract-names: func [] [
    names: copy []
    foreach [name address phone] contacts [append names name]
    copy names
]
view g: layout [
    t: text-list data extract-names [
        n/text: copy t/picked
        a/text: copy pick contacts (1 + index? find contacts t/picked)
        p/text: copy pick contacts (2 + index? find contacts t/picked)
        show g
    ]
    text "Name:"
    n: field
    text "Address:"
    a: field
    text "Phone:"
    p: field
    across
    btn "Add" [
        append contacts reduce [copy n/text copy a/text copy p/text]
        t/data: extract-names
        show t
    ]
    btn "Remove" [
        remove/part (find contacts t/picked) 3
        t/data: extract-names
        show t
    ]
    btn "Save" [save %contacts contacts]
]

Теперь добавим кнопку для сортировки записей по имени. Вы можете использовать функцию "sort/skip" (сортировка/пропустить) с уточнения для выполнения этой операции:

rebol []
write/append %contacts ""
contacts: load %contacts
extract-names: func [] [
    names: copy []
    foreach [name address phone] contacts [append names name]
    copy names
]
view g: layout [
    t: text-list data extract-names [
        n/text: copy t/picked
        a/text: copy pick contacts (1 + index? find contacts t/picked)
        p/text: copy pick contacts (2 + index? find contacts t/picked)
        show g
    ]
    text "Name:"
    n: field
    text "Address:"
    a: field
    text "Phone:"
    p: field
    across
    btn "Add" [
        append contacts reduce [copy n/text copy a/text copy p/text]
        t/data: extract-names  show t
    ]
    btn "Remove" [
        remove/part (find contacts t/picked) 3
        t/data: extract-names  show t
    ]
    btn "Sort" [
        sort/skip contacts 3
        t/data: extract-names  show t
    ]
    btn "Save" [save %contacts contacts]
]

Мы можем отсортировать в обратном порядке, используя функцию "sort" с уточнениями "/skip" и "/reverse" . Обратите внимание, что в каждой из наших новых кнопок мы используем функцию extract-names. Если бы мы не создали эту функцию, в этой программе наверняка было бы много повторяющегося кода:

rebol []
write/append %contacts ""
contacts: load %contacts
extract-names: func [] [
    names: copy []
    foreach [name address phone] contacts [append names name]
    copy names
]
view g: layout [
    t: text-list data extract-names [
        n/text: copy t/picked
        a/text: copy pick contacts (1 + index? find contacts t/picked)
        p/text: copy pick contacts (2 + index? find contacts t/picked)
        show g
    ]
    text "Name:"
    n: field
    text "Address:"
    a: field
    text "Phone:"
    p: field
    btn 100 "Add" [
        append contacts reduce [copy n/text copy a/text copy p/text]
        t/data: extract-names  show t
    ]
    btn 100 "Remove" [
        remove/part (find contacts t/picked) 3
        t/data: extract-names  show t
    ]
    btn 100 "Sort Ascending" [
        sort/skip contacts 3
        t/data: extract-names  show t
    ]
    btn 100 "Sort Descending" [
        sort/skip/reverse contacts 3
        t/data: extract-names  show t
    ]
    btn 100 "Save" [save %contacts contacts]
]

7.1 Встроенная справка

Итак, где вы узнали обо всех этих полезных серийных операциях? Что ж, Rebol может предоставить информацию об использовании любой функции с помощью функции справки, а вы можете получить список всех доступных функций с помощью функции "what". Для начала попробуйте запустить этот скрипт:

REBOL []
help pick
help find
help at
help index?
help length?
help append
help remove
help insert
help extract
help copy
help replace
help select
help sort
help reverse
help head
help next
help back
help last
help tail
help skip
help change
help poke
help clear
help join
help intersect
help difference
help exclude
help union
help unique
help empty?
help write
help read
help save
help load
halt

Реболеры регулярно используют функцию справки при написании кода. Информацию об использовании встроенного диалекта графического интерфейса Rebol (называемого "VID") можно найти, исследуя объекты в SVV:

REBOL []
? svv
probe extract svv/vid-styles 2
? svv/vid-styles/button
? svv/vid-words
? svv/facet-words

Вы можете просмотреть исходный код всех "мезонинных" (некомпилированных) функций, используя функцию "source" или используя функцию "mold" с любым параметром "get-word" в качестве аргумента (синтаксис "get-word" - это двоеточие перед словом - противоположность заданному слову). Изучение источника встроенных функций - один из лучших способов изучить Rebol:

source layout
editor mold :layout

Запустите программу ниже, чтобы создать справочное руководство команд Rebol. Результаты сохраняются в файле с именем help.txt и отображаются с помощью встроенного текстового редактора Rebol. Используя редактор, вы можете переименовать файл и сохранить его в любом месте на жестком диске, делать заметки и писать собственные примеры и т.д. для использования в будущем:

REBOL [Title: "Quick Manual"]
print "This will take a minute..."  wait 2
echo %words.txt what echo off   ; "echo" saves console activity to a file
echo %help.txt
foreach line read/lines %words.txt [
    word: first to-block line
    print "___________________________________________________________^/"
    print rejoin ["word:  " uppercase to-string word]  print "" 
    do compose [help (to-word word)]
]
echo off
x: read %help.txt
write %help.txt "VID STYLES (GUI WIDGETS):^/^/"
foreach i extract svv/vid-styles 2 [write/append %help.txt join i newline]
write/append %help.txt "^/^/LAYOUT WORDS:^/^/" 
foreach i svv/vid-words [write/append %help.txt join i newline]
b: copy [] 
foreach i svv/facet-words [
    if (not function? :i) [append b join to-string i "^/"]
]
write/append %help.txt rejoin [
    "^/^/STYLE FACETS (ATTRIBUTES):^/^/" b "^/^/SPECIAL STYLE FACETS:^/^/"
]
y: copy ""
foreach i (extract svv/vid-styles 2) [
    z: select svv/vid-styles i
    ; additional facets are held in a "words" block:
    if z/words [
        append y join i ": "
        foreach q z/words [if not (function? :q) [append y join q " "]]
        append y newline
    ]
]
write/append %help.txt rejoin [
    y "^/^/CORE FUNCTIONS:^/^/" at x 4
]
editor %help.txt

Подробнее о встроенной справке будет показано далее в этом тексте. Очень важно понимать, как получить доступ ко всей справочной информации и ресурсам, доступным непосредственно в интерпретаторе. Эти ресурсы необходимы не только в качестве учебных материалов во время обучения, но и при регулярной работе с кодом Rebol. Возможность использовать поиск по справке, автозаполнение, самоанализ системного объекта и другие функции документации, встроенные непосредственно в интерпретатор, позволяют ему работать как полностью самодокументированная система. Для поддержки кодирования Rebol не требуется IDE или внешние ресурсы.

7.1.1 Скрипт Word-Broswer.r

Программа ниже представляет красиво отформатированный текст справки с интерактивными примерами, которые поясняют, как работают все функции Rebol. Он охватывает подавляющее большинство языка Rebol, и все организовано по полезным категориям и имеет перекрестные ссылки с другими связанными функциями, поэтому вы можете быстро найти и использовать нужный вам код. Это незаменимый инструмент, который поможет вам узнать все об основных функциях языка. Совместите это с тщательным изучением системного объекта (особенно объекта svv для программирования с графическим интерфейсом), и вы узнаете большую часть того, что вам нужно для продуктивной работы с Rebol:

do http://re-bol.com/wordbrowser.r

8. Ещё несколько коротких приложений, использующих конструкции последовательностей и циклов

8.1 Слайд-шоу изображений

Это приложение отображает все изображения в текущей папке с 3-секундной паузой между каждым:

  1. Список файлов в текущем каталоге читается, и ему присваивается переменная метка 'files.
  2. Запускается бесконечный цикл.
  3. Внутри каждого повторения цикла Foreach выполняется цикл foreach. Для каждого файла в папке, если суффикс файла найден в заданном списке расширений файлов (png, jpg, gif, bmp), то любой отображаемый в данный момент макет окна не просматривается, и новый макет окна, отображающий текущий файл отображается изображение. Если пользователь щёлкает изображение мышью, программа закрывается. В противном случае программа ждет 3 секунды, а затем продолжит выполнение циклов.
REBOL [title: "Image Slideshow"]
files: read %./
forever [
    foreach file files [
        if find [%.png %.jpg %.gif %.bmp] suffix? file [
            unview 
            view/new center-face layout [
                image file [quit]
            ]
            wait 3
        ]
    ]
]

8.2 Гистограмма

Это небольшое приложение демонстрирует, как визуально отобразить список числовых значений на графической гистограмме:

  1. В этом примере создается блок (список) месяцев и числовых значений с меткой "d".
  2. Создается пустой блок с надписью "gui".
  3. Цикл "foreach" используется для просмотра каждого месяца и пары значений в списке "d". Для каждой пары элементов "month" и "value" в списке "d" некоторый код макета графического интерфейса пользователя добавляется к блоку "gui". Добавленный код состоит из кнопки, размер которой соответствует вычислению (значение * 10), и отображающей текст месяца. Функция "compose" используется для оценки значений размера и месяца в скобках. Например, если выбранный месяц и элементы значения - "March" (март) и "13", элементы, добавленные в блок gui, будут [btn 130 "March"].
  4. Отображается построенный блок макета графического интерфейса пользователя. Слово по центру используется для центрирования макета окна на экране.
REBOL [title: "Bar Chart"] 
d: ["March" 13 "April" 9 "May" 21 "June" 29 "July" 10] 
gui: copy []
foreach [month value] d [
    append gui compose [btn (value * 10) (month)]
]
view center-face layout gui

8.3 Отчет Paypal

В этом примере загружается файл учетной записи Paypal из Интернета и вычисляется сумма всех продаж в столбце "Gross Sales" (Валовые продажи):

  1. Сумма метки переменной установлена ​​для представления начального значения в $0.
  2. Метка переменной "x" задается для представления блока строковых данных, считываемых с данного URL-адреса.
  3. Первая строка в блоке данных "x" - это набор заголовков столбцов (заголовки для каждого столбца данных). Мы не хотим использовать эту строку в наших вычислениях, поэтому новая переменная "y" установлена ​​для представления всех, кроме первой строки значений "x" (т.е. "Y" настроен на начало "at" (в) второй строке в "x").
  4. Запускается цикл "foreach" для прохождения каждой строки в блоке "y".
  5. Данные в каждой строке файла Paypal представлены в формате "CSV" или "Comma Separated Value" (значения, разделенные запятыми), что означает, что каждое значение в каждой строке файла разделено запятой. Функция синтаксического анализа "parse" разделяет каждую строку на блок значений, помеченных здесь значениями.
  6. Значение "Валовых продаж" ("Gross Sales") находится в столбце № 8 в каждой строке, поэтому мы добавим текущее значение суммы к денежной стоимости, выбранной из элемента 8 в блоке значений. Если сделать это для каждой строки, окончательное значение суммы будет суммой всех индивидуальных значений валовых продаж.
  7. Сообщите пользователю сумму.
REBOL [title: "Paypal Reports"]    
sum: $0
x: read/lines http://re-bol.com/Download.csv
y: at x 2
foreach line y [
    values: parse/all line ","
    sum: sum + to-money pick values 8
]
alert join "Total Gross Sales: " sum

8.4 Игра Tric Trac

Смысл настольной игры Tric-Trac - бросить два кубика и сопоставить выпавшее число с любой комбинацией доступных чисел на доске. Например, если вы выбросите 6 с помощью кубиков, вы можете сопоставить числа 5 + 1, 4 + 2, 3 + 2 + 1 и т.д. на доске. После того, как номер на доске был выбран, его нельзя использовать повторно до конца игры. Игра заканчивается, когда у вас нет возможных комбинаций цифровых кнопок, соответствующих выпавшему значению. Чтобы определить окончательный результат, просуммируйте оставшиеся невыбранные числа на доске. Цель состоит в том, чтобы набрать наименьший итоговый результат (вы можете играть против себя или по очереди, играя против других). Вот как работает код в этой простой игровой симуляции Tric-Trac:

  1. Функция "random/seed" используется для заполнения генератора случайных чисел Rebol текущим временем, так что уникальные случайные числа могут быть сгенерированы с помощью функции 'random.
  2. Создается новый блок с меткой "g". Для начала, этот блок содержит 2 строки диалектного кода графического интерфейса пользователя: слово "across" и кнопку, которая предупреждает пользователя случайным значением от 1 до 12 (для имитации броска кости).
  3. Цикл повторения используется для добавления кода графического интерфейса пользователя в блок "g". Этот код состоит из текстового виджета, отображающего числа от 1 до 12, и виджета "check".
  4. Код макета блока "g" отображается в центрированном окне макета графического интерфейса пользователя.
REBOL [title: "Tric Trac"]
random/seed now
g: [
    across 
    btn "Roll" [alert form 1 + random 11]
] 
repeat i 12 [
    append g compose [text (mold i) check]
]
view center-face layout g

Версия этой игры с большим количеством функций доступна по адресу http://www.rebol.org/view-script.r?script=trictrac.r

8.5 Список покупок и список дел

Это приложение ведет список покупок, которые нужно купить. Он проверяет, не добавляете ли вы повторяющиеся элементы, и позволяет сохранять и загружать список.

  1. Создается макет окна. Он содержит пять виджетов: текстовый список размером 500x400 пикселей, помеченный "t", поле ввода текста шириной 500 пикселей, помеченное "f", и три кнопки.
  2. Когда пользователь вводит элемент в поле "f", программа проверяет, найден ли уже введенный текст в списке. Если повторяющаяся запись не найдена в списке, элемент добавляется в блок данных, отображаемый виджетом "t" (t/data). Дисплей обновляется функцией "show", и курсор снова помещается в поле "f" с функцией "focus".
  3. Если пользователь нажимает кнопку "Remove Selected" (удалить выбранное), выбранный элемент удаляется из текстового списка, и отображение обновляется.
  4. Если пользователь нажимает кнопку "Save List" (Сохранить список), данные в текстовом списке сохраняются в файл% shopping.txt, и пользователь получает предупреждение с текстом "Saved" (Сохранено).
  5. Если пользователь нажимает кнопку "Load List" (Загрузить список), текстовый список настраивается на отображение данных, загруженных из файла% shopping.txt, и отображение обновляется.
REBOL [title: "Shopping List"]
view center-face layout [
    t: text-list 500x400
    f: field 500 "(Enter Items Here)" [
        if not find t/data f/text [
            append t/data copy f/text
        ] 
        show t 
        focus f
    ]
    across
    btn "Remove Selected" [remove find t/data t/picked  show t]
    btn "Save List" [save %shopping.txt t/data  alert "Saved"]
    btn "Load List" [t/data: load %shopping.txt  show t]
]

Вот немного более сложный вариант программы, представленной выше, "Список дел", в которой добавлены некоторые функции. Он предоставляет возможность сохранять и загружать списки с разными именами файлов, возможность перемещать элементы вверх или вниз в порядке списка, а также возможность сохранять снимок экрана программы в изображение .png и просматривать это изображение в интернет браузере. Попробуйте выбрать функции серии и метки переменных и посмотрите, сможете ли вы следовать общему процессу программы:

REBOL [title: "To Do"]
view/new gui: layout [
    t: text-list 500x400
    across
    f: field [if not find t/data v: value [append t/data copy v] focus f]
    btn "Del"  [remove find t/data t/picked]
    btn "Up"   [attempt [move/to z: find t/data t/picked (index? z) - 1]]
    btn "Down" [attempt [move/to z: find t/data t/picked (index? z) + 1]]
    btn "Load" [attempt [t/data: load request-file/file/only %todo.txt]]
    btn "Save" [attempt [
        save request-file/save/file/only %todo.txt t/data
        alert "Saved"
    ]]
    btn "Print" [save/png %todo.png to-image gui  browse %todo.png]
] 
forever [wait .1  show gui  if not viewed? gui [quit]]

8.6 Календарь

Вот небольшое приложение для личного календаря, которое позволяет сохранять события для определенных дней:

  1. Создается новый файл "mycal" для сохранения данных календарного события. Помните, что уточнение "/append" функции записи добавляет данные в файл (вместо стирания существующего содержимого). Если файл ещё не существует, функция записи создаёт новый пустой файл (т.е. без добавления к нему ничего ("")). Если файл уже существует, к нему ничего ("") не добавляется, поэтому он остается прежним.
  2. Запускается бесконечный цикл.
  3. Функция "request-date" (запрос-дата) используется для получения даты, выбранной пользователем. Результат этой функции помечен как "d". Если пользователь не выбирает дату ("none"), программа завершает работу.
  4. Макет окна создается и центрируется на экране (с диалектным словом "center-face" (центр-вид) GUI").
  5. Выбранная дата отображается жирным шрифтом в верхней части окна.
  6. В макет добавляется виджет текстовой области с меткой "a". Он содержит данные "select" ed (найденные после) значения даты "d" в "mycal" файле (если выбранная дата не найдена в mycal файле, ничего не отображается).
  7. В макет добавлен виджет кнопки. При щелчке по нему дата ("d") и текст, содержащиеся в области, помеченной "a", сохраняются в файле mycal, а затем текущее окно макета не просматривается.
  8. Цикл "навсегда" начинается заново.
REBOL [title: "Calendar"]    
write/append %mycal "" 
forever [ 
     if none = d: request-date [quit] 
     view center-face layout [ 
         text bold form d 
         a: area form select (l: load %mycal) d 
         btn "Save" [ 
             save %mycal head insert l reduce [d a/text] 
             unview 
         ] 
     ] 
]

8.7 Генератор Pig Latin

Эта консольная программа позволяет пользователю вводить фразу, которая конвертируется в Pig Latin:

  1. У пользователя запрашиваем строку текста. Символы "^/" в конце цитируемого текста используются для печати возврата каретки (это то же самое, что и "newline" )новая строка)). Метка "p" присваивается тексту, введенному пользователем.
  2. Функция синтаксического анализа "parse" используется для разделения строк по указанным символам. Здесь фраза, помеченная выше "p", разделена на каждый пробел.
  3. Результатом функции "parse" является блок текстовых строк (здесь отдельные слова фразы, введенной пользователем). Этому списку слов присваивается ярлык "x".

Цикл "foreach" используется для просмотра каждого слова в блоке слов. Во время каждого повторения цикла foreach отдельные слова из списка помечаются как "w".

  1. Во время каждого повторения цикла foreach каждое отдельное слово разделяется на гласные. Этот блок символов помечен как "x".
  2. Вывод Pig Latin создается путем объединения нескольких частей текста: части слова перед первой гласной и части слова, начинающейся с первой гласной. Условная оценка используется для определения того, какая часть данного слова должна использоваться в каждой из половин слова Pig Latin. Другая оценка "either" (либо) используется для определения того, какие конечные символы должны использоваться для формирования второго слова в тексте Pig Latin (в зависимости от того, существуют ли негласные символы перед первой частью исходного слова). Например, если слово начинается с согласной буквы, вторая половина латинской пары Pig Latin оканчивается на "ау". В противном случае он заканчивается "hay". Обратите внимание, что функция "prin" используется для печати каждого слова Pig Latin. Функция "prin" делает то же самое, что и "print", за исключением того, что она не присоединяет символ новой строки к концу каждого печатаемого элемента (в этом случае функция позволяет печатать каждое из выходных слов рядом друг с другом вместо печати на отдельных строках).
  3. Печатается пустая строка, а функция остановки "halt" используется для предотвращения закрытия программы, чтобы пользователь мог прочитать распечатанные результаты.
REBOL [title: "Pig Latin"]
p: ask "Type some words to convert to Pig Latin:  ^/^/"
s: parse p " "
foreach w s [
    x: parse w "aeiou"
    prin rejoin [
        either q: find/match w x/1 [q] [w] 
        x/1 
        either q ["ay"]["hay"]
        " "
    ]
]
print newline
halt

8.8 Марширующая армия пришельцев с логотипом

Вот пример, который перемещает армию логотипов Rebol по экрану:

  1. Определен блок координат начальной позиции, помеченный как "poss" (возможный).
  2. Определена функция построения блока "build-block". Он строит блок команд рисования из блока существующих координат положения, перемещая каждое изображение на 8 пикселей от существующего положения. В этой функции сначала копируются значения блока "poss" в метку переменной "existing-poss" (существующий-возможный), и создается новый пустой блок "poss". Цикл foreach используется для заполнения нового блока pos значениями координат, которые перемещаются на 8 пикселей вправо (+ 8x0) от их местоположений в существующем блоке "Poss". Затем создается новый блок "logos", и цикл "foreach" используется для заполнения его командами рисования, составленными из сгенерированных координат в новом блоке "Poss".
  3. Функция "build-block" запускается один раз перед отображением окна, чтобы создать блок "logos" команд рисования. Приведенное выше определение функции просто определяет, что делает функция "build-block". Чтобы запустить этот код, вы должны фактически выполнить функцию "build-block" (как и любую другую функцию ("request-text", "now" и т.д.), Функция выполняется простым вводом её имени).
  4. Создается макет окна. Он содержит блок рисования, отображающий все графические команды в блоке логотипов.
  5. Макет окна также содержит виджет кнопки. Когда пользователь нажимает кнопку, блок кода зацикливается 10 раз. Внутри цикла выполняется функция "build-block", отображение блока "b" обновляется функцией "show", чтобы отображать новые графические команды в сгенерированном блоке логотипов с изображениями, смещенными более чем на 8 пикселей. Направо. Цикл приостанавливается на 0,2 секунды во время каждой из 10 итераций.
REBOL [title: "Marching Alien Logo Army"]
poss: [
    10x30 120x30 230x30 340x30 450x30 560x30
    10x60 120x60 230x60 340x60 450x60 560x60 
]
build-block: func [] [
    existing-poss: copy poss
    poss: copy []
    foreach pos existing-poss [append poss pos + 8x0]
    logos: copy []
    foreach pos poss [append logos compose [image (pos) logo.gif]]
]
build-block
view layout [
    b: box 800x300 aqua effect [draw logos]
    btn "Move 10 clicks"[
        loop 10 [
            build-block
            show b
            wait .2
        ]
    ]
]

8.9 Игра Поймайка

В этой игре игрок пытается поймать падающие изображения логотипа Rebol, используя клавиши курсора для перемещения. Скорость увеличивается по мере прохождения игры. Игра заканчивается, когда падающий логотип падает на пол. Окончательный счет - это количество времени, в течение которого игра была сыграна. Очки сохраняются вместе с именем каждого игрока, отсортированы от наименьшего к наибольшему и отображаются в конце игры. Взгляните на элементы окна графического интерфейса пользователя, условные оценки вычисленных значений переменных внутри бесконечного цикла, операции управления списком оценок, постоянное хранилище данных и т.д.:

  1. Функция "random/seed" используется для заполнения генератора случайных чисел Rebol текущим временем, так что уникальные случайные числа могут быть сгенерированы с помощью функции 'random.
  2. В метке переменной "start" установлено время, когда программа была запущена.
  3. Скорость переменной установлена ​​на начальное значение 2.
  4. Макет окна создан. Уточнение "/new" функции "view" используется для создания окна, ещё не отображая его. Макет обозначен буквой "g". Макет имеет размер 600х440 пикселей. Виджет изображения, содержащий встроенное изображение "logo.gif", помещается в координату 280x20. Этот виджет помечен как "a". Виджет с синей кнопкой размером 50x20 пикселей помещается в координату 280x420. Этот виджет помечен буквой "b". Настроены обработчики клавиатуры для клавиш со стрелками влево и вправо. Если нажата левая клавиша, положение синей кнопки "b" смещается на 10 пикселей влево. При нажатии правой клавиши координата кнопки "b" сдвигается на 10 пикселей вправо.
  5. Запускается бесконечный цикл.
  6. Положение изображения сдвинуто вниз. Расстояние переключения определяется переменной скорости. Функция "as-pair" используется для создания координаты, в которой значение y (по вертикали) является округленным значением скорости. Это увеличенное значение координаты добавляется к текущей координате виджета. Конечным результатом этого вычисления является то, что виджет перемещается вниз на количество пикселей.
  7. Условная оценка "if" используется для проверки того, перекрываются ли виджеты "a" и "b" (то есть фигура игрока и падающее изображение соприкасаются/сталкиваются - если да, то падающая часть ловится). Если это так, позиция виджета устанавливается на случайную координату x в верхней части экрана. Это начинает сбрасывать "новое" изображение логотипа, как только предыдущее падающее изображение было поймано (на самом деле во всей игре есть только одно изображение логотипа - оно просто перемещено). Значение "x" случайной координаты находится где-то между 1-500 пикселями от левой стороны окна, а значение "y" - на 20 пикселей от верха окна. Значение скорости также увеличивается на 0,1 каждый раз, когда ловится падающий логотип. Это означает, что каждые 10 уловов скорость увеличивается на одно округленное значение в пикселях.
  8. Оценка "if" используется для проверки того, превышает ли значение y координаты виджета 440 (т.е. изображение касается пола). Если это так, игра окончена, поэтому для завершения цикла навсегда используется функция "break".
  9. Если игра не была остановлена ​​выше, программа ожидает 0,01 секунды, показывает все обновления макета окна (помечены как "g") и продолжает повторять цикл "forever".
  10. Когда игра заканчивается, счёт сохраняется, и высокие результаты отображаются в отсортированном порядке от наименьшего к наибольшему. Для этого сначала создаётся файл "партитуры", если он ещё не существует. Затем из файла загружаются любые существующие партитуры. Затем к списку очков добавляются 2 значения: текущий счёт (то есть текущее время минус время начала) и имя игрока (полученное с помощью функции request-text). Список партитур сортируется по количеству баллов с использованием уточнения "skip" "пропустить" (каждые 2 элемента в списке содержат балл и имя (балл, имя, балл, имя и т.д.)), и этот отсортированный список сохраняется в файл баллов. . Функция 'request-list' используется для отображения всех отсортированных оценок.
REBOL [title: "Catch Game"]
random/seed now   
start: now/time
speed: 2
view/new center-face g: layout [
    size 600x440 
    at 280x20   a: image logo.gif
    at 280x420  b: btn 50x20 blue
    key keycode [left]  [b/offset: b/offset - 10x0]
    key keycode [right] [b/offset: b/offset + 10x0]
]
forever [
    a/offset: a/offset + (as-pair 0 round speed)
    if overlap? a b [
        a/offset: as-pair (random 500) 20
        speed: speed + .1
    ]
    if a/offset/y > 440 [break]
    wait .01
    show g
]
write/append %scores ""
scores: load %scores
append scores now/time - start 
append scores request-text/title "Name:"
save %scores sort/skip scores 2 
request-list "High Scores:" scores

8.10 Инструмент для гитарных аккордов и гамм

Эта программа позволяет пользователю быстро создавать и сохранять изображения диаграмм грифа гитары для аккордов и/или гамм. Когда программа запустится, введите желаемое количество ладов на диаграмме (по умолчанию 5 ладов, но вы можете использовать 3 или 4 для диаграмм меньшего размера или больше для диаграмм полного масштаба грифа). Щёлкните любой лад на любой струне, чтобы добавить точку (положение пальца). Щёлкните любую добавленную точку, чтобы удалить ее (верните ее на пустую позицию). Щёлкните правой кнопкой мыши любой лад на любой строке, чтобы добавить символ по вашему выбору (вы можете использовать эту функцию, чтобы добавить номера пальцев, метки корневых нот, метки интервалов и т.д.). Щёлкните текст заголовка ("Название аккорда"), чтобы дать аккорду или гамме имя. Щёлкните правой кнопкой мыши заголовок, чтобы сохранить диаграмму в формате .png (имя файла изображения по умолчанию - это текст заголовка, введенный выше).

  1. Программа начинает с получения от пользователя ряда ладов. Используется функция "request-text" с уточнениями "/title" и "/default" (пользователю предоставляется номер по умолчанию 5). Ответ пользователя помечен буквой "f".
  2. Блок диалектного кода графического интерфейса пользователя помечен как "g". Слово "backdrop" (фон) устанавливает белый цвет фона макета окна. Слово "across" (поперек) используется для размещения виджетов по экрану. Слово "space" (пробел) используется для установки промежутка между виджетами на 0 как в горизонтальном, так и в вертикальном направлении (обычно между виджетами есть буфер пространства по умолчанию - здесь он установлен на 0x0). Слово "origin" используется для установки позиции первого виджета в макете на 0x0.
  3. Слово "style (стиль) используется для создания нового виджета с меткой "s", который представляет собой блок размером 20x20 пикселей, отображающий символ "|" на его лицевой стороне с размером шрифта 20, цветом шрифта чёрный и смещением тени шрифта 0x0 (без тени). Для виджета настроено два действия. Первый блок запускается всякий раз, когда по виджету щёлкают левой кнопкой мыши (точно так же, как обычный блок действий, который вы видели во всех других примерах). Второй блок запускается всякий раз, когда по виджету щёлкают правой кнопкой мыши. При щелчке левой кнопкой мыши по любому виджету для текста лица устанавливается значение "O" или "|". Условная оценка "either" (либо) используется, чтобы определить, является ли текущий текст лица "|". Если это так, текст лица устанавливается на "O", в противном случае текст лица устанавливается на "|". Если щёлкнуть правой кнопкой мыши какой-либо виджет, в качестве текста лица устанавливается некоторый текст, запрашиваемый пользователем.
  4. В макет добавляется текстовый виджет с меткой "t". Он имеет размер 120x24 пикселей, жирный текст по центру и размер шрифта 18. Ему назначены 2 альтернативных блока действий для реакции на левый и правый щелчки мыши. Если щёлкнуть текстовый виджет левой кнопкой мыши, в качестве текста лица устанавливается некоторый текст, запрашиваемый пользователем. Используется функция "request-text" с уточнением "/default", а текст по умолчанию, который отображается в запросчике, является текущим текстом лица в виджете. Если по текстовому виджету щёлкнуть правой кнопкой мыши, будет сделана попытка сохранить макет "p" в файл изображения. Функция сохранения с уточнением "/png" принимает 2 параметра: имя файла для сохранения и данные для сохранения. В этом случае имя файла получается от пользователя с помощью функции "request-file". Уточнения "/save", "/only" и "/file" функции "request-text" вызывают диалог сохранения, который позволяет выбрать только один файл с именем файла по умолчанию (в данном случае текст виджета "t", соединённый с символами ".png"). Данные изображения создаются с использованием функции "to-image" с текущим макетом (помеченным "p") в качестве его параметра.
  5. Функция цикла используется для выполнения блока кода "f" количество раз. Помните, что метка "f" была установлена ​​в начале программы - это количество ладов, которые нужно включить в макет. Здесь текстовый ответ, полученный от пользователя, необходимо преобразовать в целое число. Это достигается с помощью функции "to-integer". Зацикленный блок добавляет несколько виджетов и слово возврата (новая строка) к блоку макета "g" выше.
  6. Будет показан блок кода макета "g", и этот макет помечен как "p". Чтобы было ясно, метка "g" относится к блоку кода диалекта графического интерфейса пользователя, используемому для создания макета. Метка "p" относится к фактическому текущему макету (который внутри состоит из множества низкоуровневых объектов, функций, команд рисования и т.д.). Этот низкоуровневый макет, нарисованный в настоящее время, является тем, что требуется в качестве параметра функции "to-image".
REBOL [title: "Guitar Chord and Scale Diagrammer"]
f: request-text/title/default "Number of frets in each diagram:" "5"
g: [
    backdrop white
    across  space 0x0  origin 0x0
    style s box 20x20 "|" font-size 20 font-color black shadow 0x0 [
        face/text: either "|" = face/text ["O"] ["|"] 
    ] [
        face/text: request-text
    ]
    t: text 120x24 bold center font-size 18 "Chord Name" [
        face/text: request-text/default face/text
    ] [ attempt [
        save/png request-file/save/only/file join t/text ".png" to-image p
    ] ]
    return
]
loop to-integer f [append g [s s s s s s return]]
view center-face p: layout g

Вот версия программы выше с добавленной функцией макета HTML. Нажмите клавишу "p" на клавиатуре, чтобы создать HTML-макет любых выбранных вами диаграмм. HTML-макет можно распечатать, отправить по электронной почте, загрузить на веб-сайт и т.д.:

REBOL [title: "Guitar Chord and Scale Diagrammer"]
f: request-text/title/default "Number of frets in each diagram:" "5"
layout-html: func [] [
    filelist: sort request-file/filter/title 
        ["*.png"] "Select image(s) to print:" ""
    html: copy "<html><body>"
    foreach file filelist [
        append html rejoin [
            {<img src="file:///} to-local-file file {"> &nbsp; &nbsp; }
        ]
    ]
    append html [</body></html>]
    write %chords.html trim/auto html
    browse %chords.html 
]
g: [
    at 100x100 key #"p" [layout-html]
    backdrop white
    across  origin 0x0  space 0x0
    style s box 20x20 "|" font-size 20 font-color black shadow 0x0 [
        face/text: either "|" = face/text ["O"] ["|"] 
    ] [
        face/text: request-text
    ]
    t: text 120x24 bold center font-size 18 "Chord Name" [
        face/text: request-text/default face/text
    ] [ attempt [
        save/png request-file/save/only/file join t/text ".png" to-image p
    ] ]
    return
]
loop to-integer f [append g [s s s s s s return]]
view center-face p: layout g

Приложения в этом разделе четко демонстрируют, что списки и структуры кода цикла являются важным дополнением к таким концепциям, как переменные, функции, постоянное хранилище данных и другие базовые принципы кодирования.

8.11 Дополнительные серии приложений для изучения

Вот ещё несколько коротких примеров приложений, в которых используются конструкции рядов. Посмотрите, сможете ли вы следовать основному потоку кода в каждой программе.

Полноэкранная презентация (попробуйте угадать, какая системная переменная содержит размер экрана). Обратите внимание, что макеты слайдов хранятся во вложенном блоке блоков:

REBOL [title: "Simple Presentation"]
slides: [
    [
        at 0x0 box system/view/screen-face/size white [unview]
        at 20x20 h1 blue "Slide 1"
        box black 2000x2
        text "This slide takes up the full screen."
        text "Adding images is easy:"
        image logo.gif
        image stop.gif
        image info.gif
        image exclamation.gif
        text "Click anywhere on the screen for next slide..."
        box black 2000x2
    ]
    [
        at 0x0 box system/view/screen-face/size effect [
            gradient 1x1 tan brown
        ] [unview]
        at 20x20 h1 blue "Slide 2"
        box black 2000x2
        text "Gradients and color effects are easy in REBOL:"
        box effect [gradient 123.23.56 254.0.12]
        box effect [gradient blue gold/2]
        text "Click anywhere on the screen to close..."
        box black 2000x2
    ]
]
foreach slide slides [
    view/options center-face layout slide 'no-title
]

Простое, но полнофункциональное приложение для розничной кассы:

REBOL [title: "Minimal Cash Register"]
view gui: layout [
    style fld field 80
    across
    text "Cashier:"   cashier: fld 
    text "Item:"      item: fld 
    text "Price:"     price: fld [
        if error? try [to-money price/text] [alert "Price error" return]
        append a/text reduce [mold item/text tab price/text newline]
        item/text: copy "" price/text: copy ""
        sum: 0
        foreach [item price] load a/text [sum: sum + to-money price]
        subtotal/text: form sum
        tax/text: form sum * .06
        total/text: form sum * 1.06 
        focus item
        show gui
    ]
    return
    a: area 600x300
    return
    text "Subtotal:"   subtotal: fld 
    text "Tax:"        tax: fld 
    text "Total:"      total: fld
    btn "Save" [
        items: replace/all (mold load a/text) newline " "
        write/append %sales.txt rejoin [
            items newline cashier/text newline now/date newline
        ]
        clear-fields gui
        a/text: copy ""             
        show gui             
    ]
]

Программа отчетов, которая вычисляет дневную сумму продаж для указанной выше программы:

REBOL [title: "Daily Sales Total"]
sales: read/lines %sales.txt
sum: $0
foreach [items cashier date] sales [
    if now/date = to-date date [
        foreach [item price] load items [
            sum: sum + to-money price
        ]
    ]
]
alert rejoin ["Total sales today: " sum]

Ниже представлены две разные версии одной и той же программы группового чата. Первый запускается в текстовой консоли. Второй использует окно графического интерфейса, позволяющее пользователю вводить текст и просматривать сообщения. Сообщения просто хранятся в текстовом файле на веб-сервере (для использования этой программы вам необходимо знать действующий URL-адрес FTP веб-сайта и использовать правильные имя пользователя и пароль для записи файла):

REBOL [title: "Group Chat (Console)"] url: ftp://user:pass@site.com/public_html/chat write/append url "" name: copy ask "^LName: " forever [

notes: copy read url
message: ask rejoin [newpage notes "Message:  "]
if message = "erase" [write url ""]
if message <> "" [
    write/append url rejoin [
        now " (" name "):  " message "^/^/"
    ]
]

]


REBOL [title: "Group Chat (GUI)"] url: ftp://user:pass@site.com/public_html/chat write/append url "" name: request-text/title "Name:" view gui: layout [

a: area 600x300
text "New Message:"
message: field 600 [
    if message/text = "erase" [write url ""]
    if message/text <> "" [
        write/append url rejoin [
            now " (" name "):  " message/text "^/^/"
        ]
    ]
    a/text: copy read url  focus message  show gui 
]

]

Вот игра, которая манипулирует списком изображений в блоке рисования:

REBOL [title: "Ski Game"]
tree:  load to-binary decompress 64#{
eJzt18sNwjAQBFDTBSVw5EQBnLjQE1XRngmBQEj8Wa/3M4oYOZKBKHkaWwTO1/sh
jDkNx3N6HI7LcOzCfnz/9v5cMnEai7lj4mokT9C7XczUsrhvGSku6RkgDIbHAEP0
2EiIMBdMDuaOWZCSL91bQvCsSY4MHE9umXz7ydVi3xgltYvEKboexzVSlpTa614d
NonpUauIv176dX0ZTRgJlVgzNl25A3gkGwld1bkrNFqqedQfEI02AU9PjDeMpac/
ShKeTXylROqCImlXRFd9zkQoh4tp+GpqlSTnLnum4HTEzK/gjpmTpDxSASlHFqYU
EE/8nddG9n+9LIm8t9OeIEra2JZWDRSG4VEioa0UFCZFqv/aMQh2Rf790EnGgcJU
SVAer0Bhcp7/epVJvkHzBHjPfz+XSe6BwryC5gmQno3mAY3tpba2KAAA
}
skier-left: load to-binary decompress 64#{
eJyN0U8og2EcB/DvNrz+E5fJZSmRf9Ej76h3Ne1AIspyMQflpJDFU/KO1cQmSnGa
A3PYkvInB3kvuyzlgJolh+fCRUq5iBvP8+5lTvKrX33ep+/zp9/b2Tthhl6zvGt5
W3nX8TYhS1//MOGnSjNEa/AUxd0UVQ3raL9IYbBvA2OBI9Q0DqB6fAujl08Yi97D
Hr3F5EQYSss2OrrWEFo5xB+VO5Vx/skvnxmQbDCFvxcjMJ/b0s6LAZXGA3O0ZtTt
pW3WbJmDeMC8a1gE9o3bTBFI9YvGhrOKSueyEQpu9ri60vQFXFqPMx1K+sNWrdOh
73Y/uMr85fKdcIrJ0z6vxSfsYV5KCU2JEPNIlD9dFZ65AfXwD+HsKdAZiiLdqtvt
Hh65E5ZklTGmDvWLgxxKkjAivwt7XxhJEvIsrCY8ikLs0Tj3yGeCKaQtdsX9fv3G
N1jCJdyv84lHJkNriiM7Li29OIDV0jcU8kuIHaiPLEDEsG9DQYxiQTi0A8sBpEvh
OT65GmBYH9Jx5nf8TFFUFf5ZX2hFdG1uAgAA
}
skier-right: load to-binary decompress 64#{
eJxz8s1jYgCDMiDWAGIJINYCYkYGFrD4D0YGOBBAMBn4++Yz6HjVMSgY1oP5gWdu
M/gHTmCwNutlKJ26l6F03VUGp3XnGGo+/mGILVnMoFkwhaHm7GcGz4m7GbABFwST
eQWSNXMQbM+3DAwlULbmEgaWXih75QUGzvkQJstMBwbPRRA2L1D5yS8QNudioNQF
qNYPDExAZRCtDg78c6Fa7wZK3Ycq940O3L1fAcLWigpctUsZzHTSj5Jd+l7NAKS6
3HnXk6jHSiBF7sUmxi7Gl9VAZrqVOxsZuTirg8TTS0qAQs5FIPF0BhYXFkgog/zg
7gJlq5SXpaWVF4O9lZKuXl6eVl4AZLIfKS82LzYuB2nlOFxWXl5ubA6ytm1KWU65
cXExkMl09lNNR3q5eTFQPYfHE7YT6cXlJgcYGI7cPMAOMtKhgcH9wE8FBuPycgOG
BoYKtl8ODL4gjccY2HSAfr4BVMvgAwyazwwsXSA7ORgY2BQYeH+Cw+sAKPo5wEHj
kQAO/GZwIIHDgc0AaxQSBAAFOXD7bgIAAA==
}
random/seed now
the-score: 0
board: reduce ['image 300x20 skier-right black]
for i 1 20 1 [
    pos: random 600x540
    pos: pos + 0x300
    append board reduce ['image pos tree black]
]
view center-face layout/tight [
    scrn: box white 600x440 effect [draw board] rate 0 feel [
        engage: func [f a e] [
            if a = 'key [
                if e/key = 'right [
                    board/2: board/2 + 5x0
                    board/3: skier-right
                ]
                if e/key = 'left [
                    board/2: board/2 - 5x0
                    board/3: skier-left
                ]
                show scrn
            ]
            if a = 'time [
                new-board: copy []
                foreach item board [
                    either all [
                        ((type? item) = pair!) 
                        ((length? new-board) > 4)
                    ] [ 
                        append new-board (item - 0x5) 
                    ] [
                        append new-board item
                    ]
                    coord: first back back (tail new-board)
                    if ((type? coord) = pair!) [
                        if ((second coord) < -60) [
                            remove back tail new-board
                            remove back tail new-board
                            remove back tail new-board
                            remove back tail new-board
                        ]
                    ]
                ]
                board: copy new-board
                if (length? new-board) < 84 [
                    column: random 600
                    pos: to-pair rejoin [column "x" 440]
                    append board reduce ['image pos tree black]
                ]
                collision-board: remove/part (copy board) 4
                foreach item collision-board [
                    if (type? item) = pair! [
                        if all [
                          ((item/1 - board/2/1) < 15)
                          ((item/1 - board/2/1) > -40)
                          ((board/2/2 - item/2) < 30)
                          ((board/2/2 - item/2) > 5)
                        ] [
                            alert "Ouch - you hit a tree!"
                            alert rejoin ["Final Score: " the-score]
                            quit
                        ]
                    ]
                ]
                the-score: the-score + 1 
                score/text: to-string the-score
                show scrn
            ]
        ]
    ]
    origin across h2 "Score:" 
    score: h2 bold "000000"
    do [focus scrn]
]

9. Создание веб-приложений с использованием REBOL CGI

Чтобы создавать приложения CGI для веб-сайта, вам нужен доступный веб-сервер, а интерпретатор REBOL должен быть загружен и установлен на вашем веб-сервере. Этот проект содержит минисервер Uniform с Rebol, настроенный для тестирования сценариев CGI в Windows.

9.1 HTML-формы и серверные скрипты - базовая модель CGI

Следующий HTML-код содержит форму с полем ввода текста, кнопкой и "действием" (action), указывающим на указанный URL:

<HTML>
    <HEAD><TITLE>Data Entry Form</TITLE></HEAD>
    <BODY>
        <FORM ACTION="http://yourwebserver.com/your_rebol_script.cgi">
            <INPUT TYPE="TEXT" NAME="username" SIZE="25">
            <INPUT TYPE="SUBMIT" NAME="Submit" VALUE="Submit">
        </FORM>
    </BODY>
</HTML>

Сохраните следующий сценарий по URL-адресу действия, указанному выше. Сценарий декодирует отправленные данные, назначает этим данным отправленную метку и выводит результат прямо в веб-браузер пользователя. Помните, что фигурные скобки используются в Rebol для многострочного строкового содержимого:

#!/home/your_user_path/rebol/rebol -cs
REBOL []
print {content-type: text/html^/}  
submitted: decode-cgi read-cgi

print rejoin [
    {<HTML><HEAD><TITLE>Page title</TITLE></HEAD><BODY>}
    {Hello } second submitted {!}
    {</BODY></HTML>}
]

Чтобы приведенный выше код работал на вашем веб-сервере, интерпретатор REBOL должен быть найден по пути, указанному в "/home/your_user_path/rebol/rebol -cs" (т.е. если интерпретатор находится на том же пути, что и сценарий, это строка должна читать "#!./rebol -cs"). Строка decode-cgi read-cgi является ключом к получению данных, отправленных HTML-формами (выше этому блоку данных присваивается метка "submitted" (отправлено)).

9.2 -Стандартный шаблон компьютерной графики для запоминания

Большинство программ CGI обычно проверяют отправленные данные, и если они пустые (т.е. данные не были отправлены), программа печатает исходную HTML-форму для получения ввода от пользователя. В противном случае отправленные данные обрабатываются по мере необходимости, а вывод печатается в веб-браузере пользователя в виде новой HTML-страницы. Вот базовый пример всего этого процесса в одном скрипте:

#!/home/your_user_path/rebol/rebol -cs
REBOL []
print {content-type: text/html^/}
submitted: decode-cgi read-cgi

; Четыре строки выше - это стандартные заголовки REBOL CGI. В приведенной ниже 
; строке печатаются стандартные теги HTML, head и body в браузере посетителя:
print {<HTML><HEAD><TITLE>Page title</TITLE></HEAD><BODY>}

; Затем определите, были ли отправлены какие-либо данные. Распечатайте 
; начальную форму, если она пуста. В противном случае обработайте и 
; распечатайте некоторый HTML, используя отправленные данные. Наконец, 
; распечатайте стандартные закрывающие теги body и html, которые были открыты 
; выше:
either empty? submitted [
    print {
        <FORM METHOD="POST">
        <INPUT TYPE="TEXT" NAME="username" SIZE="25">
        <INPUT TYPE="SUBMIT" NAME="Submit" VALUE="Submit">
        </FORM>
        </BODY></HTML>
    }
] [ 
    print rejoin [{Hello } submitted/2 {!}]
    print {</BODY></HTML>}
]

10. Примеры приложений CGI

10.1 Общее приложение CGI с HTML-формой

Вот базовый шаблон CGI, который печатает форму для ввода данных пользователя. Демо этого скрипта доступно на http://guitarz.org/rebol3:

#!./rebol -cs
REBOL [title: "Generic CGI Application, With HTML Form"]
print {content-type: text/html^/}
print {<HTML><HEAD><TITLE>Page title</TITLE></HEAD><BODY>}
submitted: decode-cgi read-cgi
either empty? submitted [
    print {
        <FORM METHOD="POST">
        <INPUT TYPE="TEXT" NAME="username" SIZE="25">
        <INPUT TYPE="SUBMIT" NAME="Submit" VALUE="Submit">
        </FORM>
        </BODY></HTML>
    }
] [ 
    print rejoin [{Hello } submitted/2 {!}]
    print {</BODY></HTML>}
]

10.2 Фотоальбом CGI

Вот простая программа CGI, которая отображает все фотографии в текущей папке на веб-сайте, используя цикл foreach. Демо этого скрипта доступно на http://guitarz.org/rebol3/photos.cgi:

#!./rebol -cs
REBOL [title: "CGI Photo Album"]
print {content-type: text/html^/}
print {<HTML><HEAD><TITLE>Photos</TITLE></HEAD><BODY>}
folder: read %./
count: 0
foreach file folder [
    foreach ext [".jpg" ".gif" ".png" ".bmp"] [
        if find file ext [
            print [<BR> <CENTER>]
            print rejoin [{<img src="} file {">}]
            print [</CENTER>]
            count: count + 1
        ]
    ]
]
print join {<BR>Total Images: } count
print {</BODY></HTML>}

10.3 -CGI текстовый чат

Вот короткое приложение для веб-чата. Пользователи могут ввести слово "erase" (стереть) в поле имени, чтобы удалить все предыдущие тексты. Демо этого скрипта доступно по адресу http://guitarz.org/rebol3/chat.cgi:

#!./rebol -cs
REBOL [title: "Group Chat"]
print {content-type: text/html^/}
url: %./chat.txt
write/append url ""
submitted: decode-cgi read-cgi
if submitted/2 = "erase" [write url ""]
if submitted/2 <> none [
    write/append url rejoin [
        now " (" submitted/2 "):  " submitted/4 "^/^/"
    ]
]
notes: copy read url
print rejoin [
    "<pre>" notes "</pre>"
    {<FORM METHOD="POST">
        Name:<br>
        <input type=text size="65" name="username"><br>
        Message:<br>
        <textarea name=message rows=5 cols=50></textarea><br>
        <input type="submit" name="submit" value="Submit">
    </FORM>}
]

10.4 Типичное приложение с раскрывающимся списком

В следующем примере показано, как автоматически создавать списки дней, месяцев, времени и данных, считанных из файла, с использованием динамических циклов (foreach, for и т.д.). Элементы можно выбрать из раскрывающихся списков в распечатанной HTML-форме. Демо этого скрипта доступно по адресу http://guitarz.org/rebol3/drop.cgi:

#!./rebol3 -cs
REBOL [title: "Dropdown Lists"]
print {content-type: text/html^/}
print {<HTML><HEAD><TITLE>Dropdown Lists</TITLE></HEAD><BODY>}
submitted: decode-cgi read-cgi
if not empty? submitted [
    print rejoin [{NAME SELECTED: } submitted/2 {<BR><BR>}]
    selected: rejoin [
        {TIME/DATE SELECTED: }
        submitted/4 { } submitted/6 {, } submitted/8
    ]
    print selected
    quit
]
; If no data has been submitted, print the initial form:
print {<FORM METHOD="POST">SELECT A NAME:  <BR> <BR>}
names: read/lines %users.txt
print {<select NAME="names">}
foreach name names [prin rejoin [{<option>} name]]
print {</option> </select> <br> <br>}
print { SELECT A DATE AND TIME: }
print rejoin [{(today's date is } now/date {)} <BR><BR>]
print {<select NAME="month">}
foreach m system/locale/months [prin rejoin [{<option>} m]]
print {</option> </select>}
print {<select NAME="date">} 
for daysinmonth 1 31 1 [prin rejoin [{<option>} daysinmonth]]
print {</option> </select>}
print {<select NAME="time">}
times: ["10am" "11am" "12pm" "1pm" "1:30pm" "4:15pm" "7:30pm"]
foreach time times [prin rejoin [{<option>} time]]
print {</option> </select><br> <br>}
print {<INPUT TYPE="SUBMIT" NAME="Submit" VALUE="Submit"></FORM>}

Файл "users.txt", использованный в приведенном выше примере, может выглядеть примерно так:

nick
john
jim
bob

11. Больше основ Rebol

11.1 Типы данных

Rebol распознает более 40 собственных типов данных, а новые могут быть определены пользователем. Функция "type" определяет тип данных значения. Вот несколько примеров:

a-string: "Hello World"                    type? a-string
an-integer: 3874904                        type? an-integer
a-decimal: 7348.39                         type? a-decimal    
web-site: http://musiclessonz.com          type? web-site 
email-address: user@website.com            type? email-address      
the-file: %/c/myfile.txt                   type? the-file 
money-amount: $343.56                      type? money-amount
color-tuple: 123.54.212                    type? color-tuple
a-character: #"z"                          type? a-character
a-word: 'asdf                              type? a-word                   
html-tag: <br>                             type? html-tag    
binary-info:  #{ddeedd}                    type? binary-info    
image: load http://rebol.com/view/bay.jpg  type? image
a-sound: load %/c/windows/media/tada.wav   a-sound/type

Вот несколько примеров приведения, которые преобразуют данные из одного типа в другой:

to-decimal an-integer     ; Преобразование значений в разные типы ("приведение")
to-string web-site        ; теперь URL-адрес веб-сайта заключен в кавычки
form web-site             ; "form" также преобразует различные значения в строку
form $29.99
alert form $29.99         ; функция alert ТРЕБУЕТ строковый параметр
alert $29.99              ; (это вызывает ошибку)
5 + 6                     ; вы можете выполнять математические операции с 
                          ; целыми числами
"5" + "6"                 ; (ошибка) вы не можете выполнять математические
                          ; вычисления со строками
(to-integer "5") + (to-integer "6")    ; это устраняет математическую проблему
to-pair [12 43]           ; создает пару координат
as-pair 12 43             ; лучший способ создать пару координат
to-binary 123.54.212      ; преобразовать значение цвета REBOL в 
                          ; шестнадцатеричное значение цвета
to-binary request-color   ; преобразовать цвет, выбранный пользователем, в 
                          ; шестнадцатеричный
to-tuple #{00CD00}        ; преобразовать шестнадцатеричное значение цвета в 
                          ; значение цвета REBOL
form to-tuple #{00CD00}   ; преобразовать шестнадцатеричное значение цвета в 
                          ; строку
write/binary %floorplan8.pdf debase read clipboard://  ; вложения e-mail

REBOL правильно вычисляет значения для типа:

6:30am + 00:37:19
now  
now + 0:0:59  
now - 10   
23x54 + 19x31
22x66 * 2
22x66 * 2x3
192.168.1.1 + 0.0.0.37
11.22.33.44 * 9         ; обратите внимание, что значение каждого IP-сегмента 
                        ; ограничено 255
0.250.0 / 2             ; простой способ настроить значения цвета
$29.99 * 5
x: 12  y: 33  q: 18  p: 7
(as-pair x y) + (as-pair q p)   ; очень часто используется в графических
                                ; приложениях, использующих координаты
remove form to-money 1 / 233
remove/part form to-time (1 / 233) 6

Могут быть сгенерированы случайные значения данных в соответствии с типом:

random/seed now/time    ; всегда используйте эту строку, чтобы получить 
                        ; реальные случайные значения
random 50               ; случайное число от 0 до 50
random 50x100           ; левая сторона ограничена 50, правая ограничена 100
random 222.222.222      ; каждый сегмент ограничен # от 0 до 222
random $500
random "asdfqwerty"     ; случайное сочетание заданных символов
random [1 2 3 4 5]      ; случайно отсортированный список значений

11.2 Разнообразие дополнительных примеров работы коротких серий

Вот несколько примеров последовательной работы:

new-block: copy []  ; новый, пустой блок
some-names: ["John" "Bill" "Tom" "Mike"]   ; список текстовых строк
more-names: copy some-names   ; копия приведенного выше списка
probe more-names
same? more-names some-names   ; НЕ тот же список, а его копия
same-names: some-names   ; ЭТИ метки теперь относятся к ТОЧНО ЖЕ списку
probe same-names
same? same-names some-names ; изменить некоторые-имена и одноименные 
                            ; изменения ТОЖЕ
sortednames: sort copy some-names   ; "копия" удерживает некоторые имена от 
                                    ; изменения
sortednames: sort some-names  ; здесь блок некоторых имен был отсортирован
print first sortednames  ; вот 3 разных способа выбрать 1-й предмет:
print sortednames/1 
print pick sortednames 1 
print second sortednames   ; 3 разных способа выбрать второй предмет:
print sortednames/2
print pick sortednames 2
find some-names "John"
first find some-names "John"
find/last some-names "John" 
select some-names "John"   ; использовать серии как словари
reverse sortednames 
length? sortednames 
head sortednames 
next sortednames 
back sortednames 
last sortednames 
tail sortednames  
at sortednames 2
skip sortednames 1
extract sortednames 3  ; каждый третий предмет
index? sortednames 
insert (at sortednames 3) "Lee" 
append sortednames "George" 
remove sortednames 
remove find sortednames "Mike" 
change sortednames "Phil" 
change third sortednames "Phil"
poke sortednames 3 "Phil" 
copy/part sortednames 2 
replace/all sortednames "Lee" "Al"
probe form sortednames
probe mold sortednames
join some-names sortednames 
intersect sortednames more-names  
difference sortednames more-names 
exclude sortednames more-names 
union sortednames more-names 
unique sortednames 
clear sortednames
empty? sortednames
probe same-names
probe more-names

index-num: length? more-names
print pick more-names index-num
print pick more-names (index-num - 1)
print pick more-names (random length? more-names)

index-num: ((index? (find more-names "Tom")) - 1)
print pick more-names index-num ; 4 способа выбрать элементы по переменному 
                                ; индексу
print more-names/:index-num
print compose [more-names/(index-num)]
print reduce [more-names/(index-num)]

READ считывает данные из файла побайтно, LOAD выполняет ПРЕОБРАЗОВАНИЕ. "WRITE" записывает серию байтов в файл, "SAVE" выполняет ПРЕОБРАЗОВАНИЕ:

save %names.txt more-names         ; данные серии, сохраненные в текстовый файл
loaded-names: load %names.txt      ; используйте "load", чтобы прочитать его в 
                                   ; переменной
write %names2.txt mold more-names  ; серия сохранена, но С КВАДРАТНЫМИ 
                                    ; КРОНШТЕЙНАМИ
loaded-names2: load %names2.txt    ; "load" также правильно загружает этот файл
read-names: to-block read %names.txt  ; "read" требует преобразования "to-block"
read-names2: to-block read %names2.txt  ; блок внутри блока
probe read-names2                       ; [["John" "Phil" "Tom" "Mike"]]
first read-names2                       ; ["John" "Phil" "Tom" "Mike"]

Работа со сжатыми блоками данных:

write/binary %compressed.dat compress mold more-names  ; сжать и сохранить
probe load decompress read/binary %compressed.dat  ; читать и распаковывать
save %compressed.dat compress mold more-names  ; ещё один способ сэкономить
probe load decompress load %compressed.dat  ; и загрузить сжатую серию

Увеличение счетчика (аналогично функциям "repeat" (повтор) и "for" (для)):

count: 0
foreach item items [
    count: count + 1
    print rejoin ["^/Item #" count ": " item]
]

Вложенный блок:

big-block: [
    [may june july] 
    [ 
        [1 2 3] 
        [
            [yes no]
            [monday tuesday friday]
        ]
    ]
]

Отступ облегчает чтение блока, но не обязателен:

big-block: [[may june july][[1 2 3][[yes no][monday tuesday friday]]]]

probe first big-block          ; 3 способа получить первый предмет в блоке
probe big-block/1
probe pick big-block 1
probe second big-block        ; 3 способа получить второй предмет в блоке
probe big-block/2
probe pick big-block 2 
probe first second big-block     ; 1-й блок во 2-м блоке в биг-блоке
probe big-block/2/1
probe second second big-block    ; 2-й блок во 2-м блоке в биг-блоке
probe big-block/2/2
probe first second second big-block
probe big-block/2/2/1
probe second second second big-block
probe big-block/2/2/2
probe big-block/2/2/2/1
probe big-block/2/2/2/2
probe big-block/2/2/2/3

Блок контактной информации:

users: [
    "John Smith" "123 Tomline Lane Forest Hills, NJ" "555-1234"
    "Paul Thompson" "234 Georgetown Pl. Peanut Grove, AL" "555-2345"
    "Jim Persee" "345 Pickles Pike Orange Grove, FL" "555-3456"
    "George Jones" "456 Topforge Court Mountain Creek, CO" ""
    "Tim Paulson" "" "555-5678"
]

Отсортируйте копию блока по первому столбцу (группы из каждых 3 последовательных элементов). Без копии ("copy") исходный список будет постоянно изменен:

probe sort/skip copy users 3

Чтобы отсортировать по любому другому столбцу, сначала преобразуйте блок во вложенный блок блоков (строки данных столбца):

new-users: copy []
foreach [name address phone] users [
    append/only new-users reduce [name address phone]
] ; append/only inserts blocks as blocks, instead of as individual items
editor new-users

Сортировать по 2-му полю (по адресу) по возрастанию:

field: 2  sort/compare new-users func [a b] [(at a field) < (at b field)]
editor new-users

Сортировать по убыванию:

field: 2  sort/compare new-users func [a b] [(at a field) > (at b field)]
editor new-users

"Сгладьте" блок обратно в исходное состояние (без вложенных блоков блоков):

users: copy []
foreach block new-users [append users reduce block]
editor users

Извлечь столбцы:

probe extract users 3           ; столбец имени (каждый третий элемент)
probe extract/index users 3 2   ; столбец адреса (пропустить 3, начиная со 2)
probe extract/index users 3 3   ; телефонная колонка (пропустите 3, начиная с 3)

Преобразуйте весь блок в строку:

probe form users

Получите группы из 3 последовательных предметов:

foreach [name address phone] users [ 
    print rejoin [
        "^/Name:     " name 
        "^/Address:  " address 
        "^/Phone:    " phone 
    ]
]

Выведите номера телефонов для всех имен, содержащих букву "а":

foreach name (extract users 3) [
    if find name "a" [
        print pick users ((index? find users name) + 2)
    ]
]

Добавить в конец списка:

append users ["Joe Thomas" "" "555-321-7654"]

Добавить значения переменных ('Repend is' reduce + 'append)

name: "Alex Sharp"  address: "937 Boll Rd"  phone: "555-294-2834"
repend users [name address phone]

Вставить по определенному индексу:

insert (at users 4) [
    "Tom Adams" "321 Way Lane Villageville, AZ" "555-987-6543"
]

Удалите один и несколько элементов:

remove (at users 4)  ; remove 1 item
remove/part (at users 4) 2  ; remove 2 items
change (at users 1) "Jonathan Smith"
remove (at users 1) insert (at users 1) "Jonathan Smith"
foreach item users [
    replace item "John Smith" "Jonathan Smith"
]

Получение одного и нескольких элементов:

copy/part users 3
copy/part (at users 4) 3
copy at tail users -3
copy/part (at users 7) 3
copy/part (find users "Jim Persee") -3
copy/part (skip (find users "Jim Persee") -6) 3
alert form (copy/part users 3)

chosen: request-list "Choose a person: " (extract users 3)
alert form reduce [copy/part find users chosen 3]
alert reform [copy/part find users chosen 3]
chosen: request-list "Choose an address: " (extract/index users 3 2)
alert reform [copy/part at (find users chosen) -1 3]

Переместить позиции предметов:

x: ["one" "two" "three" "four" "five" "six"]
move/to (find x "five") 2
print x               ; позиция элемента изменена

x: ["asdf" "qwer" "zxcv" "uiop" "hjkl" "vbnm"]
y: head clear skip tail x -2
probe y               ; последние 2 объекта удалены

Вложенные блоки:

data: [
    1 2 3 [4 5 6]
    7 8 9 [0 9 8 7 6 5 4 3 2 1]
    3 4 5 [6 3 1 7 8 0] 
]
counter: 1
foreach [col1 col2 col3 col4] data [
    print rejoin [
        "Row: " counter newline
        "Column1: " col1 newline
        "Column2: " col2 newline
        "Column3: " col3 newline
        "Column4 (sorted): " (sort col4) newline newline
    ]
    counter: counter + 1
]

Каталоги - это просто списки файлов - работают все операции серии:

foreach file read %. [
    if (suffix? file) = %.tester [
        rename file to-file (replace to-string file ".tester" ".test")
    ]
]
list-dir

foreach line reverse copy system/console/history [print line]

Вот полезный уникальный генератор строк, демонстрирующий функцию замены

replace/all replace/all replace/all replace/all form now/precise trim {
    /} "" ":" "x" "-" "q" "." ""

11.3 Строки

Строки текста работают так же, как блоки элементов данных - они просто список символов. Используйте все те же функции, которые используются для управления элементами в блоке, чтобы управлять списком символов в строке текста:

the-string: "abcdefghijklmnopqrstuvwxyz"

; 3 разных способа получить только 7-й символ:

pick the-string 7
the-string/7 
seventh the-string

; получить оставшиеся 7 символов строки:

copy/part the-string 7

; получить нужные 7 символов строки:

copy at tail the-string -7

; получить 7 символов из середины строки, начиная с 12-го символа:

copy/part (at the-string 12) 7

; получить 7 символов из середины строки, начиная с 7 символов от буквы "m":
copy/part (find the-string "m") -7

; получить 7 символов из середины строки, начиная с 12 символов назад 
; с буквы "t":

copy/part (skip (find the-string "t") -12) 7

; Измените "cde" на "123"

replace the-string "cde" "123"

; Несколько способов изменить седьмой символ на "7"

change (at the-string 7) "7"
poke the-string 7 #"7"  ; символ фунта относится к одному символу
poke the-string 7 (to-char "7")     ; другой способ использования одиночных 
                                    ; символов
print the-string

; Удалите 15 символов, начиная с 3-й позиции:

remove/part (at the-string 3) 15
print the-string

; Вставьте 15 символов, начиная с 3-й позиции:

insert (at the-string 3) "cdefghijklmnopq"
print the-string

; Вставьте 3 экземпляра "- +" в начало строки:

insert/dup head the-string "-+" 3
print the-string

; Замените каждый экземпляр "-+ " на " ":
print the-string

; Получить каждый третий символ из строки:

extract the-string 3

11.4 Управление файлами и чтение/запись из/в различные источники данных/протоколы

Вот несколько примеров функций, демонстрирующих операции управления файлами:

rename %temp.txt %temp2.txt       ; изменить имя файла
write %temp.txt read %temp2.txt   ; копировать файл
write/append %temp2.txt ""   ; создать файл (или, если он существует, ничего
                             ; не делать)
delete %temp2.txt
change-dir %../
what-dir 
list-dir
make-dir %./temp
print read %./
osfile: to-local-file filename   ; REBOL использует собственный 
                                 ; многоплатформенный синтаксис.
to-rebol-file osfile  ; Преобразование из нотации файлов ОС обратно в REBOL
the-url: http://website.com/subfolder
split-path the-url   ; "split-path" разбивает любой файл или URL на 2 части

Вот несколько примеров чтения и записи данных в и из различных источников данных и протоколов:

print read http://rebol.com  ; "read" извлекает данные из многих источников
editor http://rebol.com     ; встроенный редактор также может читать многие 
                            ; источники
print read %./   ; символ % используется для локальных файлов и папок
editor %./
write %temp.txt "test"   ; write принимает ДВА параметра (имя файла и данные)
editor %temp.txt
editor request-file/only   ; "only" уточнение ограничивает выбор до 1 файла
write clipboard:// (read http://rebol.com)  ; 2nd параметр в скобках
editor clipboard://
print read dns://msn.com   ; REBOL может читать многие встроенные протоколы
print read nntp://public.teranews.com 
write/binary %/c/bay.jpg (read/binary http://rebol.com/view/bay.jpg)
write/binary %tada.wav (read/binary %/c/windows/media/tada.wav)
write/binary %temp.dat (compress read http://rebol.com)  ; СЖАТЬ ДАННЫЕ
print decompress read/binary %temp.dat                   ; ДЕКОМПРЕСС ДАННЫЕ
print read ftp://user:pass@website.com/name.txt       ; user/pass обязательный
write ftp://user:pass@website.com/name.txt "text"     ; user/pass обязательный
editor ftp://user:pass@website.com/name.txt  ; можно сохранять изменения на 
                                             ; сервере!
editor pop://user:pass@website.com    ; читать все электронные письма в этом 
                                      ; аккаунте
send user@website.com "Hello"   ; отправить электронное письмо
send user@website.com (read %file.txt)   ; отправить текст из этого файла по 
                                         ; электронной почте
send/attach user@website.com "My photos" [%pic1.jpg %pic2.jpg pic3.jpg]

11.5 Подробнее о пользовательских функциях

Любую строку или блок данных можно рассматривать как функцию, используя "do":

some-actions: [
    alert "Here is one action." 
    print "Here's a second action."
    write %/c/anotheraction.txt "Here's a third action."
]
do some-actions

Скопируйте, вставьте и запустите любой код с помощью "do":

write clipboard:// {alert "This code was run from the clipboard"}
do read clipboard://

write %some-code.r {
    REBOL [] ; исполняемый код, сохраненный в файл, должен начинаться с этого 
             ; заголовка
    print rejoin [newpage "The code in %some-code.r just ran." newline]
}
do %some-code.r

write ftp://user:pass@site.com/public_html/some-code.r {
    REBOL []
    print "The code in http://site.com/some-code.r just ran."
}
do http://site.com/some-code.r

Вы можете выполнить командой "do" любой присоединенный текст:
the-word: to-word request-list "choose a word:" (first system/words)
do rejoin ["help " the-word]

"Does" может создать ярлык функции, когда список параметров не требуется:

cls: does [prin "^(1B)[J"]          ; то же, что и "prin newpage"
cls

По умолчанию переменные в функциях ГЛОБАЛЬНЫЕ:

x: 10
change-x-globally: func [y z] [x: y + z]
change-x-globally 10 20
print x

Вы можете изменить это поведение по умолчанию с помощью параметра "/local":

x: 10
change-x-locally: func [y z /local x] [x: y + z]
change-x-locally 10 20
print x

Вот как включить параметры уточнения в ваши функции:

compute: func [x y /multiply /divide /subtract] [
    if multiply [return x * y]
    if divide   [return x / y]
    if subtract [return x - y]
    return x + y
]
compute/multiply 10 20
compute/divide 10 20
compute/subtract 10 20
compute 10 20

Вот как включить документацию по функциям (используется 'help') и потребовать типы данных для параметров:

concatenate-string-or-num: func [
    "This function will only concatenate strings or integers."
    val1 [string! integer!] "First string or integer"
    val2 [string! integer!] "Second string or integer"
] [
    join val1 val2
]
help concatenate-string-or-num
concatenate-string-or-num "Hello " "there."  ; это работает правильно
concatenate-string-or-num 10 20              ; это работает правильно
concatenate-string-or-num 10.1 20.3          ; это создает ошибку

Использование "do" для метапрограммирования:

do [
    print "^/This example builds a line of code, and then executes it.^/"
    function: ask "Enter a function, such as 'print' or 'editor':  "
    parameter: ask "Enter a parameter, such as some random text:  "
    print rejoin [function { "} parameter {"}]
    do rejoin [function { "} parameter {"}]
    do compose [(to-word function) (parameter)]
    print "That's a very simple way to accomplish metaprogramming tasks."
]

Сохраняйте функции в файлы библиотеки. Импортируйте библиотеки с помощью "do":

write %imported-func.r {
    REBOL [title: "play-sound"]
    play-sound: func [sound-file] [
        wait 0
        insert sound-port: open sound:// load sound-file
        wait sound-port
        close sound-port
    ]
}
do %imported-func.r
play-sound %/C/WINDOWS/Media/chimes.wav

Получить код любой функции в виде текстовой строки:

editor mold :read-cgi

Переопределите встроенную (мезонинную) функцию:

request: do replace/all mold :request "bold" ""
request/ok/type "An alert without bold text" 'alert

11.6 Управление событиями с графическим интерфейсом

"Feel" и "Engage" вместе обнаруживают события:

view layout [
    text "Mouse me." feel [
        engage: func [face action event] [
            if action = 'up [print "You just released the mouse."]
        ]
    ]
]

Переменные "f", "a" и "e" - это ярлыки, используемые для обозначения лица, действия и события. Например, "e/offset" получает координату щелчка мыши:

print "Click anywhere in the window, then click the text."
view center-face layout [
    size 400x200
    box 400x200 feel [
        engage: func [f a e] [
            print rejoin ["Mouse " a " at " e/offset]
        ]
    ]
    origin 
    text "Click me" [print "Text clicked"] [print "Text right-clicked"]
    box blue [print "Box clicked"]
]

Вот общий код щелчка и перетаскивания:

movestyle: [
    engage: func [f a e] [
        if a = 'down [initial-position: e/offset]
        if find [over away] a [
            f/offset: f/offset + e/offset - initial-position
            show f
        ]
    ]
]
view layout [
    size 600x400
    text "This is some text" feel movestyle
]

Этот код перетаскивания гарантирует, что перетаскиваемый элемент размещается как верхняя грань в z-порядке макета:

movestyle: [
    engage: func [f a e] [
        if a = 'down [
            initial-position: e/offset
            remove find f/parent-face/pane f
            append f/parent-face/pane f
        ]
        if find [over away] a [
            f/offset: f/offset + (e/offset - initial-position)
        ]
        show f
    ]
]
view layout/size [
    style moveable-object box 20x20 feel movestyle
    at random 600x400 moveable-object (random 255.255.255)
    at random 600x400 moveable-object (random 255.255.255)
    at random 600x400 moveable-object (random 255.255.255)
    at random 600x400 moveable-object (random 255.255.255)
    at random 600x400 moveable-object (random 255.255.255)
    text "This text and all the boxes are movable" feel movestyle
] 600x440

Этот пример следует за всеми движениями мыши:

view center-face layout [
    size 600x440
    at 270x209 b: btn "Click Me!" feel [
        detect: func [f e] [
            if e/type = 'move [
                if (within? e/offset b/offset 59x22) [
                    b/offset: b/offset + ((random 50x50) - (random 50x50))
                    if not within? b/offset -59x-22 659x462 [
                        b/offset: 270x209
                    ]
                    show b
                ]
            ]
            e
        ]
    ]
]

Чтобы перехватить другие события, используйте "insert-event-func". Этот пример перехватывает и отвечает на события закрытия:

insert-event-func [
    either event/type = 'close [
        really: request "Really close the program?"
        if really = true [unview]
    ] [event]  ; always return other events
]
view center-face layout [size 600x400]

Этот пример перехватывает события изменения размера:

insert-event-func [
    either event/type = 'resize [
        fs: t1/parent-face/size
        t1/offset: fs / 2x2
        t2/offset: t1/offset - 50x25
        t3/offset: t1/offset - 25x50
        show gui  none
    ] [event]
]
svv/vid-face/color: white
view/options gui: layout [
    across
    t1: text "50x50"
    t2: text "- 50x25"
    t3: text "- 25x50"
] [resize]

11.7 Больше различных примеров графического интерфейса, методов, виджетов (некоторые сетки) и т.д.

Ещё несколько встроенных стилей виджетов:

print "GUI Output:^/"
view layout [
    h1 "Some More GUI Widgets:"
    box red 500x2
    drop-down 200 data system/locale/months [
        a/text: join "Month:  " value show a
    ]
    a: field
    slider 200x18 [bar1/data: value show bar1]
    bar1: progress
    scroller 200x16 [bar2/data: value show bar2]
    bar2: progress
    across 
    toggle "Click here" "Click again" [print value]
    rotary "Click" "Again" "And Again" [print value]
    choice "Choose" "Item 1" "Item 2" "Item 3" [print value]
    return
    x: radio y: radio z: radio
    btn "Get Radio States" [print [x/data y/data z/data]]
    return
    led
    arrow
    below
    code "Code text"
    tt "Typewriter text"
    text "Little Text" font-size 8
    title "Centered title" 500
]

Вы можете разместить изображения на большинстве виджетов:

view layout [
    area 400x400 load http://rebol.com/view/bay.jpg effect [
        Fit Flip Emboss 
    ]
]

И ещё много эффектов:

effects:  [
  invert contrast 40 colorize 0.0.200 gradcol 1x1 0.0.255 255.0.0 tint 100
  luma -80 multiply 80.0.200 grayscale emboss flip 0x1 flip 1x0 rotate 90
  reflect 1x1 blur sharpen aspect tile tile-view
]

Градиенты (блеклые цвета) можно применять как эффект:

view layout [area effect [gradient red blue]]

view layout [
    size 500x400
    backdrop effect [gradient 1x1 tan brown]
    box effect [gradient 123.23.56 254.0.12]
    box effect [gradient blue gold/2]
]

Переключение между отдельными панелями в макете одного окна:

gui: layout [
    across
    btn "Fields"      [window/pane: pane1 show window]
    btn "Text List"   [window/pane: pane2 show window]
    return
    window: box 400x200
]
pane1: layout/tight [field 400 field 400 area 400]
pane2: layout/tight [text-list 400x200 data system/locale/days]
window/pane: pane1
view center-face gui

Изменение глобального свойства цвета лица:

svv/vid-face/color: white
alert "New global background color is now white."

Отвечая на клавиши:

view center-face layout [
    size 600x440 
    h3 "Press the left or right arrow key"
    key keycode [left]  [alert "You pressed the LEFT arrow key"]
    key keycode [right] [alert "You pressed the RIGHT arrow key"]
    btn #"a" "Click Me or Press the 'a' Key" [alert "clicked or pressed"]
]

Вот полезный сценарий для отображения всех кодов клавиш:

insert-event-func func [f e] [if e/type = 'key [print mold e/key] e]
view layout [text "Type keys to see their character/keycode"]

Как обращаться к главному окну макета:

view gui: layout [
    btn1: btn "Button 1"
    btn2: btn "Remove all widgets from window" [
        foreach item system/view/screen-face/pane/1/pane [
            remove find system/view/screen-face/pane/1/pane item
        ]
        show gui
    ]
]

Обнаружение графических коллизий с использованием функции "within" (внутри):

view center-face layout [
    size 400x400
    btn1: btn red
    at 175x175 btn2: btn green
    box 0x0 rate 0 feel [engage: func [f a e] [if a = 'time [
        btn1/offset: btn1/offset + 5x5
        show btn1
        if within? btn1/offset btn2/offset 1x1 [alert "Collision" unview]
    ]]]
]

Более простой пример столкновения с использованием функции "overlap" (перекрытия):

gui: view/new center-face layout [
    size 400x400
    btn1: btn red
    at 175x175 btn2: btn green
]
forever [
    wait .02
    btn1/offset: btn1/offset + 5x5  show gui 
    if overlap? btn1 btn2 [alert "Collision"]
    if btn1/offset/1 > 300 [alert "done" quit]
]

Используйте "to-image", чтобы создать снимок экрана любого макета:

picture: to-image layout [
    page-to-read: field "http://rebol.com"
    btn "Display HTML"
]
save/png %layout.png picture     ; сохранить изображение в файл
browse %layout.png

Простой информационный экран:

flash "Waiting..."  wait 3  unview
inform layout [btn "Click Me" [flash "Waiting..." wait 3 unview]]

Вот все основные слова графического интерфейса, которые вам следует знать:

VID-STYLES--GUI-WIDGETS: [
    face blank-face IMAGE BACKDROP BACKTILE BOX BAR SENSOR KEY BASE-TEXT
    VTEXT TEXT BODY TXT BANNER VH1 VH2 VH3 VH4 LABEL VLAB LBL LAB TITLE
    H1 H2 H3 H4 H5 TT CODE BUTTON CHECK CHECK-MARK RADIO CHECK-LINE
    RADIO-LINE LED ARROW TOGGLE ROTARY CHOICE DROP-DOWN ICON FIELD INFO
    AREA SLIDER SCROLLER PROGRESS PANEL LIST TEXT-LIST ANIM BTN BTN-ENTER
    BTN-CANCEL BTN-HELP LOGO-BAR TOG
]
LAYOUT-WORDS: [
    return at space pad across below origin guide tab tabs indent style
    styles size backcolor backeffect do
]
STYLE-FACETS--ATTRIBUTES: [
    edge font para doc feel effect effects keycode rate colors texts help
    user-data with bold italic underline left center right top middle
    bottom plain of font-size font-name font-color wrap no-wrap as-is
    shadow frame bevel ibevel
]
SPECIAL-STYLE-FACETS: [
    ARROW: [up right down left]  ROTARY: data  CHOICE: data  DROP-DOWN: 
    [data rows]  FIELD: hide  INFO: hide  AREA: hide  LIST: [supply map
    data]  TEXT-LIST: data  ANIM: [frames rate]
]

Особенно мощный виджет "list" (список) может создавать сетки данных не только из текстовых полей, но и из виджетов ЛЮБОГО типа:

y: read %.   c: 0   x: copy []
foreach i y [append/only x reduce [(c: c + 1) i (size? to-file i)]]
slider-pos: 0
view center-face layout [
    across space 0
    the-list: list 400x400 [
        across  space 0x0
        text 50 purple
        text 250 bold [editor read to-file face/text]
        text 100 red italic
        return box green 400x1
    ] supply [
        count: count + slider-pos
        if none? q: pick x count [face/text: none exit]
        face/text: pick q index
    ]
    scroller 16x400 [
        slider-pos: (length? x) * value
        show the-list
    ]
]

Более мощный пример сетки, реализованный с помощью виджета "list":

REBOL [title: "Table/Grid/Listview Example"]

headers: ["Numbers" "Text" "Dates"]

x: [
    [1   "1"   1-1-2012]
    [11  "11"  1-2-2012]
    [2   "2"   1-3-2012]
]

do decompress #{
789CC518C98EDB36F4AEAF78500FB11228B2074D0AA8B3A01F904BAF860EB245
D9CAD0A2225133720CFF7B1F77D24BE324456A60C626F9F69D1C5B4A86015E4A
3A922778B3199B7445D9FA1996F6670E8763118D21E004CB298735EBF6B02CCE
4EC9AEE3FB74E8CA3581A5B7C8615E447B8D3741B46674DCB5430E94B41BBE7D
822D292BD20F91FA36FC25F8E118F5A423258706341E2C23C04FD975A4ADC0C7
819E7C664D0BCB781B237C9C713271888BA83821CD9946F0B7A355734AEFCDB0
1F38D945949595DA22550EF5D8AE615995BC4CEB8612C87AF26524032FB4644D
0D7AC783CACD9E5C65ACA5FB4C625B8842A9C5B9309D26253ED672FA5B08E3B0
2CD8B065AF401BB9161A0FE50BF945320B56C2A6E1194C2885B45C4D4BFECBCD
56A3BDAE98CAC5303870D663C82C606682B29E929388331FC12908D265119C0B
529F610E33839EC22241D2211517C28E1E740DFEAB279835F00E3E271060845C
14B2B40826554FAA11D3CE91B2B09E8E3692FE3D68FE37775D720A29D75BE851
CAE9C47EDA78B5D51D819CD24E43119B4E8B7A72BAB29EA7CA4546DBBA21B432
0A92866F490F128CF55814726819F7D69E4062335BB35D57F618F79A5A092BA4
35C3DA5582A49CC02388E54A2F9594C50FD0B9BF484719CEF8B4889E0956E075
CF28350AAA555AEED8D85A4F0E69C7B01ACB2F0CBB00C6B85A1D3EBAF4C0EC58
6A44BB5584D0F798030666AE2B05CD842F0CB32CA01788AF7F0C14F5E8C9D07C
25E9A66F6C25EB48BF262D2F37C468213A970043DAB268672F0D79CD501942DA
B4C6369475654BB2452680E04F9194F3692E516983012BB6B345EE2FE02D383E
279077B9E598DD2131AFDF4948AE85E9D18A15AAE951F5B4F6BB4D92681369CC
126D54363D2C3EFA6C25CCD84AE564EEA314A0561D6F18561B212FD2142A032D
F76CE4E0357865CBC259B56E30D92B46861FB1A3C4F0DC03336B14A1A7AF750A
EF1709B22DAB2AA54D4B0CD3B014600B9E647F6E50890DE698A927A29567BCE1
58552A529723C5C6FE5755A9E163C082228BC46F79EC178F9D4F89BDF4E9DA45
B4E0040F22447BC2C7BE5501DA92D754910C6BFB597B083C278ABBAE478E80C2
8F639D15ED4030B7A5CB44EE4E5280C48777992B9CB363588AFF2343FD8D7439
0345348FE1E76C8407BC1F09DC3FDA0E6007AFBF150B88552B535A42FC141721
0D254A60095FFD33E52512A355FA5D7A7F123CEA9EEDBE2B38844B6E60A3C90B
BB7AC4D138B399A1206C970086CECC882E7792DBEDF929B4A625736E5161B20C
855126358089D5C66F0C3BAC5463D7511C08825E475E48FB84718B851F9BA1C8
75EC8F0C1BDFEBB6E1A2D2FA7B77BFCFDFCBBF0F1F9404122FD7E8EF5489370A
B6ACC52BC297DC28E2F31026CD4DB600991A6EEDA2DD8256BB20D4DD1C99CF3D
01E4A1EA2F6BDBBC3C1692F717116E44CCA6036D2A34F65E8C2DDA0CED062BBD
9D06B0DF12BF3B3762E701DE8C1DF635373D288238318AFB831E46826B442DF9
BB99643DAAF29CDF88E90B6070E1F1012ED5A230287CA94BCAD38ABD62540DBC
94C2E31493034E69753D104F3C214D8AF1A0653C0463573F7CC5D140F8B96E7A
8CD4966C4A8E898CB54F51C442EFD14F02648C3BE90ED36BC335621AEA01165A
7966D44E2CEEA5DD5B2860642E12ADF3299DF0EC766A9764F24FF0F7454ADBAB
525D3BB926D329BC91E8F2FE35796485D04E399DC44E288939C1E21EED2FBCAC
530112C4101C9CA78E36826FC691FC8E10AE2F86B748CC4B0187C11A6CDB6075
E11F5EB590A8854173DD9FB640F3A95828F5C905448C59A46A785064B04EF7AE
C4B093023363508A81D1543E6C0AB5AC69A26BE8CD5C6F190F19664AB59B4B58
7869D53532E873A691AAC3E0B6182AF9EDA1514EDD29CCA70FF3C88E856E86C6
A39919783FCEFD693A89BE3511FFD0A86DEE25105CF0641F066B66D1B5223DD8
B9195A154429B5151F4ABC350D628693CF5FE666211DAF59C36AE49CB5560B25
2476315861F83FAB1E0B2BECDCD1B71EBD9C2C6650B03E39887FDB23621E72C3
F888C301354F5B4396E319D48450701DF028E604317059979EB1928C0C79FBB6
2173F1DC44B9D156E916F7312CFE9850D72014A5B91FECD483D32366E2536C1F
19F797225CE5A1BE8EA9FB9A0B07FF2E2D6DBF2694828C5E0D2015B74969A1CF
FDF7B34E101F44D4AE90721C3D35507DF3702AE799C15E211C6139A5AA53F45A
7199BB71DC05971DF4C3801AF6C08E7DFAA299EBBBBE78E5A0DA7C3A2FFC7BF9
5B252884CED06E385EE3FA4CF6E26FCD2AA43A765884DC7304A40BF35A118089
F12404BC0CD761894BCF68DECDAF039F5356D0C7C87BF1B6CFC2764FBD093BD5
CC83F03FD2FC2B1641170000
}
view center-face gui: layout gui-block

Другие параметры, такие как раскрашивание строк и указание типов данных столбцов с использованием сжатого кода сетки, приведенного выше, показаны в следующем примере. Это очень полезный инструмент для ввода, визуализации и демонстрации данных:

REBOL [title: "Table/Grid/Listview Example With Expanded Features"]

headers: ["Numbers" "TEXT (Note Sort)" "Dates"] ; НЕОБХОДИМЫЕ НАЗВАНИЯ КОЛОНОК

; ВСЕ ЭТИ ДОПОЛНИТЕЛЬНЫЕ ПАРАМЕТРЫ НАСТРОЙКИ *** НЕОбЯЗАТЕЛЬНЫ ***:

x: [[1 "1" 1-1-2012][11"11"1-2-2012][2"2"1-3-2012]]  ; некоторые данные по умолчанию

colors: [blue black red]    ; указываем цвета столбцов
empty-space: 235            ; размер пустой области графического интерфейса 
                            ; для отображения под сеткой
svv/vid-face/color: white   ; цвет графического интерфейса по умолчанию

; Вот как добавить код макета графического интерфейса, чтобы он отображался 
; над сеткой: 

gui-block: {
    h3 "RIGHT-CLICK/DRAG HEADERS TO RESIZE COLUMNS.  RESIZE WINDOW..."
    text "Click headers to sort (note that sort is DATA-TYPE SPECIFIC)."
    text "Notice Arrow Keys, PgUp/PgDn Keys, Scroll Bar, and highliting"
    text "Click any cell to edit data. Buttons load and save data to HD."
}

; Следующая строка автоматически подгоняет сетку под окно графического 
; интерфейса с измененным размером.:

insert-event-func [either event/type = 'resize [resize-fit none] [event]]

do decompress #{
    789CC518C98EDB36F4AEAF78500FB11228B2074D0AA8B3A01F904BAF860EB245
    D9CAD0A2225133720CFF7B1F77D24BE324456A60C626F9F69D1C5B4A86015E4A
    3A922778B3199B7445D9FA1996F6670E8763118D21E004CB298735EBF6B02CCE
    4EC9AEE3FB74E8CA3581A5B7C8615E447B8D3741B46674DCB5430E94B41BBE7D
    822D292BD20F91FA36FC25F8E118F5A423258706341E2C23C04FD975A4ADC0C7
    819E7C664D0BCB781B237C9C713271888BA83821CD9946F0B7A355734AEFCDB0
    1F38D945949595DA22550EF5D8AE615995BC4CEB8612C87AF26524032FB4644D
    0D7AC783CACD9E5C65ACA5FB4C625B8842A9C5B9309D26253ED672FA5B08E3B0
    2CD8B065AF401BB9161A0FE50BF945320B56C2A6E1194C2885B45C4D4BFECBCD
    56A3BDAE98CAC5303870D663C82C606682B29E929388331FC12908D265119C0B
    529F610E33839EC22241D2211517C28E1E740DFEAB279835F00E3E271060845C
    14B2B40826554FAA11D3CE91B2B09E8E3692FE3D68FE37775D720A29D75BE851
    CAE9C47EDA78B5D51D819CD24E43119B4E8B7A72BAB29EA7CA4546DBBA21B432
    0A92866F490F128CF55814726819F7D69E4062335BB35D57F618F79A5A092BA4
    35C3DA5582A49CC02388E54A2F9594C50FD0B9BF484719CEF8B4889E0956E075
    CF28350AAA555AEED8D85A4F0E69C7B01ACB2F0CBB00C6B85A1D3EBAF4C0EC58
    6A44BB5584D0F798030666AE2B05CD842F0CB32CA01788AF7F0C14F5E8C9D07C
    25E9A66F6C25EB48BF262D2F37C468213A970043DAB268672F0D79CD501942DA
    B4C6369475654BB2452680E04F9194F3692E516983012BB6B345EE2FE02D383E
    279077B9E598DD2131AFDF4948AE85E9D18A15AAE951F5B4F6BB4D92681369CC
    126D54363D2C3EFA6C25CCD84AE564EEA314A0561D6F18561B212FD2142A032D
    F76CE4E0357865CBC259B56E30D92B46861FB1A3C4F0DC03336B14A1A7AF750A
    EF1709B22DAB2AA54D4B0CD3B014600B9E647F6E50890DE698A927A29567BCE1
    58552A529723C5C6FE5755A9E163C082228BC46F79EC178F9D4F89BDF4E9DA45
    B4E0040F22447BC2C7BE5501DA92D754910C6BFB597B083C278ABBAE478E80C2
    8F639D15ED4030B7A5CB44EE4E5280C48777992B9CB363588AFF2343FD8D7439
    0345348FE1E76C8407BC1F09DC3FDA0E6007AFBF150B88552B535A42FC141721
    0D254A60095FFD33E52512A355FA5D7A7F123CEA9EEDBE2B38844B6E60A3C90B
    BB7AC4D138B399A1206C970086CECC882E7792DBEDF929B4A625736E5161B20C
    855126358089D5C66F0C3BAC5463D7511C08825E475E48FB84718B851F9BA1C8
    75EC8F0C1BDFEBB6E1A2D2FA7B77BFCFDFCBBF0F1F9404122FD7E8EF5489370A
    B6ACC52BC297DC28E2F31026CD4DB600991A6EEDA2DD8256BB20D4DD1C99CF3D
    01E4A1EA2F6BDBBC3C1692F717116E44CCA6036D2A34F65E8C2DDA0CED062BBD
    9D06B0DF12BF3B3762E701DE8C1DF635373D288238318AFB831E46826B442DF9
    BB99643DAAF29CDF88E90B6070E1F1012ED5A230287CA94BCAD38ABD62540DBC
    94C2E31493034E69753D104F3C214D8AF1A0653C0463573F7CC5D140F8B96E7A
    8CD4966C4A8E898CB54F51C442EFD14F02648C3BE90ED36BC335621AEA01165A
    7966D44E2CEEA5DD5B2860642E12ADF3299DF0EC766A9764F24FF0F7454ADBAB
    525D3BB926D329BC91E8F2FE35796485D04E399DC44E288939C1E21EED2FBCAC
    530112C4101C9CA78E36826FC691FC8E10AE2F86B748CC4B0187C11A6CDB6075
    E11F5EB590A8854173DD9FB640F3A95828F5C905448C59A46A785064B04EF7AE
    C4B093023363508A81D1543E6C0AB5AC69A26BE8CD5C6F190F19664AB59B4B58
    7869D53532E873A691AAC3E0B6182AF9EDA1514EDD29CCA70FF3C88E856E86C6
    A39919783FCEFD693A89BE3511FFD0A86DEE25105CF0641F066B66D1B5223DD8
    B9195A154429B5151F4ABC350D628693CF5FE666211DAF59C36AE49CB5560B25
    2476315861F83FAB1E0B2BECDCD1B71EBD9C2C6650B03E39887FDB23621E72C3
    F888C301354F5B4396E319D48450701DF028E604317059979EB1928C0C79FBB6
    2173F1DC44B9D156E916F7312CFE9850D72014A5B91FECD483D32366E2536C1F
    19F797225CE5A1BE8EA9FB9A0B07FF2E2D6DBF2694828C5E0D2015B74969A1CF
    FDF7B34E101F44D4AE90721C3D35507DF3702AE799C15E211C6139A5AA53F45A
    7199BB71DC05971DF4C3801AF6C08E7DFAA299EBBBBE78E5A0DA7C3A2FFC7BF9
    5B252884CED06E385EE3FA4CF6E26FCD2AA43A765884DC7304A40BF35A118089
    F12404BC0CD761894BCF68DECDAF039F5356D0C7C87BF1B6CFC2764FBD093BD5
    CC83F03FD2FC2B1641170000
}

; ДОБАВИТЬ ЛЮБЫЕ ВИДЖЕТЫ И/ИЛИ КОД GUI, ЧТОБЫ ПОЯВЛЯТЬСЯ ПОД СЕТКОЙ, ЗДЕСЬ:

append gui-block [

    ; ЗАМЕНИТЕ "BTN" НА "KEY", ЧТОБЫ СКРЫТЬ КНОПКИ И ПО-прежнему ИСПОЛЬЗОВАТЬ 
    ; ЯРЛЫКИ КЛЮЧЕЙ ИЗМЕНИТЬ/УДАЛИТЬ КНОПКИ И/ИЛИ ЯРЛЫКИ КЛАВИАТУРЫ ПРИ 
    ; НЕОБХОДИМОСТИ:
text "" return
btn "Insert (Ins)" keycode [insert] [add-line] 
btn "Remove (Del)" #"^~" [remove-line]  
btn "Move (CTRL+M)" #"^M" [move-line]
btn "Grow (+)" #"+" [resize-grid 1.333]
btn "Shrink (-)" #"-" [resize-grid .75]
btn "Fit (CTRL+R)" #"^R" [resize-fit]
return
btn "Load Blocked (CTRL+O)" #"^O" [load-blocked/request %blocked.txt]
btn "Save Blocked (CTRL+S)" #"^S" [save-blocked/request %blocked.txt]
btn "Load Flat (CTRL+U)" #"^U" [load-flat/request %flat.txt]
btn "Save Flat (CTRL+F)" #"^F" [save-flat/request %flat.txt]

; ЗАГРУЗИТЕ ФАЙЛ ДАННЫХ ПО УМОЛЧАНИЮ ЗДЕСЬ (вместо того, чтобы указывать его в 
; приведенном выше коде): 
; Обратите внимание, что функции load-flat и save-flat загружают "плоские" 
; блоки, которые представляют собой просто длинные последовательности значений 
; данных. Функции load-block и save-blocked загружают блоки, строки которых 
; заключены внутри выделенных блоков. Все эти функции предоставляют 
; необязательное уточнение "/request", которое позволяет пользователю выбрать 
; файл:

;  do [load-blocked %blocked.txt] 

]
view/options center-face gui: layout gui-block [resize]

11.8 Встраивание файлов (изображений, звуков, двоичных исполняемых файлов и т.д.) в код

Используйте этот скрипт для встраивания файлов:

system/options/binary-base: 64
editor picture: compress to-string read/binary to-file request-file/only

Вот как можно использовать приведенные выше данные:

view layout [image load (to-binary decompress picture)]

Вот пример некоторых данных изображения, созданных с помощью приведенного выше сценария:

logo-pic: load to-binary decompress #{
789C018A0375FC89504E470D0A1A0A0000000D49484452000000640000001808
020000008360CFB90000001374455874536F667477617265005245424F4C2F56
6965778FD916780000033249444154789CD599217402310C86F7CE6227B1481C
1637874362B1382C1687C4A15168240A89C5A2B058ECDEBE47DFFA429276DCEE
10FDCD582F97267FD33F2D7CF47ABDCF32D1ED76E7F3F9ED76FB4EE0743A8D46
A3B6A683A80FFE540562381C1E8FC7144D12DBEDB6951C3B9D4E91648DC7E34C
41B925465D349C14A2CA230BA65EA729E27C3E37CCB43CB228905A3525B1DBED
9A4CED93851C7C193088A0667C0D0603FB5640BFDFB7F648C0D0836B1C41C22E
11D7EBF57038F074BFDF534429BE2693891B4626CE1C59BC7CB95CDC99EEF7FB
66B349F922D65A4B4A8DE0D0B547B9DD85212B6B4CB4D3E994B055FEE8943566
30134626BBDA64052C974BD757A637B1DA2E599959A05EE61F4032D62C55EFBC
6EED01878954188DC80AE714C07126D24F91BBBE6265A129B3D96C2A4085BB64
459FEBF51A1B2692E5A9FA17A428B562EBE595A1F29650AD5C6B9525FD4621E0
A95D73491606F9046C94101A06178B4518E19122023655DA184B03ECA15BE98E
6D9D302E536E8D2C96A5FF0061458FEE9EAA045958720EDCFC82CF145A9E2C7C
52BC6CF0503B8C2B2200DAACD24698A4B710361E6421930E05A85E9484BE51B3
0885AE9727CB22A5591981B73D1AC6A58D2ABD5892DF46C5993DCFF25BC8828E
14538AACEB3390A43C59D890213B5D2AA3D2AC3C59ABD54ACE2E85C29E36DE42
162B8C0AC47F0942B512972CCCF0D91170ED6594ECC130288549ED44744DE52C
771381C571D5AFEDB14B2E79CB022F13C834A056049EFCE35C2A7449877A2B00
2D872635082FEA2D267D8BC047AD910D3875CE9247078A826259FC8234F264E1
9FAD4AAC52015465D973193B3755B611B417FB562A0C66C77EF7001F5463FD83
2CF20F83B2B8E0C22DAE760FA556B32AAF87B86A18C18259CFAA3567C250C7C3
1AE72CD95350531BD93FAE3B6CEADB33188174FCBBD77B7B7A0841DAB6C3EBEE
F13DE8696B6455E222ADCE23F162ECF644064709A47AA8FD3632BFAD78EA5E92
D947500C3BB04CAD419F3D5B05580DC127118E3D2866CAFB8AC6CAFCEB68F895
56796455CF47AAD741F5B957D4D751245980BD569729B723D742A964558FFB4D
EAB6A440BF6ACE54157EB028F7A730B695BDF749D05EA9C1B612C4CF0F396EDC
8E943F5C020000000049454E44AE426082CAEBA2D78A030000
}  
view layout [image logo-pic]

11.9 Запуск приложений командной строки

Вы можете запускать исполняемые функции, используя команду "call". Смотрите вывод команды "help call", чтобы увидеть множество доступных уточнений "call":

call/show "notepad.exe c:\config.sys"   ; запустить команду оболочки ОС

12. Порты

"Порты" в Rebol создаются с помощью функции "open":

help open

Порты обеспечивают детальный доступ к источникам данных, таким как файлы, электронная почта, сетевые подключения и т.д. эта строка:

write/append %temp.txt "1234"

Такой же как:

temp: open %temp.txt
append temp "1234"
close temp

Просмотрите все свойства объекта порта с помощью "probe":

temp: open %temp.txt
probe temp
close temp
temp: open %temp.txt
print temp/date
print temp/path
print temp/size
close temp

Только одно из свойств, активируемых при открытии файлового порта, включает установку разрешений на чтение, запись и выполнение для файла:

my-file: open %temp.txt
set-modes my-file [
    world-read: true
    world-write: true
    world-execute: true
]
close my-file

Обязательно изучите все остальные свойства порта, чтобы увидеть, как данные обрабатываются под капотом:

write %temp.txt ""
print read %temp.txt
temp: open %temp.txt
append temp "1234"
print temp/state/inBuffer
print read %temp.txt
update temp
print read %temp.txt
temp: head temp
insert temp "abcd"
print temp/state/inBuffer
print read %temp.txt
close temp
print read %temp.txt
append temp "1q2w3e4r"  ; (error)

Детализированный доступ, например, для чтения очень больших файлов, может управляться с помощью структуры порта:

x: open/direct/lines %input.txt
while [not empty? data: copy/part x 10] [
   probe data
   ask "continue..."
]
close file

12.1 Порты электронной почты

Порты позволяют работать с источниками данных способами, которые невозможны при использовании других функций. Например, этот пример требует загрузки ВСЕЙ почты в учетной записи, просто чтобы прочитать второе сообщение:

print second read pop://user:pass/site.com

Версия порта фактически загружает только одно сообщение из порта учетной записи. Обратите внимание, что порты отвечают на последовательные функции:

my-email: open pop://user:pass/site.com
print second my-email

12.2 Порты консоли

Доступом к консоли также можно управлять с помощью структуры порта:

print ""
q: open/binary/no-wait console://
forever [if wait q [print join "You typed:  " to-integer copy q]]

q: open/binary/no-wait console:// 
while [120 <> x: to-integer copy wait q] [print join "You typed:  " x]
print "Goodbye!" wait 2

12.3 Звуковые и другие аппаратные порты

Структура порта используется не только для доступа к структурам данных, но также к оборудованию и другим функциям. Акустическая система настроена как порт в Реболе. Воспроизведите звуки, открыв звуковой порт и вставив в него данные:

the-sound: load %/c/windows/media/tada.wav
insert s: open sound:// the-sound wait s close s
insert s: open sound:// load %/c/windows/media/tada.wav wait s close s
insert s: open sound:// load request-file/only wait s close s

Эти данные могут быть в виде файла .wav или могут быть сгенерированы с помощью кода:

REBOL [title: "Sine Wave Example, by Carl Sassenrath"]
tone: #{}
for phase 1 360 6 [
    val: 128 + to-integer 127 * sine phase
    append tone to-char val
]
q: make sound [rate: 44100  channels: 1  bits: 8  volume: 0.5  data: #{}]
loop 1000 [append q/data tone]
insert s: open sound:// q wait s close s

В этом примере открывается последовательный порт:

port: open serial://port1/9600/8/none/1

12.4 Сетевые порты

В этом разделе показано, как отправлять текстовые и двоичные данные через сетевые порты:

Базовый сервер (сначала запустите этот скрипт):

REBOL [title: "Server"]
port: first wait open/lines tcp://:55555
print join "Received: " first wait port

Базовый клиент (запустите этот скрипт вторым, в отдельном экземпляре REBOL):

REBOL [title: "Client"]
port: open/lines tcp://localhost:55555
insert port ask "Send:  "

Это приложение сочетает в себе сервер и клиент:

REBOL [title: "Network Text Messenger"]
view layout [ across
    q: btn "Serve" [
        focus g 
        p: first wait open/lines tcp://:8 
        z: 1
    ]
    text"OR"
    k: btn "Connect" [
        focus g 
        p: open/lines rejoin[tcp:// i/text ":8"]
        z: 1
    ]
    i: field form read join dns:// read dns://  
    return
    r: area rate 4 feel [
        engage: func [f a e] [
            if a = 'time and value? 'z [
                if error? try [x: first wait p] [quit]
                r/text: rejoin [x "^/" r/text] 
                show r
            ]
        ]
    ]
    return
    g: field "Type message here [ENTER]" [
        insert p value
        focus face
    ]
]

Это приложение демонстрирует, как отправлять двоичные файлы через сетевой порт:

REBOL [title: "Network Binary File Transfer"]
; сервер/получатель - сначала запускаем:
if error? try [port: first wait open/binary/no-wait tcp://:8] [quit]
mark: find file: copy wait port #""
length: to-integer to-string copy/part file mark
while [length > length? remove/part file next mark] [append file port]
view layout [image load file]
; клиент/отправитель - запускать после сервера (изменить IP-адрес при 
; использовании на 2 ПК):
save/png %image.png to-image layout [box blue "I traveled through ports!"]
port: open/binary/no-wait tcp://127.0.0.1:8  ; adjust this IP address
insert file: read/binary %image.png join l: length? file #""
insert port file

Вот VOIP-домофон:

REBOL [title: "VOIP Intercom"] do [write %ireceive.r {REBOL []
if error? try [port: first wait open/binary/no-wait tcp://:8] [quit]
wait 0  speakers: open sound://
forever [
    if error? try [mark: find wav: copy wait port #""] [quit]
    i: to-integer to-string copy/part wav mark
    while [i > length? remove/part wav next mark] [append wav port]
    insert speakers load to-binary decompress wav
]} launch %ireceive.r
lib: load/library %winmm.dll
mci: make routine! [c [string!] return: [logic!]] lib "mciExecute"
if (ip: ask "Connect to IP (none = localhost):  ") = "" [ip: "localhost"]
if error? try [port: open/binary/no-wait rejoin [tcp:// ip ":8"]] [quit]
mci "open new type waveaudio alias wav"
forever [
    mci "record wav"  wait 2  mci "save wav r"  mci "delete wav from 0"
    insert wav: compress to-string read/binary %r join l: length? wav #""
    if l > 4000 [insert port wav]  ; squelch (don't send) if too quiet
]]

Это приложение демонстрирует, как отправлять и получать данные через UDP:

REBOL [Title: "UDP Group Chat"]
net-in: open udp://:9905  ; This is UDP, so NO known IP addresses required
net-out: open/lines udp://255.255.255.255:9905
set-modes net-out [broadcast: on]
name: request-text/title "Your name:"
gui: view/new layout [
    a1: area wrap rejoin [name ", you are logged in."] 
    f1: field 
    k1: at 0x0 key #"^M" [
        if f1/text = "" [return]
        insert net-out rejoin [name ":  " f1/text]
    ]
]
forever [
    focus f1
    received: wait [net-in]
    if not viewed? gui [quit]
    insert (at a1/text 1) copy received  show a1
]

13. Файлы с общим кодом (DLL, So, библиотеки Dylib и т.д.)

Для загрузки разделяемых библиотек использовалась функция load/library. Присвойте загруженной библиотеке метку. Этот пример загружает библиотеку Windows kernel32.dll и помечает ее как lib:

lib: load/library %kernel32.dll

Определите функцию Rebol, используя сигнатуру любой экспортируемой функции в разделяемой библиотеке, с помощью "make routine!". Присвойте экспортируемой функции метку, определите типы возвращаемых значений и все необходимые типы параметров. Новая функция Rebol, представленная ниже, помечена как "воспроизведение звука". Он включает в себя функцию "Beep" из загруженной выше библиотеки kernel32.dll (здесь помечена как lib). Он возвращает целочисленное значение и требует 2 целочисленных параметра:

play-sound: make routine! [
    return: [integer!] 
    pitch [integer!] 
    duration [integer!]
] lib "Beep"

Вот пример используемой функции воспроизведения звука. Он использует цикл for для воспроизведения каждой частоты от 37 до 3987 с шагом 50 герц в течение 50 миллисекунд каждая. Когда закончите, закройте библиотеку с помощью функции "free":

for hertz 37 3987 50 [
    print rejoin ["The pitch is now " hertz " hertz."]
    play-sound hertz 50
]
free lib

Вот пример Windows API, который воспроизводит файл AVI:

REBOL [title: "AVI example"]
lib: load/library %winmm.dll
mciExecute: make routine! [c [string!] return: [logic!]] lib "mciExecute"
if not exists? %test.avi [
    flash "Downloading test video..."
    write/binary %test.avi read/binary http://re-bol.com/test.avi
    unview
]
video: to-local-file %test.avi
mciExecute rejoin ["OPEN " video " TYPE AVIVIDEO ALIAS thevideo"]
mciExecute "PLAY thevideo WAIT"
mciExecute "CLOSE thevideo"
free lib
quit

Пример звукозаписи Windows API:

REBOL [title: "Sound Recorder"]
lib: load/library %winmm.dll
mciExecute: make routine! [ 
    command [string!]
    return: [logic!] 
] lib "mciExecute"
file: to-local-file to-file request-file/save/title/file "Save as:" {
    } %rebol-recording.wav
mciExecute "open new type waveaudio alias buffer1 buffer 6"
mciExecute "record buffer1"
ask "RECORDING STARTED (press [ENTER] when done)...^/"
mciExecute "stop buffer1"
mciExecute join "save buffer1 " file
free lib
print "Recording complete.  Here's how it sounds:^/"
insert snd: open sound:// load to-rebol-file file wait snd close snd
print "DONE.^/"

Пример AutoIT DLL, который перемещает мышь по экрану:

REBOL [title: "AutoIT DLL example"]
if not exists? %AutoItDLL.dll [
    write/binary %AutoItDLL.dll
    read/binary http://musiclessonz.com/rebol_tutorial/AutoItDLL.dll
]
lib: load/library %AutoItDLL.dll
move-mouse: make routine! [
    return: [integer!] x [integer!] y [integer!] z [integer!]
] lib "AUTOIT_MouseMove"
print "Press the [Enter] key, and your mouse will move to the top"
ask "corner of your screen, and then down diagonally to 200x200:  " 
for position 0 200 5 [
    move-mouse position position 10 
]
free lib
print "^/Done.^/"
halt

Используйте Windows API для захвата изображения с веб-камеры:

REBOL [title: "Webcam"]
avicap32.dll: load/library %avicap32.dll
user32.dll: load/library %user32.dll
find-window-by-class: make routine! [
    ClassName [string!] WindowName [integer!] return: [integer!]
] user32.dll "FindWindowA"
sendmessage: make routine! [
    hWnd [integer!] val1 [integer!] val2 [integer!] val3 [integer!]
    return: [integer!]
] user32.dll "SendMessageA"
sendmessage-file: make routine! [
    hWnd [integer!] val1 [integer!] val2 [integer!] val3 [string!]
    return: [integer!]
] user32.dll  "SendMessageA"
cap: make routine! [
    cap [string!] child-val1 [integer!] val2 [integer!] val3 [integer!]
    width [integer!] height [integer!] handle [integer!] 
    val4 [integer!] return: [integer!]
] avicap32.dll "capCreateCaptureWindowA"
view/new center-face layout/tight [
    image 320x240
    across
    btn "Take Snapshot" [
        sendmessage cap-result 1085 0 0
        sendmessage-file cap-result 1049 0 "scrshot.bmp"
        browse %scrshot.bmp
    ]
    btn "Exit" [
        sendmessage cap-result 1205 0 0
        sendmessage cap-result 1035 0 0
        free user32.dll   quit
    ]
]
hwnd: find-window-by-class "REBOLWind" 0
cap-result: cap "cap" 1342177280 0 0 320 240 hwnd 0
sendmessage cap-result 1034 0 0
sendmessage cap-result 1077 1 0
sendmessage cap-result 1075 1 0
sendmessage cap-result 1074 1 0
sendmessage cap-result 1076 1 0
do-events

Используйте Windows API, чтобы изменить заголовок окна Rebol по умолчанию:

tt: "Your Title"
user32.dll: load/library %user32.dll
gf: make routine![return:[int]]user32.dll"GetFocus"
sc: make routine![hw[int]a[string!]return:[int]]user32.dll"SetWindowTextA"
so: :show show: func[face][so[face]hw: gf sc hw tt]
view layout [text 400x400 "No 'REBOL -' in the title bar!"]

Используя DLL usps4cb:

REBOL [title: "USPS Intelligent Mail Encoder"]
unless exists? %usps4cb.dll [
    write/binary %usps4cb.dll read/binary http://re-bol.com/usps4cb.dll
]
GEN-CODESTRING: make routine! [
    t [string!]  r[string!]  c [string!]  return: [integer!]
]  load/library request-file/only/file %usps4cb.dll "USPS4CB"
t: request-text/title/default "Tracking #:" "00700901032403000000"
r: request-text/title/default "Routing #:" "55431308099"
GEN-CODESTRING t r (make string! 65)
alert first second first :GEN-CODESTRING

MP3-плеер с использованием libwmp3.dll:

REBOL [Title: "MP3 Jukebox"]
if not exists? %libwmp3.dll [
    write/binary %libwmp3.dll
    read/binary http://musiclessonz.com/rebol_tutorial/libwmp3.dll
]
lib: load/library %libwmp3.dll
Mp3_Initialize: make routine! [
    return: [integer!]
] lib "Mp3_Initialize"
Mp3_OpenFile: make routine! [
    return: [integer!] 
    class [integer!] 
    filename [string!]
    nWaveBufferLengthMs [integer!]
    nSeekFromStart [integer!] 
    nFileSize [integer!]
] lib "Mp3_OpenFile"
Mp3_Play: make routine! [
    return: [integer!] 
    initialized [integer!]
] lib "Mp3_Play"
Mp3_Stop: make routine! [
    return: [integer!] 
    initialized [integer!]
] lib "Mp3_Stop"
Mp3_Destroy: make routine! [
    return: [integer!] 
    initialized [integer!]
] lib "Mp3_Destroy"
Mp3_GetStatus: make routine! [
    return: [integer!] 
    initialized [integer!] 
    status [struct! []]
] lib "Mp3_GetStatus"
status: make struct! [
    fPlay [integer!] 
    fPause [integer!] 
    fStop [integer!] 
    fEcho [integer!] 
    nSfxMode [integer!] 
    fExternalEQ [integer!] 
    fInternalEQ [integer!] 
    fVocalCut [integer!] 
    fChannelMix [integer!] 
    fFadeIn [integer!] 
    fFadeOut [integer!] 
    fInternalVolume [integer!] 
    fLoop [integer!] 
    fReverse [integer!] 
] none
Mp3_Time: make struct! [
    ms [integer!] 
    sec [integer!]
    bytes [integer!] 
    frames [integer!] 
    hms_hour [integer!] 
    hms_minute [integer!] 
    hms_second [integer!] 
    hms_millisecond [integer!] 
] none
TIME_FORMAT_SEC: 2
SONG_BEGIN: 1
SONG_CURRENT_FORWARD: 4
Mp3_Seek: make routine! [
    return: [integer!] 
    initialized [integer!]
    fFormat [integer!]
    pTime [struct! []]
    nMoveMethod [integer!]
] lib "Mp3_Seek"
Mp3_PlayLoop: make routine! [
    return: [integer!] 
    initialized [integer!]
    fFormatStartTime [integer!]
    pStartTime [struct! []]
    fFormatEndTime [integer!] 
    pEndTime [struct! []]
    nNumOfRepeat [integer!] 
] lib "Mp3_PlayLoop"
Mp3_GetSongLength: make routine! [
    return: [integer!]
    initialized [integer!]
    pLength [struct! []]
] lib "Mp3_GetSongLength"
Mp3_GetPosition: make routine! [
    return: [integer!] 
    initialized [integer!]
    pTime [struct! []]
] lib "Mp3_GetPosition"
Mp3_SetVolume: make routine! [
    return: [integer!] 
    initialized [integer!]
    nLeftVolume [integer!]
    nRightVolume [integer!]
] lib "Mp3_SetVolume"
Mp3_GetVolume: [
    initialized [integer!]
    pnLeftVolume [integer!]
    pnRightVolume [integer!]
    return: [integer!]
] lib "Mp3_GetVolume"
Mp3_VocalCut: make routine! [
    return: [integer!] 
    initialized [integer!]
    fEnable [integer!]
] lib "Mp3_VocalCut"
Mp3_ReverseMode: make routine! [
    return: [integer!] 
    initialized [integer!]
    fEnable [integer!]
] lib "Mp3_ReverseMode"
Mp3_Close: make routine! [
    return: [integer!] 
    initialized [integer!]
] lib "Mp3_Close"
waves: []
foreach file read %. [
    if (%.mp3 = suffix? file) [append waves file]
]
append waves "(CHANGE FOLDER...)"
initialized: Mp3_Initialize
view center-face layout [
    vh2 "Click a File to Play:"
    file-list: text-list data waves [
        if value = "(CHANGE FOLDER...)" [
            new-dir: request-dir
            if new-dir = none [break]
            change-dir new-dir
            waves: copy []
            foreach file read %. [
                if (%.mp3 = suffix? file) [append waves file]
            ]
            append waves "(CHANGE FOLDER...)"
            file-list/data: waves
            show file-list
            break
        ]
        Mp3_GetStatus initialized status
        if (status/fPlay = 0) [
            file: rejoin [to-local-file what-dir "\" value]
            Mp3_OpenFile initialized file 1000 0 0
            Mp3_Play initialized
        ]
    ]
    across
    tabs 40
    text "Seek:   " 
    tab slider 140x15 [
        plength: make struct! Mp3_Time compose [0 0 0 0 0 0 0 0]
        Mp3_GetSongLength initialized plength
        location: to-integer (value * plength/sec)
        ptime: make struct! Mp3_Time compose [0 (location) 0 0 0 0 0 0]
        Mp3_Seek initialized TIME_FORMAT_SEC ptime SONG_BEGIN
        Mp3_Play initialized
    ]
    return
    text "Volume: " 
    tab slider 140x15 [
        volume: to-integer value * 100
        Mp3_SetVolume initialized volume volume
    ]
    return
    btn "Reverse" [
        Mp3_GetStatus initialized status
        either (status/fReverse > 0) [
            Mp3_ReverseMode initialized 0
        ] [
            Mp3_ReverseMode initialized 1
        ]
    ]
    btn "Vocal-Cut" [
        Mp3_GetStatus initialized status
        either (status/fVocalCut > 0) [
            Mp3_VocalCut initialized 0
        ] [
            Mp3_VocalCut initialized 1
        ]
    ]
    return
    tabs 50
    text "Loop Start:" 
    tab start-slider: slider 120x15 []
    return
    text "Loop End:  " 
    tab end-slider: slider 120x15 []
    return
    btn "Play Loop" [
        plength: make struct! Mp3_Time compose [0 0 0 0 0 0 0 0]
        Mp3_GetSongLength initialized plength
        s-loc: to-integer (start-slider/data * plength/sec)
        pStartTime: make struct! Mp3_Time compose [0 (s-loc) 0 0 0 0 0 0]
        end-loc: to-integer (end-slider/data * plength/sec)
        pEndTime: make struct! Mp3_Time compose [0 (end-loc) 0 0 0 0 0 0]
        ; TIME_FORMAT_SEC: 2
        Mp3_PlayLoop initialized 2 pStartTime 2 pEndTime 1000  ; 1000x
    ]
    btn 58 "Stop" [
        Mp3_GetStatus initialized status
        if (status/fPlay > 0) [Mp3_Stop initialized]
    ]
]
Mp3_Destroy initialized
free lib

14. Сторонние библиотеки

Этот раздел содержит примеры, демонстрирующие, как использовать различные сторонние библиотеки Rebol. Демонстрируются базы данных SQLite и MySQL, небольшой 3D-модуль на основе графики Draw, диалекты для создания вывода PDF и Flash (.swf), XML-RPC, дополнительные инструменты компоновки графического интерфейса и другие функции:

14.1 PDF

PDF Maker от Габриэле Сантилли:

REBOL [title: "PDF example"]
do http://www.colellachiara.com/soft/Misc/pdf-maker.r
write/binary %example.pdf layout-pdf [[textbox ["Hello PDF world!"]]]
call %example.pdf


REBOL [title: "PDF example 2"]
do http://www.colellachiara.com/soft/Misc/pdf-maker.r
write/binary %example.pdf layout-pdf compose/deep [
    [
        page size 215.9 279.4  ; American Letter Size
        textbox ["Here is page 1.  It just contains this text."]
    ] 
    [
        textbox 55 55 90 100 [
            {Here's page 2.  This text box contains a starting
             XxY position and an XxY size.  Coordinates are in
             millimeters and extend from the BOTTOM LEFT of the
             page (this box extends from starting point 55x55
             and is 90 mm wide, 100 mm tall).
             All the following page sizes are the default ISO A4,
             or 211×297 mm.  That is SLIGHTLY SMALLER than the
             standard American Letter page size.}
        ]
    ]
    [
        textbox 0 200 200 50 [
            center font Helvetica 10.5
            {This is page 3.  The text inside this box is centered
             and formatted using Helvetica font, with a character
             size of 10.5 mm.}
        ]
    ]
    [
        apply rotation 20 translation 35 150 [
            textbox 4 4 200 20 [
                {This is page 4.  The textbox is rotated 20 degrees
                 and translated (moved over) 35x150 mm.  Graphics
                 and images can also be rotated and translated.}
            ]
        ]
    ]
    [
        textbox 5 200 200 40 [
            {Here's page 5.  It contains this textbox and several
             images.  The first image is placed at starting point
             50x150 and is 10mm wide by 2.4mm tall.  The second
             image is 2x bigger and rotated 90 degrees.  The last
             image is placed at starting point 100x150 and is
             streched to 10x its size.  Notice that this ENTIRE
             layout block has been evaluated with compose/deep to
             evaluate the images in the following parentheses.}
        ]
        image 50 150 10 2.4 (system/view/vid/image-stock/logo)
        image 50 100 20 4.8 rotated 90 
            (system/view/vid/image-stock/logo)
        image 100 150 100 24 (system/view/vid/image-stock/logo)
    ]
    [
        textbox [
            {This page contains this textbox and several generated
             graphics:  a line, a colored and filled box with a
             colored edge, and a circle.}
        ]
        line width 3  20 20 100 50   ; starting and ending XxY positions
        solid box edge width 0.2 edge 44.235.77 150.0.136 100 67 26 16
        circle 75 50 40   ; starting point 75x50, radius 40mm
    ]
]
call %example.pdf
; see http://www.colellachiara.com/soft/Misc/pdf-maker-doc.pdf

14.2 Конструктор Flash (.swf)

Автор Oldes:

REBOL [title: "REBOL/Flash example"]
do http://box.lebeda.ws/~hmm/rswf/rswf_latest.r
make-swf/save/html http://tinyurl.com/yhex2cf 
browse %starfield1.html
; see http://box.lebeda.ws/~hmm/rswf/ 
; and http://re-bol.com/rebol.html#section-9.17

14.3 RebGUI

Диалект графического интерфейса пользователя Эшли Трутер с функциями, которых нет в собственном VID:

REBOL [title: "RebGUI Example"]
do http://re-bol.com/rebgui.r
display/close "Tab Panel" [
    main-screen: tab-panel data [
        "Spreadsheet" [
            x: sheet data [
                A1 32 A2 12 A3 "=a1 + a2" A4 "=1.06 * to decimal! a3"
            ]
            a: area
            reverse
            button -1 " Show Data " [x/save-data set-text a x/data]
            button -1 " Quit! " [if true = question "Quit?" [quit]]
        ]
        "Pie Chart" [
            pie-chart data ["VID" yellow 19 "RebGUI" red 81]
                tip "Pie Chart!"
        ]
        "Menu" [
            menu #LHW data [
                "File" [
                     "Open" [x/text: read to-file request-file show x]
                     "Save" [write to-file request-file/save x/text]
                 ]
                 "About" [
                     "Info" [alert "RebGUI is great!"]
                 ]
            ] 
            return
            x: area #LHW "[CTRL-Z: Undo CTRL-Y: Redo CTRL-S: Spell Check]"
        ]
        "VID style"  [
            style -1 data [text bold "Back to Spreadsheet" [
                main-screen/select-tab 1
            ]]
        ]
        action [wait .2 face/color: 230.230.230]  "Text" [
            text "Tabs are a great way to maximize screen real estate."
        ]
        action [wait .2 set-focus z]  "Fields" [
            y: field
            z: field "Edit me"
        ]
    ]
] [question "Really Close?"]
do-events

Небольшой пример приложения:

REBOL [title: "RebGUI Table Grid Example"]
do load-thru http://re-bol.com/rebgui.r
alert {Default username/password is "user1/pass1"}
unless exists? %snappmx.txt [
    save %snappmx.txt [
        "user1" "pass1" "Bill Jones" "bill@site.com" "Bill LLC" 
        "user2" "pass2" "John Smith" "john@mail.com" "John LLC"
    ]
]
database: load %snappmx.txt
login: request-password
found: false
foreach [userid password name email company] database [
    either (login/1 = userid) and (login/2 = password) [found: true] []
]
if found = false [alert "Incorrect Login." quit]
add-record: does [
    display/dialog "User Info" [
        text 20 "User:" f1: field return
        text 20 "Pass:" f2: field return
        text 20 "Name:" f3: field return
        text 20 "Email:" f4: field return
        text 20 "Company:" f5: field reverse
        button -1 #XY " Clear " [clear-fields]
        button -1 #XY " Add " [add-fields]
    ]
]
edit-record: does [
    display/dialog "User Info" [
        text 20 "User:" f1: field (form pick t/selected 1) return
        text 20 "Pass:" f2: field (form pick t/selected 2) return
        text 20 "Name:" f3: field (form pick t/selected 3) return
        text 20 "Email:" f4: field (form pick t/selected 4) return
        text 20 "Company:" f5: field (form pick t/selected 5) reverse
        button -1 #XY " Delete " [
            t/remove-row t/picked
            save %snappmx.txt t/data
            hide-popup
        ]
        button -1 #XY " Save " [
            t/remove-row t/picked
            add-fields
            save %snappmx.txt t/data
            hide-popup
        ]
    ]
]
add-fields: does [
    t/add-row reduce [
        copy f1/text copy f2/text copy f3/text copy f4/text copy f5/text
    ]
    save %snappmx.txt copy t/data
]
clear-fields: does [
    foreach item [f1 f2 f3 f4 f5] [do rejoin [{set-text } item {""}]]
]
table-size: system/view/screen-face/size/1 / ctx-rebgui/sizes/cell
display/maximize "Users" [
    t: table table-size #LWH options [
        "" left .0  "" left .0   ; don't show the first 2 fields
        "Name" center .33  "Email" center .34  "Company" center .34
    ] data database [edit-record]
    reverse
    button -1 #XY " Add " [add-record]
]
do-events

14.4 Меню Cyphre и панель вкладок

REBOL [title: "Cyphre Menu and Tab Panel Example"]
do load-thru http://re-bol.com/cyphre_menu_and_tab_panel.r
insert-event-func [ 
    either event/type = 'resize [
        mn/size/1: system/view/screen-face/pane/1/size/1 
        my-tabs/size: system/view/screen-face/pane/1/size - 15x30
        show [mn my-tabs]  none
    ] [event]
]
view/options center-face layout  [
    across space 0x0 origin 0x0
    mn: menu with [ 
        size: 470x20 
        data: compose/deep [
            " File " [
                "Open" # "Ctrl+O" [request-file]
                "Save" # "Ctrl+S" [request-file/save]
                bar
                "Exit" [quit]
            ]
            " Options " [
                "Preferences" sub [
                    "Colors" [alert form request-color]
                    "Settings" [request-text/title "Enter new setting:"]
                ]
                "About" [alert "Menu Widget by Cyphre"]
            ]
        ]
    ]
    below
    at 10x25 my-tabs: tab-panel data [
        "Fields"   [
            h1 "Tab Panel by Cyphre" field field area area btn "Ok"
         ]
        "Data List"  [
            t1: text-list 400x430 data system/locale/months [alert value]
        ]
    ]
] [resize]

14.5 Henrik Listview

REBOL [title: "Listview Example"]
evt-close: func [face event] [
    either event/type = 'close [
        inform layout [
            across
            Button "Save Changes" [
                backup-file: to-file rejoin ["backup_" now/date]
                write backup-file read %database.db
                save %database.db theview/data quit
            ]
            Button "Lose Changes" [quit]
            Button "CANCEL" [hide-popup]
        ] none ] [ 
        event
    ]
]
insert-event-func :evt-close
if not exists? %list-view.r [write %list-view.r read
    http://www.hmkdesign.dk/rebol/list-view/list-view.r
]
do %list-view.r
if not exists? %database.db [write %database.db {[][]}]
database: load %database.db
view center-face gui: layout [
    h3 {To enter data, double-click any row, and type directly 
        into the listview.  Click column headers to sort:}
    theview: list-view 775x200 with [
        data-columns: [
            Student Teacher Day Time Phone Parent Age Payments
            Reschedule Notes
        ]
        data: copy database
        tri-state-sort: false
        editable?: true
    ]
    across
    button "add row" [theview/insert-row]
    button "remove row" [
        if (to-string request-list "Are you sure?" 
                [yes no]) = "yes" [
            theview/remove-row
        ]
    ]
    button "filter data" [
        filter-text: request-text/title trim {
            Filter Text (leave blank to refresh all data):}
        if filter-text <> none [
            theview/filter-string: filter-text
            theview/update
        ]
    ]
    button "save db" [
        backup-file: to-file rejoin ["backup_" now/date]
        write backup-file read %database.db
        save %database.db theview/data
    ]
]

14.6 Система меню Ensel

REBOL [title: "Another Menu Module Example"]
if not exists? %menu-system.r [write %menu-system.r (
        read http://www.rebol.org/library/scripts/menu-system.r)]
do %menu-system.r
menu-data: [
    file: item "File" menu [item "Open" item "Save" item "Quit"]
    edit: item "Edit" menu [ 
        item "Item 1"
        item "Item 2" <ctrl-q>
        ---
        item "Submenu..." menu [
            item "Submenu Item 1" 
            item "Submenu Item 2"
            item "Submenu Item 3" menu [
                item "Sub-Submenu Item 1"
                item "Sub-Submenu Item 2"
            ]
        ]
        ---
        item "Item 3"       
    ]
    icons: item "Icons" menu [
        item "Icon Item 1" icons [help.gif stop.gif]
        item "Icon Item 2" icons [info.gif exclamation.gif]
    ]
]
basic-style: [item style action [
    switch item/body/text [
        case "Open" [
            the-file: request-file
            alert rejoin ["You opened: " the-file]
        ] 
        case "Save" [
            the-file: request-file/save
            alert rejoin ["You saved to: " the-file]
        ]
        case "Quit" [
            if (request/confirm "Really Quit?") = true [quit]
        ]   
        case "Item 1" [alert "Item 1 selected"]
        case "Item 2" [alert "Item 2 selected"]
        case "Item 3" [alert "Item 3 selected"]
        case "Submenu Item 1" [alert "Submenu Item 1 selected"]
        case "Submenu Item 2" [alert "Submenu Item 2 selected"]
        case "Submenu Item 3" [alert "Submenu Item 3 selected"]
        case "Sub-Submenu Item 1" [alert "Sub-Submenu Item 1 selected"]
        case "Sub-Submenu Item 2" [alert "Sub-Submenu Item 2 selected"]
        case "Icon Item 1" [alert "Icon Item 1 selected"]
        case "Icon Item 2" [alert "Icon Item 2 selected"]
    ]
]]
evt-close: func [face event] [either event/type = 'close [quit] [event]]
insert-event-func :evt-close
view center-face layout [
    size 400x500
    at 2x2 menu-bar menu menu-data menu-style basic-style
]

14.7 r3D

Трехмерный диалект, основанный на встроенных функциях рисования Rebol, автор Эндрю Ходли:

REBOL [title: "r3D Example"]
do http://re-bol.com/r3d.r
Transx:   Transy:   Transz:   300.0
Lookatx:  Lookaty:  Lookatz:  100.0 
do update: does [ 
    world: copy [] 
    append world reduce [
        reduce [cube-model (r3d-scale 100.0 150.0 125.0) red]
    ]
    camera: r3d-position-object   
        reduce [Transx Transy Transz]
        reduce [Lookatx Lookaty Lookatz]
        [0.0 0.0 1.0] 
    RenderTriangles: render world camera r3d-perspective 250.0 400x360
    probe RenderTriangles    ; This line can be removed
] 
view layout [
    scrn: box 400x360 black effect [draw RenderTriangles]  ; basic draw
    across return
    slider 60x16 [Transx: (value * 600 - 300.0) update show scrn]
    slider 60x16 [Transy: (value * 600 - 300.0) update show scrn]
    slider 60x16 [Transz: (value * 600) update show scrn]
    slider 60x16 [Lookatx: (value * 400 - 200.0) update show scrn]
    slider 60x16 [Lookaty: (value * 400 - 200.0) update show scrn]
    slider 60x16 [Lookatz: (value * 200 ) update show scrn]
]

14.8 MySQL

Автор Nenad Radosevic ("Doc Kimbel"):

REBOL [title: "MYSQL Example"]
; Сначала запустите MySQL и создайте базу данных с именем "Contacts"
unless exists? %mysql-protocol.r [
    write %mysql-protocol.r read http://re-bol.com/mysql-protocol.r
]
do %mysql-protocol.r
db: open mysql://root:root@localhost/Contacts
insert db {create table Contacts (
    name            varchar(100),
    address         text,
    phone           varchar(12),
    birthday        date 
)} 
insert db {INSERT into Contacts VALUES 
    ('John Doe', '1 Street Lane', '555-9876', '1967-10-10'),
    ('John Smith', '123 Toleen Lane', '555-1234', '1972-02-01'),
    ('Paul Thompson', '234 Georgetown Pl.', '555-2345', '1972-02-01'),
    ('Jim Persee', '345 Portman Pike', '555-3456', '1929-07-02'),
    ('George Jones', '456 Topforge Court', '', '1989-12-23'),
    ('Tim Paulson', '', '555-5678', '2001-05-16')
}
insert db "DELETE from Contacts WHERE birthday = '1967-10-10'"
insert db "SELECT * from Contacts"
results: copy db
probe results
close db
halt
; смотрите http://softinnov.org/rebol/mysql-usage.html


REBOL [title: "MySQL GUI Example"]
do %mysql-protocol.r
results: read/custom mysql://root:root@localhost/Contacts [
    "SELECT * from Contacts"
]
view layout [
    text-list 100x400 data results [
        string: rejoin [
            "NAME:      " value/1 newline
            "ADDRESS:   " value/2 newline
            "PHONE:     " value/3 newline
            "BIRTHDAY:  " value/4
        ]
        view/new layout [
            area string
        ] 
    ] 
]

14.9 SQLite

Автор Ashley Truter:

REBOL [title: "SQLITE Example"]
unless exists? %sqlite3.dll [
    write/binary %sqlite3.dll read/binary http://re-bol.com/sqlite3.dll
]
unless exists? %sqlite.r [
    write %sqlite.r read http://re-bol.com/sqlite.r
]
do %sqlite.r
db: connect/create %contacts.db
SQL "create table contacts (name, address, phone, birthday)"
SQL {insert into contacts values 
    ('"John Doe"', '"1 Street Lane"', '"555-9876"', '"1967-10-10"')
}
data: [
    "John Smith" "123 Toleen Lane" "555-1234" "1972-02-01"
    "Paul Thompson" "234 Georgetown Pl." "555-2345" "1972-02-01"
    "Jim Persee" "345 Portman Pike" "555-3456" "1929-07-02"
    "George Jones" "456 Topforge Court" "" "1989-12-23"
    "Tim Paulson" "" "555-5678" "2001-05-16"
]
SQL "begin"
foreach [name address phone bd] data [
    SQL reduce [
        "insert into contacts values (?, ?, ?, ?)" name address phone bd
    ]
]
SQL "commit"
SQL ["DELETE from Contacts WHERE birthday = ?" "1967-10-10"]
results: SQL "select * from contacts"
probe results
disconnect db
halt
; see http://www.dobeash.com/sqlite.html


REBOL [title: "SQLITE GUI Example"]
do %sqlite.r
connect %contacts.db
results: SQL "select * from contacts"
view layout [
    text-list 100x400 data results [
        string: rejoin [
            "NAME:      " value/1 newline
            "ADDRESS:   " value/2 newline
            "PHONE:     " value/3 newline
            "BIRTHDAY:  " value/4
        ]
        view/new layout [
            area string
        ] 
    ] 
]
disconnect

14.10 Doc's Captcha

REBOL [title: "Captcha Example"]
write/binary %Caliban.caf read/binary http://re-bol.com/Caliban.caf
do http://re-bol.com/captcha.r
captcha/set-fonts-path %./
captcha/level: 4
write/binary %captcha.png captcha/generate
write %captcha.txt captcha/text
view center-face layout [
    image (load %captcha.png)
    text "Enter the captcha text:"
    f1: field [
        either f1/text = (read %captcha.txt) [
            alert "Correct"
        ] [
            alert "Incorrect"
        ]
    ] 
]

14.11 Irwin / Ensel Снимок экрана

REBOL [title: "Windows Screen Capture Example"]
do http://www.rebol.org/download-a-script.r?script-name=capture-screen.r
the-image: ftp://user:pass@site.com/path/current.png
view center-face gui: layout [
    button 150 "Upload Screen Shot" [
        unview gui
        wait .2
        save/png the-image capture-screen
        view center-face gui
    ]
]

14.12 XML и XML-RPC

Смотрите http://earl.strain.at/space/rebXR+Users+Guide

REBOL [title: "XML-RPC Example"]
xmlrpc-exec http://betty.userland.com/RPC2 [examples.getStateName 41]
defh: func [orig-call] [do orig-call]
xmlrpc-serve/default [] 'defh

14.13 Библиотека графиков и диаграмм Q-Plot

Автор Matt Licholai:

REBOL [title: "Minimal Bar Graph Example"]
if not exists? %q-plot.r [write %q-plot.r read http://re-bol.com/q-plot.r]
do %q-plot.r
view quick-plot [
    600x400
    bars [5 3 8 2 10 3 4 9 5 7]
]


REBOL [title: "Exploded Pie Chart"]
if not exists? %q-plot.r [write %q-plot.r read http://re-bol.com/q-plot.r]
do %q-plot.r
view center-face quick-plot [
    400x400
    pie [10 3 6 1 8] labels [A B C D E] explode [3 5]
    title "Exploded Sections C and E" style vh2
]


REBOL [title: "Simple Line Graph Example"]
if not exists? %q-plot.r [write %q-plot.r read http://re-bol.com/q-plot.r]
do %q-plot.r
view quick-plot [
    400x400
    line [1 2 4 8 16 32 64 128 256]
]

14.14 Rebzip

Автор Vincent Ecuyer:

REBOL [title: "Rebzip Example"]
do to-string to-binary decompress 64#{
eJztW+uP20hy/+6/oldGsJ7bcEU2X00Zd4bX9iILXO4AY5N8EOYAjkTNMNaQOomy
PTbmf8+vqptkU3xIM4cgARICHmvYVdX1fnRrPn745a9/FsvrFy9W1VfnW75biFVZ
VNnXSixfCDyr/crZlsXtwvzeeVz885IkSsJEJYEQju96bhCHrhKOF8s4CGToSgKS
QeQHnh/jo1KRG8aRFzb0HD9O/CCMPA+fvciPwziUEX4RMkhkpEAIH90gAGFf0j6h
lCqUbhTRPkEcY3dftvx5kUwCMBYSCU+GIO1KIh64sR+5oAo8FUWhBDnwJIJEhX4U
Bgq4IJbIOIqilj/phknoRrSMz1GcuJGrSC5wBCRFvHoKLISQzSchVOwr0PMJHjyr
JArjlj8CVH6SsP4iBQFiLyR6TuCrIJRhABJJ7LsBRCQg3w8j3w8U6S+KPGI1avUn
HNggCsKA9ZdIpUJgJ1hIkhgSu0lEJlBeEvpgFkDYzvO8JKJ9wtiVkCgMGnqe60ZK
KS8I2XQkVBzR3k4cuxArimLCk6RJ6I32gd2TOJaQgei6RKCl50Bb0JRL8jqeD39x
vTCCMgWwYdYgJP3BYSRkc0mIEDYIvdCnfQJP+lC+77XyRqEXwwqK9efHWPahENID
VOdJ2A94xHMko4T2CaMwdGNJvEKqIJJebNFzlAv7h2HC+oOWwFWSkFxR7IGnhPzP
C8mllMv+l4BXP/LZ/+BCkZcElrwiTkLlh6Ek1/IC2N93pQyJJwgC5cAXHUgVKC8G
HxxDgUdUJHuH54VQTEPPIWbJA2lrOBR4ChLaG3huHICviA0FVv1YerRPhF29wA3I
F32yrSv91v+kC6XFiBGXfwtJ867PsYQHvkN2dPA/wGQYUQz5McweRz4LRL8pz2/5
g/IilYRxzC4sOSEkCcUERE1CWJhihewRKNIZ4ilCRMBTSR4J51CBp1r/U1BO7MKY
gmMM1pCkJ0d6HqJAQgO8qx968EyyaUwBqRLONT4JLmPX0h+CN4CTUIoiwYIkSOKI
bBrBt0PF9AQ0CgvAiwnBlyQF0Yb34iUiuPUXz4e/+WHCoSkSFSSkb9JfGMR4i1RF
sSIhYBKHimMoAo8wNwUXtAd2PK/lLyQ4KJi3iwOIgqDlmIDh4bBuRLEC0jHUyj6n
wlj6yqd9EBmsY7flDyaCjwQR2QMxBu1CZxxLgfQofkOOMWDCIsQTlBr6fkIJDsGF
gEx87Nky6LnIXyCpONmQTZFWKdgD5B0w5VKyAZ4HHn1yQGTDIPDBIUUXIgRJTXmi
5RCxhtiCY3K4wEt8BY/kaFIhJQ+OZuI2Voqjzw0SlA6XRIopuCjFWhyCHx+lIuTs
66K6yMAnYJQkpCvgUkpAMqCADtlukfTJb8g8cF3lIUdJYdUkbAG2Ql2TAs6Yih0S
kQXnTEhvKDsKviBp10C5LmKdc4JykbvAsUVQIANQRfRdjkCsJ+QJhIjcmniUvYEo
FZiXigMNsuMfBbFEdkXSQ9RaHEqsgRUv4qqEihdHiUfUkQ6hfeQ7iowIe8HzyFNg
fqRBN+RIgpeBhcAyigigGiklhx1kRe2OFZcRBEQEhmOXPikZIf0Q50IidFA3JaWi
GC4ETwttHcLACAJPG4WqgkpYocJHeUKyIYdHrZYI5Yh6A4QatQYB9w+hQlFBeCuL
QxSwGLHic0/hB1iOeHeH0lmAHEE6pOB2kd042FDIoE1FwQS3jVD/wsTiMIopMwfs
bjC2knBu9nKUeKgAlYKIJFAg0iRnxQAMIF592gh5TmFjyygCFHyJxKkzMrIkJSny
IfBBbQqXJo96IRmw90ewODZyyQ996BaeEUUWh/BYdFcel1+PyiYeyeEWI4uiDHFN
g02gXS/k2gRXcWPuIZDEAAAci8PYRz1CeQ04DkPqtJKQnNbF5hQSFL+UPShwyFho
xqjIUGNDXurD16SVvOC9iuwScdQgUSJsdXFC4kQajbmoUeeFxEuGjdDt+DCdx1GG
foBSXJsaoDwXJLmYQJ9YhqOSXWNoB4mUTOJQQGMXlxtDMIi2hPIRVSrIg+xnpQbl
I/BhK86uCFgoyKVWE0EVkOZZSPg1jImmh2IJFoQpKO84ktw+QuWykleM9EgFjgVD
oUYUwru5PCnkyDgMOakjn8Nu3BrCi9F3UkoXAedMFNOWQ9RjlCBASM0wQiDi2ujF
HrWHIduKOl4F0Ti/oByhpYkSTn2o2S6ylcUhmm1k/5gbYAHTkBlc0mGETgcGcqkT
g1DcuLtc0UARfazkIKPONbECz6HyFlAAkQQOJXzEBHsekij6IF2t0PpT4eUCAGFg
4iCmCg/fRGsCh7I6TPS/KI+xrqA+Eheyp8spCnUT/knujnQCD+Yy5lGCg4dziUQd
hVfDjnaFgmIQooorFNIMFVD2Qm4GYBKSDGWBLBLSRtQ6QHpu19F9INTdxLdUGEgq
skFAoSYirsKBz30bumvEleIeE70cQjIgFYZU0PyYUomA3WDAGA2bVaGgnASxy85B
WQfr3PyFQEMB5pQBRqkwetysYSoj1H1+e1c5h7t8UzlqITbHYmUNY7OP7fJBVHeZ
+Jxuj5m4eRBK3OR4lxZrsc+q4744iLz6edagasBljnnvNtv/cC1mvzfoVSmYpIa+
bvfLcuyxF0V2m1b55+xNTaUzHTqe+FruzRLt71AfORf0kxawTm8pFVDH2uBen5Ah
eALUhBi/hX3R/uQfx906rTIHE+uAkoz8pB9ApTTXWprgV8u0eHAO1T4vbkkX7+kd
1LC6y1afDsf7Fhq4Ha39VuRVnm41lz2Fbcp9lq7uQCfdm426kzQz/KpjZXp3xZra
5atPzRDOO5M+UGp5lWn+JLyeUprZ3ZfjykjFu4/vUEtrCZ+lkL5rZPe76uGNIfHy
u2uexxPjbst0Lf6zzAsxe/l9JpZV6dxlX2vXaY2pCeH17HF2PSzo60N+W6QQKju8
0KRX6dbZ5NvMwcoCTBsxxMvvCONfXEydj1pFWVHtp2ERqxo2K9ZOuXFqlGFoNK8a
mrh21tlhtc93VbkfAcdQ8GhkWJXF52x/yMuCDaYlAUKuj19OjfiOwTm8hfFFMk4q
tnlVQRhwm2OJkCdD/t/rcNf79wMeLNzkRbp/QBJhc3XNiGX2wjbW4ZyDECSLYfRV
C42WU7lXJ7F9Ho2zZKQxUQn9S3HnddKJrgYzCWEc7sp99WyNM/b/PpWfS6EAfaKj
3eS3/7CXrcuBFKDRKdw1a7dZdYFRhszAjDZs9zm0EpzYAX6KVUuXd1lKJZXCNbOM
tSp3D/Ndim01eWmxf063A2H7P8t80LjF/WFdHpwqv88mBGCPYEhBkH1u6e2lzq+N
bUJ2flce9+IPdACsrjpeXtZRPb/Pi2OVAciXfZDTIJgfMuy9pli46gaAlpQKz2WS
EmRfUnr7RElptvyDeHWffhWuYfIhQ/w6NJe4o1KXRXWnhRZ1tzVfpw+WUOR7F9lv
sy/vz1jwKf7WxV1YIazf2Dqg3eCQ6+PqtI3E0ICGvtMAwgk6IJidui2ifQ8g6DTQ
WoUTDea+VktnbN/R0rD1/7u0RLuNaCmkQ2lbB+ROP7HrdAAD5V6qqvEu+1u+c6gD
emjU9P1deb9D63XIKI9RJ9UZOSxmuS/TEJSFMupdVzXymhdaYNNnafB1vs9WaKMe
BO+toa4fG+gihQ8tCZT0/Rf6rdwwaqentaLzX8t1vslXGGLQcPHSEMJ4E2zY1tBz
lqwzINxn1V25tsRzmBxU1r455N8ycfL7qWu8RgHYlEIziaKb0TzRIIF5e9dFN7vr
AYARG6geA4umyRTbrLit7nTr/mKyre84jhZ1IX48wEKW63ShXotv2/xGQJVZet9Z
OdHRonnR5dxoY2MLD+VkG5gxh1v8s+D92xkvLw4V1NEhYIR5ZYt6Jf7Uvjhh5mrg
3rNm0hTM3jo9h0/5rmd8OQ5apfm2B++oHkKj63W22cJrOwDXfV5HbNOofktl5mTf
Lk0rFYw5Zbqpsv2wTz7R1wYT3Gs7cVjxbx5uIF9+fxywVHcQ7C3r4fQRG5jJawIC
2r499NaNO5lg/6NR89BdeYdYAz9slQE7Gnx1gj/kBUyh96bTyHHCm9OncTjOiQy3
HtqBchw9r02W6QMM5DX76SWiIVZMNaydhdP8a3YE/qjfT1gt+4oassmz7XoMlumw
HDXVQd1rkKK0KA7mBaOStqhNBJSBNecJKHHP8PDTA4zzPi4O6KdXfSn7gOiq/z8g
/s8FhGVhUAVL93Cx88Dr/PCpON7fwPiHaqgqtqA0je0LJPS0Ql91g8mt70fWuaHm
+okYpr8sN5tD1uflSUE/EfEtkNHTaOnUP/k/aihp2zfjJ7O/f/y3D3Rw3HbTx705
Xz78PLNHjephh3bWNI14oZvg+lQeWObjtdkcLrRLqztmoLf/92bQAeIP1OZyR23a
+fvyMzp8UiwdYM7ms7b9NgxpaMK9ZOjJdb89fIOAxZfYAhG9yfeH+lBiaQYl6r1E
Qd9S08J1UPXgMTjHNLwukChW5TpzGr0265xs/2k2O2GoPosAL+Crs8Rq1+ukWzGb
XY+tIzIw5HUgOr4BZxU/YsRqZqtfjvl2TXMVvUz3q7v8c1aPoewccBJMBWh0PtUD
zOFnTbt2JhOVWKVakcOGENCQ+rm14Rfk7Y4NhT4Z+kG0089/MAxsekNsibxqFaGr
ShefuCK0X4krQsuL1fa4ziwGWgLzdZbt6DKFQQ5aFII8HG/q8Q/MWwjwqpsSY87s
z/mhqhG+3JFWml60uB2c0DgBcL3maiuKG6dWjiZTIOvDP9o0Y5VpM4kyoJ7hymMl
mqJguTje10GmHbWuj00OqNXecZglJhdEjFk7cfGTWrhkoIWYRLFjrre1IVDusmKu
pZtry8+/7HOUPF63mv9W7oWlt4Vwx3VlIhYtzIsTh9HDHllx+Uq/ubq2XJJsuSzK
iuejNwbnRANky4VZmnvdJWPFhY5BTofa9Plef+pGKotmgHvJPt1uxbJBNNvid3IA
frOn2ZuJLrtkT1u+/KARUkGi8WDdnnC8GZpX9d4UIA3GG83t9QCnr0W6gzXX+ru8
RVVncrFFoAwWsfqSkqEaOUbaNnqMu/HYakKfMOaL7iHOoAIGujnbj6xYtK8260cf
0RXllxcDcpNmqSyUhQlvU0OJtzdDpDDItyEpltrNmISRqg0X42FypBk1ZEzV2qYo
FFqHteuP4LE2N2zX2l0n9N5qgA8tGZq3+fHeOtByBjvU+un3wvVDljfBL0a7oj76
iGS6ctdxbin1gu5cR5fdrQwzBM3VZWC5Q5mqBqKantekr9PDRvjX4MGi9ZijzubU
s6kcWX+y0/vopKlrM3efVrXrzwR3aXGb6SMgpj+XIpDtKUmbawd2Ose7HaP98mW2
G6Db15LupnugVPY0mX6Y2lXCqpQ/NaPLEOJpomSfQcvUeT3lUC0B4m1kbu7poptx
e9f8neXuxEPN1dRyfYiNrTpg7SRnZTvIe9P0aIT+NJQedOecbVrocw7XisXNqWmx
piZDevrQwy0J3ZM07chqS8Fsmo4aqBW51y0fC7tffp+t7NsIu2vmi7vW/9vG2fTL
fy22D+JLuf+EJhK5vHPMrM8XDvVxBg1E9Qms1ULTo6Xo9MFUQupe2Oqh1w2rnUaa
Bes3091riLetTC2ZLo2p9rjFoVHuFSRJj9vq6oTA3485zSrvy+LHiluHCSKDXTYf
EQ3chHAmGD/uoBTraLfS6badwOvXXNubg5sGs0OTYaxY4dmMnZEPr7P9vtwfTjt2
/dZuZgl4pImnpkwriaq30fdpf16gFxnv3qlmma9AzJ7VtpsG9CReCIG4O8Xi7vEr
mdK8OeHnPv2UUYrQwxhDnGOn9tU6Lds9hOnXB8KYNNy83qX7QzYnhmtiJ8lp6iD/
UA42qtXd/nju/P/VeNt51QOWukqP3xVwn6ddXsMO5sRXptf7lu3LNxp8br4NKZbm
6GKTbuFHfRZ4BxNOU1vUlz7WfbJ+NUKSA8nI90p/UaD7xQGGGEHmXqhGHuTH6le7
B6mj0HPNxOB5bEuR6Tg0Csy/Ich6kH2Gg9qGo0e0u4deogomNN2732q+7HNKZkR7
/fvgqe0GLm/bDXuLI1va6XXKiyy4jitZ70d26OfrqX160J3deqsTUnVEm3DIZrgY
nyvo4TIxuNrnoS/yoMDd++3a5IOgw6wf0Jqs7uamYtfJYHxedM/Mkr2KuZgEp6f9
ppj+JvWZSwv7YY3O/uYI50+i/ISaQd3U9d9OzlPtZ3xWVeen5Ha419m2H2zTJGpp
+eBqCmhitK+fM9/pHHteflf014sfgviRmvD37lvvrfuWGvHmO88X0jGXI+8J97d/
ef9xqnE/fWaEMAMiXTcsxsbBoQfzcL5GNPyxo3xx1lPqx3wt9YLLsaGnkdrTd0L0
HXuw4qGbHagXIxQU4d7kcPdsd6G+aN9HnqS3GDNIadj1dp8+HNCPXM76ozWMt1PI
k9CR4Sr7PrYYKpRTBIpS39dt04FzmzHE9h6uaP9e4EJ/eYJb1s5B33aLOt8lu9xF
Zr+9f/t769qDhzpDz8vvsUrePdZfa3pSSLhsiNo2dM8Hvyie4pOuoD+OFL9++PVX
AUVfhPYP5G175+fbtov9pPTz4S/vWxtlxeUx8Dxux6uOXp1crr8vR5PkG0Fnhktd
i/gvXujjBeXCrpSbFG3Kms7/+cBhsl42TJg5Vv8/eJB++vRbgfPZ4gJJntFh0EOT
aHMD+fTsv892WVqJ/Fk1nx778LQnwkUU6Kn/EIP/jIt/6G8mXmCOaR/ULHa7qUv9
Y5zy8MrUxQWxsDzxU1NsZnXVmRFH45s+wVWf4qLDG1r3r3wkN3wBaz9D96uT3xgZ
QrBPjCZtc3p9NJ1p9D3g5e55rU+jlj2MJxv+tQ7Q9jg15b+oQClr7z/GLT52VTY9
PGz6x1fzxQWI9AwcbGnc50bK9JZ0Mr1sDhyvxWG3zSu+yzpv1WE5GfeZchLuM+U0
DPUPVs+zwo5QnwReqvH6eXrKPTT3oU/zDHp6d6eL8fMp+znXJzxtpf+2e87QXa/K
TiNknc6anHxSBfS3cObvc+TYY2EuRdYLpGnr5LOP1V6o0ARS5+pZna07CC0Pet62
j9hfoGv6L0cgfyluTAAA
}
make-dir %./tempfiles/
repeat i 10 [write join %./tempfiles/ i random "asdfghjklqwertyuiop"]
zipfile: request-file/file/save/only %zippedfiles.zip
zip/deep zipfile %tempfiles/

Есть множество других полезных библиотек, доступных на rebol.org и на различных веб-сайтах сообщества Rebol (многие из которых созданы авторами выше).

15. Функция синтаксического анализа Parse

Функция синтаксического анализа parse Rebol имеет два режима работы. Во-первых, его можно использовать для разделения строк:

my-text: {"apple","orange","pear"}
parsed-block: parse my-text none

some-text: {    First Name
           Last Name
           Street Address
           City, State, Zip}
parsed-block: parse/all some-text "^/"
foreach item parsed-block [trim item]
probe parsed-block

Помимо этого, синтаксический анализ - один из самых уникальных и мощных аспектов Rebol. Это в значительной степени отвечает за способность Rebol создавать языковые диалекты (DSL). Parse может принимать либо блок, либо строку данных, а также набор правил, которые позволяют ему выполнять типы сопоставления с образцом, обычно обрабатываемые регулярными выражениями (regex).

Этот пример берет строку текста, выполняет поиск по строкам "<%" и "%>" - любой экземпляр - и заменяет все между строкой "text2":

code: "text1 <% replace this %> <% replace this %> text3"
parse/all code [
    any [thru "<%" copy new to "%>" (replace code new " text2 ")] to end
]
print code

В этом примере сопоставляются открывающие и закрывающие теги заголовков HTML, данные между ними копируются в метку my-ip, затем выполняется поиск в результате my-ip строки "Ваш IP-адрес:" и копируется все до конца в переменная с надписью 'stripped-ip:

parse read http://guitarz.org/ip.cgi [
    thru <title> copy my-ip to </title>
]
parse my-ip [
    thru "Your IP Address is: " copy stripped-ip to end
]
alert to-string rejoin [
    "External: " trim/all stripped-ip "  "
    "Internal: " read join dns:// read dns://
]

В этом примере извлекаются все ссылки на изображения, прочитанные из HTML-документа, копируются URL-адреса ссылок в блок с меткой "x", изображения загружаются в новую папку, а затем для каждого изображения отображается слайд-шоу с графическим интерфейсом пользователя. Обратите внимание, что одна строка читаемого кода синтаксического анализа извлекает все ссылки на изображения:

html: read http://musiclessonz.com/ScreenShots.html
x: copy []
parse html [any [thru {src="} copy link to {"} (append x link)] to end]
make-dir %./downloaded-images
change-dir %./downloaded-images
foreach i x [attempt [
    print rejoin ["downloading:  " i] 
    write/binary (to-file last split-path to-url i) (read/binary to-url i)
]]
foreach i read %. [view center-face layout [image (load i)]]

В этом примере выполняется поиск всех URL-ссылок http:// в строке текста и выполняется их упаковка в теги HTML <a href>:

bb:  "some text http://guitarz.org http://yahoo.com"
bb_temp: copy bb
append bb_temp " "
append bb " "
parse bb [any [thru "http://" copy link to " " (
    replace bb_temp (rejoin [{http://} link]) (rejoin [
    {<a href="} {http://} link {" target=_blank>http://} 
    link {</a>}]))] to end
]
bb: copy bb_temp
print bb

Этот пример позволяет вам в интерактивном режиме вносить изменения в некоторый код макета графического интерфейса:

code: {
    view layout [
        btn "some text"
        btn "some more text"
    ] 
}
strings: copy []
parse code [
    any [thru {"} copy a-string to {"} (append strings a-string)] to end
]
foreach str strings [
    if true = request rejoin [{Change "} str {"?}] [
        replace/all code str request-text/title rejoin [
            {Change "} str {" to:}
        ]
    ]
]
editor code

Это удаляет все комментарии из каждой строки кода в скрипте Rebol:

code: read to-file request-file
parse/all code [any [
    to #";" begin: thru newline ending: (
        remove/part begin ((index? ending) - (index? begin))) :begin
    ]
]
editor code  ; все комментарии удалены

В этом примере создается очищенный блок данных Rebol из документа CSV, считанного из файла:

filename: %filename.csv
data: copy []
lines: read/lines filename
foreach line lines [
    append/only data parse/all line ","
]
info: copy ""
foreach line data [
    either find "Header" line/1 [
        info: line/1
    ][
        append line info
    ]
]
remove-each line data [find "Header" line/1/1]
remove-each line data [
    (line/3 = "TITLE") or (line/3 = "DESCRIPTION")
]

Parse - чрезвычайно мощная замена регулярному выражению. Он удобочитаемый и полностью уникален для Rebol. Если вы хотите заниматься обработкой текста, интеллектуальным анализом данных или созданием диалектов в Rebol, ключевым моментом является обучение построению правил синтаксического анализа.

16. Привязка меток слов к контекстам

В REBOL слова поддерживают ссылку на контекст, в котором они созданы:

REBOL []
y: copy []
f1: func [/local x] [x: 1 append y 'x]
f2: func [/local x] [x: 2 append y 'x]
f1 
f2
probe y                        ; [x x]
probe reduce y                 ; [1 2]  !!!

Блок "y" выше содержит два слова с меткой "x", оба содержатся в одном блоке, но каждое слово "x" относится к разным значениям. Это верно, потому что каждой из меток переменных "x" было присвоено значение в другом контексте (в данном случае - в локальной области внутри функции).

Эта особая возможность Rebol может вызвать проблемы при использовании одних и тех же переменных, определенных в двух разных контекстах:

x: [1 2 3]
f: [print y]
foreach y x [do f]

** Script Error: y has no value
** Near: print y

Вы можете использовать функцию привязки для ссылки на конкретный экземпляр слова, связав его с другим словом из желаемого контекста:

x: [1 2 3]
f: [print y]
foreach y x [do bind f 'y]

Вы увидите, что "используется привязка при применении" правил синтаксического анализа, а также в определенных ситуациях метапрограммирования:

ui-size: system/view/screen-face/size - 0x50
gui: {size gui-size}
gui: to-block gui
view layout gui

** Script Error: gui-size word has no context
** Where: do-facets
** Near: gui-size

Привязка слова gui к глобальному контексту системы устраняет проблему, указанную выше:

gui-size: system/view/screen-face/size - 0x50
gui: {size gui-size}
gui: to-block gui
bind gui 'system
view layout gui

17. Многозадачность (у Rebol нет потоков)

В этом разделе демонстрируются некоторые основы многозадачности в REBOL. Этот пример демонстрирует, как получить ввод с клавиатуры, не блокируя цикл выполнения программы:

p: open/binary/no-wait console://
q: open/binary/no-wait [scheme: 'console]
count: 0
forever [
    count: count + 1
    if not none? wait/all [q :00:00.01] [
        wait q
        qq: to string! copy q
        probe qq
        print ["^/loop count incremented to" count "while waiting^/"]
    ]
]

Ранее в примере игры "Поймать" вы видели один метод многозадачности графического интерфейса. Используйте "view/new" для создания графического интерфейса, но не запускайте цикл событий (обычно с помощью "do-events"). Вместо этого запустите бесконечный цикл "forever", выполните любые вычисления, оценки и вручную обновите отображение макета с помощью "show". Как правило, вы хотите включать небольшую задержку в каждый повтор, используя функцию "wait" (ожидание):

REBOL [title: "Catch Game"]
random/seed now   
start: now/time
speed: 2
view/new center-face g: layout [
    size 600x440 
    at 280x20   a: image logo.gif
    at 280x420  b: btn 50x20 blue
    key keycode [left]  [b/offset: b/offset - 10x0]
    key keycode [right] [b/offset: b/offset + 10x0]
]
forever [
    a/offset: a/offset + (as-pair 0 round speed)
    if overlap? a b [
        a/offset: as-pair (random 500) 20
        speed: speed + .1
    ]
    if a/offset/y > 440 [break]
    wait .01
    show g
]

Другой способ многозадачности в графическом интерфейсе:

  1. Присвойте виджету с графическим интерфейсом значение 0.
  2. Назначьте этому виджету "feel" (ощущение) обнаружения и поместите действия, которые вы хотите выполнять одновременно, в блок, который будет оцениваться каждый раз, когда происходит событие "time" (время).
  3. Остановите и начните оценку одновременно активных частей кода, назначив скорость "нет" или 0, соответственно, ассоциированному (-ым) виджету (-ам) графического интерфейса.

Вот демонстрация графического интерфейса описанной выше техники:

REBOL [title: "GUI Multitasking"]
webcam-url: http://209.165.153.2/axis-cgi/jpg/image.cgi
view layout [
    btn "Start Video" [
        webcam/rate: 0 
        webcam/image: load webcam-url 
        show webcam
    ]
    btn "Stop Video" [webcam/rate: none show webcam]
    return 
    webcam: image load webcam-url 320x240 rate 0 feel [
        engage: func [f a e][
            if a = 'time [
                f/image: load webcam-url show f
            ] 
        ] 
    ]
    clock: field to-string now/time/precise rate 0 feel [
        engage: func [f a e][
            if a = 'time [
                f/text: to-string now/time/precise show f
            ] 
        ] 
    ]
    h3 "Notice the delay in the timer as each image loads"
]

В этом примере достигается истинная многозадачность, просто записывая код для одного процесса в отдельный файл и выполняя его в отдельном процессе интерпретатора REBOL с помощью функции "launch" (запуска):

REBOL [title: "Launching Separate Processes"]
write %async.r {
    REBOL []
    view layout [
        origin 10x10
        clock: field to-string now/time/precise rate 0 feel [
            engage: func [face action event][
                if action = 'time [
                    face/text: to-string now/time/precise show face
                ] 
            ] 
        ]
    ]
}
launch %async.r
webcam-url: http://209.165.153.2/axis-cgi/jpg/image.cgi
view center-face layout [
    btn "Start Video" [
        webcam/rate: 0 
        webcam/image: load webcam-url 
        show webcam
    ]
    btn "Stop Video" [webcam/rate: none show webcam]
    return 
    webcam: image load webcam-url 320x240 rate 0 feel [
        engage: func [face action event][
            if action = 'time [
                face/image: load webcam-url show face
            ]
        ]
    ]
]

18. Подробнее о встроенной справке

Функция "help" отображает необходимый синтаксис для любой функции REBOL:

help print

"?" является синонимом слова "help":

? print

Функция "what" перечисляет все встроенные слова:

what

Вместе эти два слова представляют собой встроенное справочное руководство для всего основного языка REBOL. Вот сценарий, который сохраняет всю вышеуказанную документацию в файл. Дайте ему несколько секунд на запуск:

echo %words.txt what echo off   ; "echo" saves console activity to a file
echo %help.txt
foreach line read/lines %words.txt [
    word: first to-block line
    print "___________________________________________________________^/"
    print rejoin ["word:  " uppercase to-string word]  print "" 
    do compose [help (to-word word)]
]
echo off
editor at read %help.txt 4

Вы можете использовать справку для поиска определенных слов и значений, если не можете вспомнить точное написание слова. Просто введите часть слова (нажатие клавиши табуляции также покажет список слов для автоматического завершения слова):

? to-         ; показывает список всех встроенных преобразований типов
? reques      ; показывает список встроенных функций запроса
? "load"      ; показывает все слова, содержащие символы "load"
? "?"         ; показывает все слова, содержащие символ "?"

Вот ещё несколько примеров способов поиска полезной информации с помощью справки:

? datatype!   ; показывает список встроенных типов данных
? function!   ; показывает список встроенных функций
? native!     ; показывает список собственных (скомпилированный код C) функций
? char!       ; показывает список встроенных управляющих символов
? tuple!      ; показывает список встроенных цветов (кортежи RGB)
? .gif        ; показывает список встроенных изображений .gif

Вы можете просмотреть исходный код для встроенных "мезонинных" (неродных) функций с помощью функции "source". Огромный объем кода REBOL доступен прямо в интерпретаторе, а все мезонинные функции были созданы дизайнером языка Карлом Сассенратом. Изучение исходного кода мезонина - отличный способ узнать больше о расширенных шаблонах кода REBOL:

source help
source request-text
source view
source layout
source ctx-viewtop  ; попробуй это:  view layout [image load ctx-viewtop/13]

Скрипт "word browser" (браузер слов) - полезный инструмент для поиска, перекрестных ссылок и изучения всех важных функций REBOL:

write %wordbrowser.r read http://re-bol.com/wordbrowser.r
do %wordbrowser.r

18 Системный объект REBOL и справка с виджетами графического интерфейса

"Справочная система" отображает содержимое системного объекта REBOL, который содержит множество важных настроек и значений. Вы можете исследовать каждый уровень системного объекта, используя обозначение пути, например:

? system/console/history        ; текущая история сеанса консоли
? system/options
? system/locale/months
? system/network/host-address

Вы можете найти информацию обо всех компонентах GUI REBOL в "system/view/VID":

? system/view/VID

Блок system/view/VID настолько важен, что REBOL имеет встроенный ярлык для ссылки на него:

? svv

Вы найдете список виджетов GUI REBOL в "svv/vid-styles". Используйте функцию "editor" (редактор) REBOL для просмотра больших разделов системы, например:

editor svv/vid-styles

Вот сценарий, который аккуратно отображает все слова в приведенном выше блоке "svv/vid-styles":

foreach i svv/vid-styles [if (type? i) = word! [print i]]

Вот более краткий способ отображения указанных выше виджетов с помощью функции "extract" (извлекать):

probe extract svv/vid-styles 2

Этот скрипт позволяет просматривать структуру объектов каждого виджета:

view layout [
    text-list data (extract svv/vid-styles 2) [
        a/text: select svv/vid-styles value
        show a focus a
    ]
    a: area 500x250 
]

Слова макета GUI REBOL доступны в "svv/vid-words":

? svv/vid-words

Следующий скрипт отображает все изображения в блоке "svv/image-stock":

b: copy [] 
foreach i svv/image-stock [if (type? i) = image! [append b i]]
v: copy [] foreach i b [append v reduce ['image i]]
view layout v

Изменяемые атрибуты ("facets"), доступные для всех виджетов графического интерфейса, перечислены в "svv/facet-words":

editor svv/facet-words

Вот сценарий, который аккуратно отображает все вышеупомянутые фасетные слова:

b: copy [] 
foreach i svv/facet-words [if (not function? :i) [append b to-string i]]
view layout [text-list data b]

Для некоторых виджетов с графическим интерфейсом пользователя доступны дополнительные фасетные слова. Следующий скрипт отображает все такие функции и их дополнительные атрибуты:

foreach i (extract svv/vid-styles 2) [
    x: select svv/vid-styles i
    ; additional facets are held in a "words" block:
    if x/words [
        prin join i ": "
        foreach q x/words [
            if not (function? :q) [prin join q " "]
        ]
        print ""
    ]
]

Чтобы изучить функции, которые обрабатывают любые дополнительные фасеты для виджетов выше, введите путь к блоку "words" (слова) виджета, то есть:

svv/vid-styles/TEXT-LIST/words

Для получения дополнительной информации о system/view/VID см. http://www.mail-archive.com/rebol-bounce@rebol.com/msg01898.html и http://www.rebol.org/ml-display-message.r?m=rmlHJNC.

Важно отметить, что вы можете УСТАНОВИТЬ любое системное значение. Просто используйте двоеточие, например, при присвоении значений переменных:

system/user/email: user@website.com

Знакомство с системным объектом даёт много полезных инструментов.

19. Узнать больше - Интернет-ресурсы

Rebol - мощный инструмент разработки общего назначения. Вы можете использовать его для создания сложного программного обеспечения всех типов для настольных, мобильных, серверных и веб-сред с большей простотой и значительно улучшенной производительностью по сравнению с другими инструментами. Поскольку код Rebol обычно на несколько порядков короче, лаконичнее и читабельнее, чем код, написанный с помощью популярных инструментов, таких как Java, C, Visual Basic, и даже инструментов сценариев, таких как Python, Ruby и Lua, разработка с его помощью означает возможность чтобы создать гораздо больше программного обеспечения в течение вашей жизни, и это делает обслуживание, обновление и улучшение этого программного обеспечения гораздо более управляемым, чем с другими инструментами разработки. Портативность, небольшой размер и уникальные особенности Rebol обеспечивают возможности, которые просто невозможны при использовании других платформ разработки.

Чтобы узнать больше о Rebol, см .:

http://business-programming.com: полная книга 850, в которой задокументировано всё, что вам нужно знать для создания различных типов приложений с Rebol (R2). В ЭТОМ ТЕКСТЕ ВКЛЮЧЕНО БОЛЕЕ 100 ПОЛНЫХ РАБОЧИХ ПРОГРАММ, каждая тема полностью объяснена, а также предоставлены ссылки на многие другие вспомогательные онлайн-документы и ресурсы. Примеры представляют собой множество полезных решений и шаблонов кода, которые демонстрируют, как решать многие типичные проблемы программирования с помощью Rebol. Более старая версия этого текста находится на http://re-bol.com

http://re-bol.com/examples.txt: пример кода из книги выше, без лишнего кода. Большая часть этого кода включена в настоящий текст, но по ссылке examples.txt довольно много дополнительных полных приложений.

19.1 Ссылки R3

http://learnrebol.com: узнайте о новейшей версии Rebol (Saphir R3 и R3-GUI) с открытым исходным кодом, доступной для мобильных платформ Android, а также для настольных и серверных сред.

Ссылки ниже являются критически важными справочными документами R3 и R3-GUI:

http://www.rebol.com/rebol3/index.html http://www.rebol.com/r3/docs/gui/gui.html http://development.saphirion.com/rebol/r3gui/ (при поддержке вверх по адресу http://re-bol.com/saphirion-r3guidocs.zip) https://github.com/saphirion/documentation

Важно понимать, что R3 - это проект с открытым исходным кодом, наиболее активно разрабатываемый сейчас группой на saphirion.com. Документы R3, найденные на rebol.com, в целом полезны и правильны, но не обязательно обновлены с учетом улучшений, сделанных Saphirion, особенно для неосновных функций, таких как графический интерфейс, протоколы, порты на новые платформы ОС и т.д.

19.2 Rebolforum.com

Помимо списка вспомогательных документов и ссылок на веб-сайты в учебнике business-programming.com, на http://rebolforum.com/index.cgi?f=printtopic&permalink=Nick19-Jan-2014/18:29:47-8:00&archiveflag=new поддерживается коллекция важных в настоящее время ссылок.

19.3 Rebol.org

Rebol.org поддерживает доступную для поиска историю нескольких сотен тысяч сообщений как из списка рассылки, так и из AltME, а также богатый архив сценариев. Обычно вы можете найти ответы практически на любой вопрос уже в архивах.

19.4 Форумы и сообщество AltME

Чтобы задать вопрос напрямую другим разработчикам REBOL, вы можете отправить сообщение на форуме:

http://rebolforum.com

http://chat.stackoverflow.com/rooms/291/rebol-and-red

Но наиболее активно сообщество Rebol использует эту программу:

AltME

Загрузите его и создайте учётную запись пользователя в мире "Rebol4". Просто следуйте инструкциям на сайте http://www.rebol.org/aga-join.r. Присоединение к AltME и знакомство с сообществом - лучший способ задать вопросы и найти поддержку, связанную с Rebol.

MakeDoc2 by REBOL - 19-Dec-2021