KnigaRead.com/
KnigaRead.com » Компьютеры и Интернет » Программирование » Хэл Фултон - Программирование на языке Ruby

Хэл Фултон - Программирование на языке Ruby

На нашем сайте KnigaRead.com Вы можете абсолютно бесплатно читать книгу онлайн Хэл Фултон, "Программирование на языке Ruby" бесплатно, без регистрации.
Перейти на страницу:

О системе RubyGems можно еще многое сказать; к тому же она постоянно развивается. Самая актуальная информация представлена на сайте http://rubygems.rubyforge.org.

21.2. Программа Rake

Утилита rake — это вариация на тему давно известной в UNIX программы make. Но вместо «странного» синтаксиса make, который все мы знаем и терпеть не можем, в rake используется код на самом Ruby. Программу написал Джим Вайрих (Jim Weirich); это первый, насколько мне известно, пример формальной реализации языка DSL (domain-specific language — язык предметной области) на Ruby.

Есть два варианта написания названия: Rake и rake. Первый - это название инструмента, второй — имя самого исполняемого файла. На мой взгляд, различие несущественное.

Нет сомнения, что на дизайн Rake оказала большое влияние программа make, так что терминология одна и та же. Как и раньше, мы говорим о целях, действиях, зависимостях и правилах.

Применениям Rake нет числа. Вы можете пользоваться ею для сборки проектов, написанных на С, C++ или Java (или на любом другом языке). Годится она и для генерирования документации с помощью RDoc, развертывания программ, обновления проекта на сайте Ruby Forge и множества других задач.

Неудивительно, что на вход Rake подается командный файл (rake-файл), который по умолчанию называется rakefile или Rakefile. Если вы хотите назвать его иначе, укажите имя с помощью флага -f или --rakefile:

$ rake           # Искать сначала 'rakefile', потом 'Rakefile'.

$ rake -f myfile # Использовать файл с именем 'myfile'.

Основная «единица работы» в Rake — задание; именуются задания посредством символов Ruby. Предполагается, что в каждом rake-файле есть задание по умолчанию :default — оно будет выполняться, если явно не указано другое имя.

$ rake        # Выполнить задание по умолчанию.

$ rake mytask # Выполнить задание с именем 'mytask'.

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

task :mytask do

 # ...

end

Содержимое блока в примере выше опущено. То, что в нем находится, называется действием.

В действии можно выполнять произвольный код на Ruby. Для типичных операций предусмотрены готовые методы. Так, метод sh (название которого напоминает об интерпретаторе команд в UNIX) запускает системную команду.

Методы cp, mv и rm предназначены соответственно для копирования, перемещения и удаления файлов. (Как и make, Rake беззастенчиво выдает свое происхождение от UNIX.) Есть и другие подобные команды; дополнительную информацию вы найдете в онлайновой документации на сайте http://docs.rubyrake.org.

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

task(:mytask) { do_something }

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

myprog.с

sub1.с

sub1.h

sub2.с

sub2.h

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

Начнем с метода file, который определяет зависимости файлов:

file "myprog.о" => ["myprog.с"]

file "sub1.о" => ["sub1.с", "sub1.h"]

file "sub2.o" => ["sub2.c", "sub2.h"]

file "myprog" => ["sub1.o", "sub2.o"]

Отметим, что метод file принимает хэш, который ассоциирует имя файла с массивом имен файлов, от которых он зависит.

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

file "myprog.о" => ["myprog.с"] do

 sh "сс -с -о myprog.о myprog.с"

end


file "sub1.o" => ["sub1.с", "sub1.h"] do

 sh "сс -с -o sub1.o sub1.c"

end


file "sub2.o" => ["sub2.c", "sub2.h"] do

 sh "сс -с -o sub2.o sub2.c"

end


file "myprog" => ["sub1.o", "sub2.o"] do

 sh "cc -o myprog myprog.о sub1.o sub2.o"

end

Здесь имеется некоторое дублирование, но от него можно избавиться. В Rake есть специальный механизм, который называется FileList; он понимает метасимволы (шаблоны) и позволяет работать сразу с несколькими файлами. В данном случае поместим все файлы с расширением .c в список SRC. Константа типа FileList ведет себя как массив:

