Ruby представляет собой объектно-ориентированный язык программирования интерпретирующего типа. Он был создан программистом из Японии -- Юкихиро Матсумото (Yukihiro Matsumoto), где этот язык пользуется большей популярностью нежели Python или Perl! Первая часть из серии является введением в основы языка Ruby. Более глубокий материал будет даваться в последующих частях.
Я не собираюсь превозносить язык Ruby и доказывать его преимущества перед другими языками программирования. Большинство из нас прекрасно понимают, что каждый язык программирования имеет свои неповторимые черты. И ваш выбор скорее будет зависеть от ваших личных предпочтений и доступности стандартных библиотек, нежели от неких таинственных технических проблем.
Я полагаю, что вы работаете в Linux и Ruby уже установлен у вас. Ruby - это свободно распространяемое программное обеспечение и поэтому нет никаких препятствий, ограничивающих его использование. Вы можете скачать его с домашней странички проекта Ruby
Начнем с обычной в таких случаях программы `Hello, World'
% cat > hello.rb print "Hello World\n" ^D % ruby hello.rb Hello World %
Имена переменных должны начинаться с символа:
$ глобальная переменная @ переменная экземпляра (поле объекта, данные-член) a-z или '_' локальная переменная A-Z константа
Кроме того существуют еще две псевдопеременные, которые являются исключением из вышеуказанного правила - это `self' и `nil'.
Обе они именуются как локальные переменные, но таковыми не являются! Реальный смысл этих переменных станет вам понятен немного позже.
Имена глобальных переменных должны начинаться с символа `$'. Глобальные переменные доступны из любой части программы. Следует отметить, что неинициализированная глобальная переменная имеет значение 'nil'. Этот факт демонстрирует следующий пример:
% ruby print $foo,"\n" $foo = 5 print $foo,"\n" ^D %Результат работы интерпретатора:
nil 5Эта особенность дает возможность `связывать' процедуры с глобальными переменными, т.е. при изменении значения переменной `связанная' процедура будет вызываться автоматически. Но об этом позже!
Существует ряд специальных предопределенных глобальных переменных, являющихся по сути системными переменными интерпретатора Ruby (доступны только для чтения). Некоторые из них приведены ниже.
Имена локальных переменных должны начинаться с прописных (маленьких) символов латинского алфавита или с символа '_'. В отличие от глобальных переменных и ссылок на переменные, локальные переменные не принимают значение 'nil', например, при выполнении следующего кода:
% ruby print foo ^DВы получите сообщение об ошибке:
"undefined local variable or method 'foo' for #(object...)".
Область видимости локальных переменных ограничивается одной из следующих разновидностей блоков программы
def foo(n) k = 2 * n print "\n",k,"\n" print defined? k,"\n" end foo 3 print defined? k,"\n" ^DВывод интерпретатора:
6 local-variable nil
В этом примере оператор `defined?' используется для проверки существования передаваемого ему аргумента. Результаты работы оператора "local-variable" и "nil" понятны и так и в комментариях не нуждаются.
Имена констант начинаются с заглавных (больших) символов латинского алфавита. Но, как правило, программирующие на Ruby, дают константам имена, состоящие только из заглавных символов. Так, например и 'Foo', и 'FOO' являются константами. Как и в случае с локальными переменными, константы инициализируются оператором присваивания, а обращение к неинициализированной константе, равно как и попытка изменения инициализированной константы, вызывает сообщение об ошибке. Проверьте это самостоятельно.
Строки в Ruby ограничиваются либо одинарными ('...'), либо двойными кавычками ("..."). Однако такие строки имеют различия между собой. При использовании двойных кавычек допускается вставлять в строки управляющие escape-последовательности, начинающиеся с символа '\', а также вычислять выражения с помощью конструкции #{}. Например:
print "\n" print '\n' print "\001","\n" print '\001',"\n" print "abcd #{5*3} efg","\n" var = " abc " print "1234#{var}567","\n" ^D \n \001 abcd 15 efg 1234abc567
Дополнительную информацию по строкам вы получите в разделе, посвященном массивам, поскольку массивы и строки во многом похожи друг на друга.
Для определения массивов используются квадратные скобки '[]'. Массивы в Ruby являются гетерогенными (т.е. могут содержать данные различных типов).
a = [1,2,"3"] print a,"\n" ^D 123
Однако, если вы попытаетесь заставить интерпретатор подсчитать сумму элементов массива, показанного выше, то он выдаст сообщение об ошибке:
Error!!String cannot be coerced into FixnumДело в том, что элемент массива `3' хранится в виде строки. Если вычисление суммы элементов массива задать следующим образом:
a = [1,2,"3"] b = a[0] + a[1] + a[2].to_i print b,"\n" ^D 6То интерпретатор выполнит его без ошибки. Добавление '.to_i' к 3-му элементу массива (т.е. a[2].to_i) заставляет интерпретатор выполнить преобразование содержимого элемента массива a[2] в целое со знаком. Ради эксперимента можете попробовать подставить '.to_s'.
К массивам можно применять операции конкатенации (слияния) и повторения.
a = [1,2,"3"] print a + ["foo","bar"] print a * 2 ^DРезультат
123foobar 123123
Можно получить "срез" массива:
a = [1,2,"3","foo","bar"] print a[0],"\n" print a[0,2],"\n" print a[0..3],"\n" print a[-2..2],"\n" print a[-3..-1],"\n"
Массивы и строки взаимно конвертируемы. Массив можно преобразовать в строку с помощью метода 'join', а строку -- в массив с помощью метода 'split'.
a = [1,2,3] print a[2],"\n" a = a.join(":") print a[2],"\n" print a,"\n" a = a.split(":") print a[2],"\n" print a,"\n" ^D
Ассоциативные массивы (хэши (англ. hash) или словари)-- еще один немаловажный вид представления данных. Хэши содержат пары ``ключ'' и ``значение'', см. пример ниже:
h = {1 => 2, "2" => "4"} print hash,"\n" print hash[1],"\n" print hash["2"],"\n" print hash[5],"\n" ^DЯ, надеюсь, результаты убедительны!
Попробуем написать функцию вычисления факториала. Математическое определение факториала:
n! = 1 (если n==0) n! = n * (n-1)! (иначе)На Ruby вычисление факториала может быть реализовано следующим образом:
def fact(n) if n == 0 1 else n * fact(n-1) end end print fact 4,"\n"В результате получится 24.
Из-за наличия ключевого слова `end' Ruby иногда называют 'Алголо-подобным' языком. В данном примере рекурсивной функции вы можете заметить отсутствие оператора возврата результата (return). Естественно, использование этого оператора не возбраняется, но в данной ситуации он является излишним, поскольку в качестве возвращаемого значения принимается результат вычисления последнего выражения.
for i in 0..4 body-of-for end
Где i -- переменная цикла, а 0..4 -- диапазон значений. Для строковых переменных, заголовок цикла for можно записать так:
for i in "abc"
Попробуйте запустить этот пример
i=0 while i < 10 print i+=1,"\n" end
Оператор выбора case используется для проверки набора условий. В результате работы следующего примера
i = 7 case i when 2..5 print "i in 2 to 5\n" when 6..10 print "i in 6 to 10\n" end ^D
вы получите
i in 6 to 10
2..5 -- означает диапазон значений от 2 до 5 включительно. Здесь проверяется - попадает ли значение переменной i в заданный диапазон.
В случае строк, оператор case будет выглядеть примерно так:
case 'abcdef' when 'aaa','bbb' print 'contains aaa or bbb \n" when /def/ print "contains def \n" end ^D contains def
Обратите внимание на слэши (символ "/"), которые окружают ключевое слово "def". Они используются для задания границ регулярного выражения, которые мы рассмотрим позднее.
Оператор case, из примера, приведенного выше, проверяет попадание значения переменной i в диапазон 2..5. Эта же проверка может быть записана несколько иначе, например:
(2..5) === i
Оператор отношения '===' используется для проверки выполнения нескольких условий одновременно и интерпретируется подобно ключевому слову when.
Попробуйте самостоятельно реализовать функцию, подобную isalnum(),isalpha(),isnum() и т.п. с помощью оператора '===' внутри конструкции if.
При использовании конструкций if и while для проверки отдельных значений, код может быть несколько сокращен
i = 7 print "contained in 5..10\n" if (5..10) === i print i-=1,"\n" while i > 0 ^D contained in 5..10 6 5 4 3 2 1 0
Иногда может возникнуть необходимость в инвертировании проверяемого условия. Так, условие "если" (if) при инвертировании приобретает смысл "если не", условие while -- в условие until и т.д.
Существует четыре различных варианта управления исполнением цикла. Первый, аналогичный C -- break, означает выход за тело цикла. Второй -- next, переход в начало следующей итерации (аналог continue в C). Третий -- redo, перезапускает текущую итерацию. Следующий C-код иллюстрирует механизм работы этих трех методов (break, next и redo):
while(condition) { label_redo: goto label_next; /* ruby's "next" */ goto label_break; /* ruby's "break"*/ goto label_redo; /* ruby's "redo" */ ... ... label_next: } label_break: ...
И четвертый вариант -- оператор return. Фактически, этот оператор приводит не только к прерыванию цикла, но и к завершению работы метода (функции), который содержит прерываемый цикл.