Настройки текста:
«Конец моим страданиям и разочарованиям»
Из песенки Вини-Пуха.
Название Ruby уже неоднократно попадалось мне на глаза на различных сайтах. К сожалению, я до сегодняшнего дня не находил времени исследовать Ruby. Почему к сожалению? Потому что это действительно замечательный язык и я это только сейчас узнал, что и стало поводом написать этот курс.
Курс ориентирован на читателей, которые уже знают какой-либо язык программирования и понимают магию, с помощью которой из набора разрозненных операторов получается нечто действительно полезное. Поэтому курс сокращен до предела и организован в виде блоков "задача — решение". Блоки сгруппированы в тематические разделы.
Язык Ruby был задуман японским программистом Yukihiro Matsumoto в 1993 году как результат синтеза всех лучших черт языков программирования с целью максимально упростить создание программ. Результат синтеза в идеях языка изложен в документации по Ruby. Ниже представлены наиболее важные из них:
● Это интерпретируемый язык. В простейшем случае это означает, что стадия компиляции для него отсутствует. Это сокращает время, необходимое для создания программы.
● В Ruby переменная может хранить любой объект — можно сказать, что Ruby безтиповый язык, как PHP или Perl.
● Определять переменные не нужно. Для задания области видимости переменной используются приставки. Например $myVar — это глобальная переменная, а myVar — локальная.
● Garbage Collector освобождает от управления памятью. Объекты, на которыре не существует ссылок, автоматически выгружаются из памяти.
● Примитивные типы отсутствуют — любое значение является объектом.
● Поддержка основных концепций ООП.
● Чрезвычайно гибкая система итераторов.
● Части кода представлены как объекты
● Поддержка регулярных выражений и сходные с Perl методы работы с ними.
● В Ruby нет разделения на Integer, Long, Byte. Для целочисленных типов есть только один тип, в рамках которого можно проводить вычисления с произвольным количеством разрядов.
● Механизмы перехвата исключений (как в Java).
Другие особенности, которые мне особо понравились:
● Поддержка потоков
● Все операторы возвращают значения, в том числе управляющие структуры (if, case)
● return в конце функции не обязателен, возвращается значение последнего оператора. Например:
● def myFunction(a, b)
● a + b
● end
● puts myFunction(1, 2)
напечатает 3.
● Условия and и or возвращают элемент, эквивалентный true или первый элемент Например:
● puts 5 or 10 > 5
● puts 10 or nil > 10
● puts nil or 7 > 7
● puts nil and 10 > nil
Внимание программистам на C и производных: пустая строка и ноль не расцениваются как false. false — это только nil (null).
Если у вас Gentoo Linux, то Ruby уже, скорее всего, будет установлен. Если же нет, то это досадное недоразумение исправляется очень легко.
$ emerge ruby
Далее можно переходить к установке дополнительных модулей или к первым программам на Ruby.
Для Ruby есть большое количество различных библиотек и расширений. Доступные в Gentoo Linux можно посмотреть с помощью
$ emerge -s ruby
Кстати, если вы регулярно обновляете Portage, то, возможно, mod_ruby можно уже установить через "emerge mod_ruby". В моей версии его статус еще Masked.
mod_ruby
modruby.net — сайт Apache модуля mod_ruby. Установка крайне проста:
$ tar -xzf mod_ruby-1.0.7.tar.gz
$ cd mod_ruby-1.0.7
$./configure.rb --with-apxs=/path/to/apxs
$ make
$ make install
Затем редактируем файл настроек apache (httpd.conf или apache.conf) и добавляем в него следующее:
# загрузка модуля mod_ruby
LoadModule ruby_module /usr/lib/apache/mod_ruby.so
AddModule mod_ruby.c
# Настройка обработчиков для файлов *.rbx
<IfModule mod_ruby.c>
RubyRequire apache/ruby-run
<Location /ruby>
SetHandler ruby-object
RubyHandler Apache::RubyRun.instance
Options +ExecCGI
</Location>
<Files *.rbx>
SetHandler ruby-object
RubyHandler Apache::RubyRun.instance
Options +ExecCGI
</Files>
</IfModule>
Примечание: это немного расходится с примером, указанным в документации, но именно так у меня получилось запустить Ruby скрипты.
Для тестирования создайте в директории public_html файл hello.rbx вида
puts "Hello!"
Обращаемся к нему по ссылке (у вас может быть другая ссылка) "http://localhost/~alex/hello.rbx". Если отработало, значит все получилось. Если нет, обращайтесь, поможем, чем сможем.
Установка книги "Programming Ruby: The Pragmatic Programmers' Guide"
Авторы: Dave Thomas и Andrew Hunt
$ emerge dev-ruby/programming-ruby
Примечание: новая редакция книги находится на сайте phrogz.net
MySQL расширение для Ruby
$ emerge dev-ruby/mysql-ruby
Для установки в Windows достаточно скачать один из вариантов Ruby с http://ftp.ruby-lang.org/pub/ruby/binaries/ (я выбрал mswin32/ruby-1.8.1-20040402-i386-mswin32.zip). Далее распаковать и проставить правильно пути к директориям. Можно также воспользоваться пакетом автоматической установки RubyInstaller
Определить правильность установки поможет команда
C: \>ruby --help
if 1 > b
#…
elsif a == 1
#…
else
#…
end
if 1 > b then 1 else 2 end
case node.type
when node.DocumentNode then
#…
else
#…
end
a = 1 if a > 1
i = 1
while i < 10
puts i += 1
end
i = 1
puts i += 1 while i < 10
Callback — это общее название, которым обозначают механизм задание части кода, который выполняется вызываемым методом. В различных технологиях используются указатели на функции (C/C++), динамический вызов функций (PHP/Perl). В Ruby задание callback можно осуществлять с помощью блоков кода. Блок передается за методом в волнистых скобках или в виде do… end. В начале блока идет перечисление параметров, с которыми он вызывается. Например |i| обозначает, что блоку передается один параметр и внутри этого блока он присваивается переменной i.
10.times { puts "I will use Google before asking questions\n" }
1.upto(3) { |i| puts "Iteration #{i}\n" }
10.downto(1) {|i| puts i}
(1..10). each {|i| puts i}
0.step(100, 10) {|i| puts i}
['January 1', 'February 23', 'March 8'].each { |holiday| p holiday }
%w{this is a test}.each{|i| p i}
Регион используется для организации проверок и циклов. Он определяется начальным и конечным значением.
0..1 # 0, 1
0…4 # 0, 1, 2, 3
'a'..'f' # 'a', 'b', 'c', 'd', 'e', 'f'
(0..4).to_a # Result: [0, 1, 2, 3, 4]
(0..9).include?(5) или (0..9) === 5
(0..9).min
(0..9).max
str = 'asdf #{10**5}' # без вычисления
str = "asdf #{10**5}" # с вычислением, str = 'asdf 100000'
"asdf".length
"asdf".index("s")
"asdf g h jkl;".split(" ")
"10 11 12".scan(/\d+/)
'Ruby??'.sub(/\?/, '!') > Ruby!?
'Ruby??'.sub(/(\?)\?/, '\1!') > Ruby?!
'Ruby??'.gsub(/\?/, '!') > Ruby!!
"10".to_i
'-=' * 10 # -=-=-=-=-=-=-=-=-=-=
"asdf" = %Q/asdf/
'asdf' = %q/asdf/ (вместо / может использоваться любой символ, например ~ -> %q~asdf~)
str = <<END
Некоторый текст
END
Приятной особенностью Ruby является встроенная поддержка больших чисел в вычислениях. Благодаря чему можно легко оперировать большими целыми числами. Например, можно легко вычислить, сколько зерен должен был отдать правитель изобретателю шахмат (по легенде, изобретатель попросил правителя положить на первую клетку два зернышка, на вторую 22 и так до последней, на которой было 264 зерен):
s, t = 2, 0
(1..64). each { t += s *= 2}
puts t # Результат: 73786976294838206460
Некоторые интересные возможности:
-10.abs — модуль
0xAAFF — hex
0b10010 — binary
?z — код символа
?\C-a — код Ctrl+a (?a & 0x9f)
?\M-a — код Alt+a (?a | 0x80)
?\C-\M-a — код Ctrl+Alt+a
Float object соответствует системному double
без модификатора — видима в текущем блоке и в подблоках
$ — глобальная
@ — переменная класса
@@ — статическая переменная класса
Первая буква заглавная — константа или имя класса
Нумерация массивов начинается с нулевого элемента. Отрицательный индекс — обратная нумерация. В отличие от PHP, массив — это последовательность из N элементов. Поэтому если a = [1, 2] и задается значение a[4] = 10, то в результате получаем массив [1, 2, nil, nil, 10].
a = []
a = Array.new
a = ["asdf", "g", "h", "jkl;"]
a = %w{Ruby is a best language}
a = "Ruby is a best language".split(" ")
a = [1, 2, 3, 4, 5]
a[2, 2] # [3, 4]
a[1..3] # [2, 3, 4]
a[1…3] # [2, 3]
a = [1, 2, 3, 4, 5]
a[1,2] = [] # a = [1, 4, 5]
a[0,1] = 3 # a = [3, 4, 5]
a[0,1] = [1, 2, 3] # a = [1, 2, 3, 4, 5]
a.length # длина массива
a.shift # "вынуть" (вернуть и удалить) первый элемент
a.pop # "вынуть" последний элемент
h = {'hash' => '{}', 'array' => '[]'}
h['hash'] = "{'key' => 'value'}"
р.find { |item| item.name == 'hash' }
r = Regexp.new('/a(b)c/')
r = /a(b)c/
r = %r{a(b)c}
str = "Ruby is OOP language"
puts $1 if str =~ /(OOP)/
puts str unless str!~ /OOP/
$1..$9 — найденные группы
$& — текст, найденный по шаблону
$` — текст до шаблона
$' — текст после шаблона
m = /(a)(b)(c)/.match('abcdefg')
m[0] > $&
m[1] > $1
…
m.pre_match > $`
m.post_match > $'
def doSomething
yield
end
doSomething { puts "It is a something:-)" }
def doSomethingWithParams
yield 1
end
doSomethingWithParams do
|i| puts "It is a something with #{i}:-)"
end
if block_given?
yield
end
def doSomething(&callback)
callback.call
end
doSomething { print "This is a something" }
def doSomething(callback)
callback.call
end
doSomething proc { print "This is a something" }
p = proc {|i| print i}
(1..10).each &p
puts — выводит строку
print — выводит строку без \n в конце
printf — аналогичен C printf
gets — помещает результат ввода строки данных в переменную $_ и возвращает строку
def myMethod(value = "Default")
def myMethod(*args)
myMethod(*[1, 2])
myMethod('param2' => 1, 'param1' => 2)
конструктор
def initialize
MyClass.new
myClass.dup
myClass.freeze
myClass.inspect
myClass.to_s
super
attr_reader: documentUri
def documentUri=(documentUri)
@documentUri = documentUri
end
@@users
class Page
def Page.addHit
@@hit += 1
end
end
[public|protected|private]
def…
def…
или
private: myMethod1,myMethod2
private_class_method: new
class NodeList
def +(newNode)
#…
end
end
begin
#…
rescue ExceptionClass
#…
rescue ExceptionClass => e
#…
ensure
#…
end
аналогичен Java коду:
try {
//…
} catch (ExceptionClass) {
//…
} catch (ExceptionClass e) {
//…
} finaly {
//…
}
$!
raise
retry
catch (:exit) do
1..10.each do |i|
1..10.each do |j|
throw: exit if a[i, j] = 0
end
end
end
module MyFunctions
def…
end
class MyClass
include MyFunctions
end
`date`
class Fixnum
alias oldPlus +
def +(value)
oldPlus(value)
puts 'Plus called'
end
end
a, b = b, a
Написав этот мини курс я попробовал составить к нему оглавление. Примерно оценив количество заголовков я пришел к выводу, что вручную это будет очень непродуктивно — проще написать небольшую программу на Ruby, которая составляет оглавление из заголовков и заменяет строку CREATE_TOC на созданное оглавление
File: createToc.rb
#!/usr/bin/ruby — w
# createToc.rb
# Программа составляет оглавление, выводит его вместо CREATE_TOC
# и добавляет якоря вида <a name="sN"></a> к заголовкам
# задаем строковую переменную — идентификатор оглавления
tocToken = 'CREATE_TOC'
# определяем массив, в котором будет строиться оглавление
toc = []
# результат
output = ''
# для всех строк входного потока
ARGF.each do |line|
# если строка содержит заголовок 3го, 4го или 5го уровня
if line =~ %r{<h([3–5])>([^<]+)</h[3–5]>}
# определить номер якоря
anchorId = toc.length.to_s
# и добавить в массив toc пункт оглавления
toc << (' ' * ($1.to_i - 3) * 2) + "<a href=\"#a#{anchorId}\">#{$2}</a><br>\n"
# к строке output добавить заголовок с добавленым якорем
output << line.sub('>', "><a name=\"a#{anchorId}\"></a>")
else
output << line
end
end
# выводим результат, в котором tocToken заменяется на оглавление
puts output.sub(tocToken, '<div class="TOC">' + toc.join + '</div>')
К сожалению, эта программа не учитывает, что оглавление и якоря могут уже быть добавлены. Если добавите такую возможность к программе, присылайте патч.
Использование программы:
$ createToc.rb < article.html > new_article.html
В продолжении планируется:
● многопоточность Ruby
● сравнение скорости программ на Ruby и PHP
● Ruby и MySQL
Статья взята с сайта OpenNet.
10.05.2004