14.8.4. Вычисление свободного места на диске
Пусть нужно узнать, сколько байтов свободно на некотором устройстве. В следующем примере это делается по-простому, путем запуска системной утилиты:
def freespace(device='.')
lines = %x(df -k #{device}).split('
')
n = lines.last.split[1].to_i * 1024
end
puts freespace('/tmp') # 16772204544
Эту задачу лучше решать, обернув метод statfs
в расширение Ruby. Такие попытки в прошлом предпринимались, но, похоже, проект умер.
Для Windows имеется несколько более элегантное решение (предложено Дэниэлем Бергером):
require 'Win32API'
GetDiskFreeSpaceEx = Win32API.new('kernel32', 'GetDiskFreeSpaceEx',
'PPPP', 'I')
def freespace(dir='.')
total_bytes = [0].pack('Q')
total_free = [0].pack('Q')
GetDiskFreeSpaceEx.call(dir, 0, total_bytes, total_free)
total_bytes = total_bytes.unpack('Q').first
total_free = total_free.unpack('Q').first
end
puts freespace('С:') # 5340389376
Этот код должен работать во всех вариантах Windows.
14.9. Различные сценарии
Приведем еще несколько примеров. Не претендуя на оригинальность, мы отнесли их к категории «разное».
14.9.1. Ruby в виде одного файла
Иногда нужно быстро или временно установить Ruby. Или даже включить Ruby в состав собственной программы, поставляемой в виде одного исполняемого файла.
Мы уже познакомились с «моментальным инсталлятором» Ruby для Windows. Существуют планы (пока еще не оформившиеся) создать подобный инсталлятор для Linux и Mac OS X.
Эрик Веенстра (Erik Veenstra) недавно добился значительных успехов в создании пакетов, включающих как Ruby, так и написанные на нем приложения. Он автор пакетов AllInOneRuby, Tar2RubyScript и RubyScript2Exe (все они есть на его сайте http://www.erikveen.dds.nl).
AllInOneRuby — это дистрибутив Ruby в одном файле. В пакет входят интерпретатор Ruby, системные классы и стандартные библиотеки, упакованные в единый архив, который легко перемещать или копировать. Например, его можно записать на USB-диск, носить в кармане и «установить» на любую машину за считанные секунды. Работает AllInOneRuby на платформах Windows и Linux; имеется также экспериментальная поддержка для Mac OS X.
Что такое Tar2RubyScript, следует из самого названия. Программа получает на входе дерево каталогов и создает самораспаковывающийся архив, включающий написанную на Ruby программу и архив в формате tar. Идея та же, что у JAR-файлов в языке Java. Запускаемый сценарий должен называться init.rb
; если сохраняется библиотека, а не автономное приложение, этот файл можно опустить.
Название RubyScript2Exe, наверное, не вполне удачно. Программа действительно преобразует написанное на Ruby приложение в один двоичный файл, однако работает она не только в Windows, но и в Linux и Mac OS X. Можете называть ее компилятором, хотя в действительности она им, конечно, не является. Она собирает файлы, являющиеся частью установленного дистрибутива Ruby на вашей машине, поэтому не нуждается в кросс-компиляции (даже если бы такая возможность имелась). Имейте в виду, что исполняемый файл «усечен» в том смысле, что неиспользуемые библиотеки Ruby в него не включаются.
Архив, созданный программой Tar2RubyScript, можно запустить на любой машине, где установлен Ruby (и программы, которые необходимы самому приложению). RubyScript2Exe не имеет такого ограничения, поскольку включает (наряду с вашим приложением) интерпретатор Ruby, всю среду исполнения и все необходимые внешние программы. Можете использовать эти инструменты вместе или порознь.
14.9.2. Подача входных данных Ruby по конвейеру
Поскольку интерпретатор Ruby — это однопроходный транслятор, можно подать ему на вход некий код и выполнить его. Это может оказаться полезным, когда обстоятельства вынуждают вас работать на традиционном языке сценариев, но для каких-то сложных задач вы хотите применить Ruby.
В листинге 14.6 представлен bash-сценарий, который вызывает Ruby (посредством вложенного документа) для вычисления интервала в секундах между двумя моментами времени. Ruby-программа печатает на стандартный вывод одно значение, которое перехватывается вызывающим сценарием.
#!/usr/bin/bash
# Для вычисления разницы в секундах между двумя моментами временами
# bash вызывает Ruby...
export time1='2007-04-02 15:56:12'
export time2='2007-12-08 12:03:19'
cat <<EOF | ruby | read elapsed
require 'parsedate'
time1 = ENV['time1']