Особенность eval[править]
Когда один из моих студентов занимался разработкой калькулятора на Ruby, то он столкнулся с одной интересной особенностью метода . В случае синтаксической ошибки в строке, переданой в качестве параметра, программа вылетала с ошибкой . Ниже идет пример, который демонстрирует эту ситуацию:
begin eval('2+2+') rescue p "error" end
Для контроля за ситуацией надо явно указать ошибку, которую вы хотите контролировать (в нашем случае ).
begin eval('2+2+') rescue SyntaxError p "error" end
Теперь все работает! Осталось только заметить, что если строка приходит из внешнего источника, то желательно ее предварительно проверить на соответствие вашим ожиданиям. Иначе, вы будете кормить хакеров… Как пояснил Yuri Leikind, этот эффект связан с тем, что rescue без параметра отлавливает ошибки выполнения программы (), а приведенный выше пример вызывает исключение (). В общем, проблема все равно решается так, как я описал выше.
Условные
При программировании мы часто хотим проверить наличие определенного условия, а затем на основе этого условия выполнить то или иное действие. Они называются условными. Давайте посмотрим на условное выражение в Ruby:
Разберем код:
- Этот код будет распечатан The number is between 1 and 5, потому что номер, присвоенный переменной numberв первой строке, равен 3. Это означает, что вызов метода number.between?(1, 5)возвращается true.
- Ruby выполнит код в ifветке и проигнорирует остальную часть оператора.
Теперь мы собираемся быстро взглянуть на сокращенный синтаксис для написания условных выражений в Ruby.
Trailing
Мы можем добавить наш ifоператор к коду в ifветке, если он находится всего в одной строке. Итак, вместо этого:
Вместо этого мы можем сделать это:
Это отличный пример удобочитаемого синтаксиса Ruby. Второй пример не только экономит нам две строки, но и очень хорошо читается!
unless
В Ruby также есть unlessинструкция, которую мы можем использовать, когда хотим что-то сделать, если условие не применяется (не имеет значения true). Опять же, мы можем добавить unlessоператор в конец строки. Эти два одинаковые:
Parentheses
В Ruby, когда вы определяете или выполняете метод, вы можете опустить круглые скобки. Следующие две строки кода означают одно и то же:
Итак, когда я могу использовать круглые скобки, а когда их опускать?
Отличный вопрос! На самом деле нет четкого правила на этот счет, но есть некоторые условности. Вот что мы рекомендуем вам пока придерживаться:
- Используйте круглые скобки для всех вызовов методов, которые принимают аргументы, за исключением puts, p, requireиinclude
- Если метод не принимает аргументов, не добавляйте пустые скобки, просто опустите их.
Подпрограммы: функции, методы и другие…[править]
Многие из студентов уже встречались с такими словами и даже пытались самостоятельно понять, что они значат. Но вопрос все равно возникает, и хотелось бы его разобрать по кускам, чтобы он больше не возникал. Начнем с того, что подпрограммы, функции и методы — это все одно и тоже. Отличия лишь в незначительных деталях. Все это кусок программы, которые программист решил объявить всего лишь один раз, а потом вызывать столько сколько душе угодно. Например, программисту заказали программу подсчета суммы факториалов (помните ) двух чисел. Вот как он написал бы программу, если бы у него не было возможности составлять подпрограммы:
n1, n2 = 4, 5 p1, p2 = 1, 1 n1.times{ |i| p1 *= i + 1 } n2.times{ |i| p2 *= i + 1 } puts "#{n1}! + #{n2}! = #{p1 + p2}"
Он тут же смекнул, что писать кусок программы подсчета факториала числа он написал дважды (чисел, то две штуки) и решил написать подпрограмму, которая этот факториал числа вычислит. Вот как будет выглядеть более продвинутая программа:
def fact( int ) pr = 1 int.times{ |i| pr *= i + 1 } pr end n1, n2 = 4, 5 puts "#{n1}! + #{n2}! = #{fact(n1) + fact(n2)}"
А если нужно было бы складывать три числа? Выигрыш в простоте очевиден. А теперь давайте разберемся, что же такое мы написал смекалистый программист. Разберем сначала верхний кусок. Он называется ОПРЕДЕЛЕНИЕМ ПОДПРОГРАММЫ или ОПРЕДЕЛЕНИЕМ МЕТОДА (от англ. define methods). Верхняя строчка состоит из ключевого слова , названия метода (в нашем случае ) и списка аргументов, то есть входных данных (в нашем случае )
Если в списке аргументов указано всего одно имя переменной, то и передавать в метод (при вызове) надо тоже один аргумент (обратите внимание на вызов метода ,. Его не обязательно вызывать с переменной в качестве аргумента
Достаточно указать какое либо число, например ). Помимо того, взгляните на в конце тела метода. ЛЮБОЙ МЕТОД должен заканчиваться . Типичный шаблон для создания метода выглядит примерно так:
def имя_метода( имя_первого_аргумента, имя_второго_аргумента, и т.д.) кусок_программы_который_мы_хотим_поместить_в_подпрограмму end
Вызывать наш метод надо примерно так:
имя_метода( значение_первого_аргумента, значение_второго_аргумента, и т.д.)
Теперь обратите внимание на то, что переменная pr в теле метода (на которую мы заменили переменные p1 и p2) расположена в последней строчке подпрограммы (т.е. непосредственно перед end)
Вроде как она там прохлаждается и совсем не нужна, но это не так. Таким образом, мы говорим, что переменная pr является РЕЗУЛЬТАТОМ РАБОТЫ ПОДПРОГРАММЫ. И как раз результат перемножения хранится в этой переменной, т.е. данная переменная содержит факториал числа int (т.е. числа, которое передано в качестве первого аргумента). Отсюда и получается, что наша подпрограмма ВОЗВРАЩАЕТ факториал числа. Теперь ПРАВИЛО: программный КОД, который ПОВТОРЯЕТСЯ больше двух раз, ДОЛЖЕН быть ВЫНЕСЕН В ПОДПРОГРАММУ. А сейчас немного о различиях между подпрограммой, функцией и методом. Дело в том, что ПОДПРОГРАММА — это ОБЩЕЕ НАЗВАНИЕ методов, функций и процедур, т.е. объединяющее понятие. Если программист говорит подпрограмма, то он может иметь в виду как метод, так и процедуру. Теперь про различия между методами, функциями и процедурами. Процедуры — это устаревшая конструкция, от которой многие языки программирования отказались. На данный момент она используется только в языке Pascal. СЕЙЧАС в основном ОСТАЛИСЬ только МЕТОДЫ, и ФУНКЦИИ. От процедур их отличает то, что ОНИ ВОЗВРАЩАЮТ РЕЗУЛЬТАТ. Иными словами, ПРОЦЕДУРА — это метод или функция, которые НЕ ВОЗВРАЩАЮТ РЕЗУЛЬТАТА. Теперь пор различия между методами и функциями. МЕТОДЫ есть только в ОБЪЕКТНО-ОРИЕНТИРОВАННЫХ ЯЗЫКАХ. ФУНКЦИИ во всех ОСТАЛЬНЫХ. Отсюда можно заключить, что мы написали с вами подпрограмму, которая является методом, т.к. Ruby — ОБЪЕКТНО-ОРИЕНТИРОВАННЫЙ ЯЗЫК. PS. Большие буквы — это влияние самоучителя Драгункина…
Тенденции в ООП[править]
Просматривая исходники некоторых стандартных библиотек Ruby наткнулся на интересную тенденцию в описании классов. Мое наблюдение касается объявление методов класса. Напомню, что такое метод класса… Метод класса — это метод, который вызывается не относительно объекта, а относительно самого класса. Пример:
puts Dir.getwd # getwd -- метод класса Dir.new("testdir").each{|x| puts "Got #{x}" } # each -- метод объекта, а new -- метод класса.
В первом случае происходит вызов метода класса, а во втором — метода объекта (метод класса создает объект, от которого вызывается метод ). Перед вызовом метода класса всегда идет название класса (в нашем случае ). В чем же их отличие при объявлении? Ниже представлен пример объявления класса метода и класса объекта:
class Dir def Dir.getwd # тело метода end def each # тело метода end end
Теперь про тенденцию… Если методов класса много, то в стандартных библиотеках просто создают еще один блок, в который помещают методы класса. Пример:
class Dir class << self def getwd # тело метода end end def each # тело метода end end
Вот такое интересное наблюдение. Думаю, что эта методика закреплена в каком либо регламентирующем документе и в дальнейшем будет стандартом.
Константы при программировании окошек[править]
Во время программирования окошек всегда приходится создавать массу констант. Чтобы потом на эти константы вешать обработчики событий. И вот какая меня посетила идея по этому поводу. Чаще всего первые строчки типичной оконной программы выглядят примерно так:
ID_FRAME = 1 ID_DIALOG_1 = 2 ID_DIALOG_2 = 3 ID_DIALOG_3 = 4
Иногда можно увидеть, как разработчик выравнивает объявления констант в одну строчку:
ID_FRAME, ID_DIALOG_1, ID_DIALOG_2, ID_DIALOG_3 = 1,2,3,4
А теперь продолжим мысль и заменим правую часть более короткой записью:
ID_FRAME, ID_DIALOG_1, ID_DIALOG_2, ID_DIALOG_3 = (1..4).to_a
Теперь используем оператор вместо метода .to_a, что позволит запись сделать более изящной, но и более непонятной:
Побитовые операторы в Ruby
Побитовый оператор работает с битами и выполняет побитовую операцию.
Предположим, что a = 60; и b = 13; теперь в двоичном формате они будут выглядеть следующим образом:
a = 0011 1100 b = 0000 1101 ------------------ a&b = 0000 1100 a|b = 0011 1101 a^b = 0011 0001 ~a = 1100 0011
Язык Ruby поддерживает следующими побитовые операторы.
оператор | Описание | пример |
---|---|---|
& | Двоичный оператор AND копирует бит в результат, если он существует в обоих операндах. | (a & b) даст 12, что составляет 0000 1100 |
| | Двоичный оператор OR копирует бит, если он существует в любом из операндов. | (a | b) даст 61, что составляет 0011 1101 |
^ | Оператор двоичного XOR копирует бит, если он установлен в один операнд, но не тот и другой. | (a ^ b) даст 49, то есть 0011 0001 |
~ | Binary Ones Оператор дополнения является унарным и имеет эффект «flipping» бит. | (~ a) даст -61, что составляет 1100 0011 в форме дополнения 2 из-за подписанного двоичного числа. |
<< | Двойной левый оператор сдвига.Значение левых операндов перемещается влево на количество бит, заданных правым операндом. | a << 2 даст 240, что составляет 1111 0000 |
>> | Двоичный оператор правого сдвига.Значение левых операндов перемещается вправо на количество бит, заданных правым операндом. | a >> 2 даст 15, то есть 0000 1111 |
100 популярнейших методов в Ruby[править]
Какие методы в Ruby самые популярные? Естественно, что ответ на подобный вопрос зависит от опытности программиста и его собственного стиля. А ведь хочется узнать ответ «в общем»… Для чего мне это? Ну как же, детей надо обучать методам первой необходимости (остальные сами выучат). Им же лень учить все! Поэтому при проектировании учебных пособий следует учитывать частоту использования тех или иных методов. Метод (он же ) учитывать не будем, ибо ясно, что он один из популярнейших. Чтобы найти наши 100 излюбленных методов Руби мы напишем простенькую программу (которая имеет право глючить) и натравим ее на каталог ruby (для узости можно натравить только на каталог ruby/lib). Методы будем искать и в строках и в коментариях. Для тех, кто хочет чистоты эксперимента, может удалять из обработки строки и коментарии. Я их оставил умышленно. Итак, код программы:
require 'find' result = [] Find.find('c:/ruby/'){ |path| if test(?f,path) && path =~ /\.rbw?$/ result += IO.read( path ).scan( /\.+/ ) end } puts (result - '.com','.jp','.org','.rb','.rbw','.amazon').inject( Hash.new() ){ |result,elem| result elem = result elem succ result }.sort_by{ |array| array1 }.reverse...100map{ |array| array.reverse.join(' : ') }
Как видно из кода программы, она предельно проста и хватает даже доменные зоны в качестве методов (а чего?! метод .com очень даже ничего). Результат ее работы примерно такой (цифра слева — это частота использования):
11866 : .new 2075 : .each 1589 : .create 1409 : .kind_of? 1178 : .pack 1140 : .size 1047 : .to_s 1046 : .join 914 : .name 832 : .nil? 817 : .freeze 711 : .push 692 : .to_i 620 : .id 615 : .empty? 583 : .delete 571 : .length 569 : .class 563 : .collect 555 : .shift 519 : .path 513 : .call 433 : .add 423 : .data 419 : .bind 415 : .inspect 413 : .split 370 : .value 349 : .text 329 : .include? 324 : .manager 316 : .index 315 : .connect 312 : .open 305 : .is_a? 303 : .dup 282 : .insert 267 : .gsub 266 : .print 260 : .concat 256 : .close 255 : .puts 248 : .destroy 231 : .read 231 : .start 231 : .pop 220 : .set 212 : .parse 207 : .ac 204 : .parent 203 : .match 200 : .kyutech 200 : .last 193 : .current 189 : .root 179 : .update 177 : .ruby 177 : .respond_to? 174 : .downcase 171 : .grid 171 : .properties 169 : .key? 169 : .gsub! 165 : .to_f 162 : .type 160 : .write 159 : .message 156 : .width 154 : .to_a 151 : .find 149 : .invoke 145 : .require 144 : .critical 140 : .nodeType 138 : .mainloop 136 : .configure 133 : .unpack 129 : .has_key? 129 : .clear 128 : .map 127 : .exist? 122 : .chr 121 : .html 120 : .strip 118 : .now 117 : .namespace 115 : .handle 114 : .first 114 : .method 112 : .sub 112 : .unshift 112 : .sort 112 : .sub! 109 : .scan 109 : .run 107 : .body 107 : .appendItem 105 : .taint 103 : .height 103 : .id2obj
Все это конечно бред, зато прикольно и есть над чем подумать!
Типы переменных в Ruby
Существует пять типов переменных:
1. Константы.2. Глобальная переменная.3. Переменная класса.4. Переменная экземпляра.5. Локальная переменная.
- Пример объявления константы:
a = "This is my book."
2. Пример объявления глобальной переменной (используется символ ):
$var = 'I love my-self'
3. Пример объявления переменной класса (используется символ @@):
@@instances = 0
4. Пример объявления переменной экземпляра (используется символ @):
@var = 'Ruby Programming'
5. Пример объявления локальной переменной:
Локальные переменные — самые распространенные, они не выходят за рамки области видимости. Эти переменные объявляются без использования перед именем переменной символов или , при этом имя переменной не должно быть целиком заглавными буквами.
var = 10