SRC = FileList["*.с"]

Теперь можно определить действия в цикле, как показано ниже. И обратите внимание, что зависимости здесь не упоминаются — Rake самостоятельно учтет эту информацию, если она была задана в другом месте.

SRC.each do |src|

 obj = src.sub(/.c$/,".о")

 file(obj) { sh "cc -с -o #{obj} #{src}" }

end

Однако проще пользоваться правилами. Это еще один механизм Rake, естественно, позаимствованный у make:

rule '.о' => '.с' do |target|

 sh "сс -с -о #{target.name} #{target.source}"

end

Тут мы наблюдаем небольшое волшебство. Rake устанавливает атрибут source, подставляя расширение имени файла из хэша (в данном случае .o заменяется на .c).

Продолжим сеанс магии. Если затребовать библиотеку rake/clean, то появляются константы clean и clobber (первоначально пустые) и задания :clean и :clobber. По сложившейся традиции clean удаляет временные файлы, a clobber — еще и собранный исполняемый файл.

Для этих напоминающих массив констант определен метод include, принимающий маску имени файлов; это неявное использование механизма FileList.

Теперь наш rake-файл принимает такой вид:

require 'rake/clean'


CLEAN.include("*.о")

CLOBBER.include("myprog")


SRC = FileList['*.с']

OBJ = SRC.ext('o')


rule '.o' => '.c' do |t|

 sh "cc -с -o #{t.name} #{t.source}"

end


file "hello" => OBJ do

 sh "cc -o hello #{OBJ}"

end


file "myprog.o" => ["myprog.c"]

file "sub1.o" => ["sub1.c", "sub1.h"]

file "sub2.o" => ["sub2.c", "sub2.h"]


task :default => ["myprog"]

Обратите внимание, что мы не задавали задания «clean» и «clobber» явно. Кроме того, отметим что «clobber» неявно включает операцию «clean». И наконец, мы определили задание default для удобства запуска rake-файла; теперь можно не указывать явно имя задания, осуществляющего компиляцию и сборку.

У программы rake есть несколько параметров командной строки. Иногда желательно протестировать rake-файл, не выполняя никаких (потенциально опасных) операций; для этого служит флаг -n или --dry-run. Флаг -T выводит список всех целей в rake-файле. Имеются также флаги, управляющие поиском библиотек, трассировкой, протоколированием и т.д.

Программа Rake сложнее, чем я описал в этом разделе (особенно это касается правил). И она продолжает развиваться. Как обычно, самую свежую информацию ищите в онлайновой документации (http://docs.rubyrake.org/).

21.3. Оболочка irb

Утилита irb (интерактивный Ruby) уже много лет как включена в дистрибутив Ruby. Можно считать, что это «испытательный стенд» или «площадка для игр», на которой вы опробуете новые приемы и идеи.

Работать с irb просто. После запуска вы получаете приглашение и можете вводить произвольные выражения Ruby. Выражение вычисляется, и печатается результат. Вот пример короткого сеанса:

$ irb

irb(main):001:0> "cell" + "о"

=> "cello"

irb(main):002:0> 3*79

=> 237

irb(main):003:0> Dir.entries(".").size

=> 17

irb(main):004:0> rand

=> 0.850757389880155

irb(main):005:0> rand

=> 0.679879756672551

irb(main):006:0> defined? Foo

=> nil

irb(main):007:0> defined? Object

=> "constant"

irb(main):008:0> quit

$

Конечно, это больше, чем калькулятор. При желании можно ввести произвольный код на Ruby:

[ [email protected] ch21]$ irb

irb(main):001:0> require 'mathn'

=> true

irb(main):002:0> gen = Prime.new

=> #

При установке флага -r выполняется require, поэтому можно включать код из внешнего файла. Предположим, что вы написали такой файл:

# File: foo.rb

class MyClass


 attr_accessor :alpha, :beta


 def initialize(a, b)

  @alpha, @beta = a, b

 end


end


obj1 = MyClass.new(23,34)

obj2 = MyClass.new("abc","xyz")

Тогда можно сделать следующее:

Перейти на страницу:
Прокомментировать
Подтвердите что вы не робот:*