Простые приложения на Ruby
Простые приложения на Ruby
Ruby удобен для коротких скриптов — читаемый синтаксис, богатая стандартная библиотека (File, JSON, Net::HTTP, SecureRandom). Ниже — типовые задачи "первого уровня" без гемов и без Rails: каждый пример можно сохранить в .rb и запустить через ruby script.rb.
Рекомендуемый порядок: после первой программы и типов, до Rails.
Как запускать примеры из главы
- Скопируйте код раздела в отдельный файл (имя — в Как запустить у примера).
- В терминале перейдите в каталог с файлом:
cd путь/к/каталогу. - Выполните:
ruby имя_файла.rb.
Проверка интерпретатора: ruby -v (нужен Ruby 3.x).
Генератор паролей
Как запустить
- Файл:
password.rb - Команда:
ruby password.rb - Нужно: Ruby 3.x, stdlib (
securerandom). - Результат: в терминале одна строка — пароль (~20 символов).
require 'securerandom'
def generate_password(length: 16, digits: true, symbols: true)
pool = [*'a'..'z', *'A'..'Z']
pool.concat(('0'..'9').to_a) if digits
pool.concat(%w[! @ # $ % ^ & *]) if symbols
Array.new(length) { pool.sample(random: SecureRandom) }.join
end
puts generate_password(length: 20)
Разбор:
require 'securerandom'подключает модуль стандартной библиотеки для криптостойкой случайности, что важно для паролей.def generate_password(...)объявляет метод с именованными аргументами, поэтому при вызове сразу видно смысл каждого параметра.pool = [*'a'..'z', *'A'..'Z']собирает базовый набор символов через диапазоны и оператор распаковки*.pool.concat(...) if digitsиif symbolsрасширяют набор символов по флагам, чтобы поведение функции было гибким.Array.new(length) { pool.sample(random: SecureRandom) }создаёт массив изlengthсимволов и каждый раз берёт случайный элемент из пула..joinсклеивает массив символов в готовую строку-пароль.puts generate_password(length: 20)печатает результат в stdout и демонстрирует, как переопределяется длина по умолчанию.
Сортировщик текстового файла
Как запустить
- Файл:
sort_lines.rb - Подготовка: рядом положите
input.txt(несколько строк текста). - Команда:
ruby sort_lines.rb— в конце файла раскомментируйте или добавьтеsort_lines('input.txt', 'sorted.txt'). - Результат: файл
sorted.txtи сообщениеСтрок: N → sorted.txt.
def sort_lines(input_path, output_path)
lines = File.readlines(input_path, encoding: 'UTF-8')
.map(&:strip)
.reject(&:empty?)
sorted = lines.sort_by(&:downcase)
File.write(output_path, sorted.join("\n") + "\n", encoding: 'UTF-8')
puts "Строк: #{sorted.size} → #{output_path}"
rescue Errno::ENOENT
warn "Файл не найден: #{input_path}"
end
sort_lines('input.txt', 'sorted.txt')
Разбор:
File.readlines(..., encoding: 'UTF-8')читает файл построчно и сразу фиксирует кодировку, чтобы избежать ошибок с кириллицей..map(&:strip)удаляет пробелы и перевод строки по краям каждой строки..reject(&:empty?)убирает пустые строки из дальнейшей обработки.sort_by(&:downcase)сортирует без учёта регистра, приводя строки к нижнему регистру для сравнения.File.write(..., sorted.join("\n") + "\n")записывает результат обратно в файл и добавляет финальный перевод строки.rescue Errno::ENOENTперехватывает типичную ошибку "файл не найден" и выводит понятное сообщение черезwarn.
Консольный калькулятор
Как запустить
- Файл:
calc.rb - Команда:
ruby calc.rb - Нужно: интерактивный терминал (ввод с клавиатуры).
- Результат: запросы
Операция, чисел; ответ= …; выход —qна запрос операции.
Код ITЗагрузка примера кода…
Разбор:
case opвыбирает ветку вычисления по знаку операции и делает код компактным.- В ветке деления проверка
b.zero?защищает от недопустимой операции и выбрасываетArgumentError. - В
elseтоже выбрасываетсяArgumentError, если пользователь ввёл неподдерживаемую операцию. loop do ... endорганизует циклический ввод, аbreak if op == 'q'завершает программу по команде выхода.gets&.stripиспользует safe-navigation&., чтобы не упасть, если ввод вернулnil.Float(gets.strip) rescue (...)пытается преобразовать ввод в число и мягко возвращает цикл к следующей итерации при ошибке.- Блок
begin/rescueвокругcalculateперехватывает ошибки бизнес-логики и показывает человеку точную причину.
Трекер задач в JSON
Как запустить
- Файл:
tasks.rb - Команда:
ruby tasks.rb - Нужно: stdlib
json; прав на запись в текущий каталог. - Результат: создаётся
tasks.json, в консоли — список задач с[ ]/[x].
Код ITЗагрузка примера кода…
Разбор:
DB = 'tasks.json'задаёт единое место хранения, чтобы все функции работали с одним и тем же файлом.load_tasksпроверяет наличие файла и безопасно возвращает пустой массив, если данных пока нет.JSON.parse(...)загружает задачи как массив хэшей; ключи после парсинга строковые ('id','title','done').save_tasksпишет JSON в человекочитаемом формате черезJSON.pretty_generate, что удобно для отладки.add_taskсоздаёт новую задачу и сразу сохраняет весь список обратно в файл.toggle(id)ищет задачу поid, инвертирует флагdoneи сохраняет результат.- Тернарный оператор в
putsпревращает булево поле в понятный чекбокс[x]или[ ].
Простой HTTP-сервер (WEBrick)
Как запустить
- Файлы:
server.rb(сервер),client.rb(клиент — второй блок кода). - Терминал 1:
ruby server.rb— процесс слушает127.0.0.1:4567. - Терминал 2:
ruby client.rb— в консоли JSON, например{"ok"=>true, "time"=>"..."}. - Остановка сервера:
Ctrl+C. - Нужно: stdlib
webrick,net/http,json.
require 'webrick'
server = WEBrick::HTTPServer.new(Port: 4567, BindAddress: '127.0.0.1')
server.mount_proc '/' do |_req, res|
res['Content-Type'] = 'application/json'
res.body = { ok: true, time: Time.now.iso8601 }.to_json
end
trap('INT') { server.shutdown }
server.start
Разбор:
WEBrick::HTTPServer.new(...)поднимает встроенный HTTP-сервер на локальном адресе и порту.server.mount_proc '/'регистрирует обработчик для корневого пути.res['Content-Type'] = 'application/json'явно указывает формат ответа клиенту.res.body = {...}.to_jsonформирует JSON-ответ как строку.trap('INT') { server.shutdown }добавляет корректное завершение поCtrl+C.server.startзапускает цикл обработки запросов и держит процесс в активном состоянии.
Клиент на stdlib:
require 'net/http'
require 'json'
uri = URI('http://127.0.0.1:4567/')
json = JSON.parse(Net::HTTP.get(uri))
puts json
Разбор:
URI(...)разбирает строку URL в объект с хостом, портом и путём.Net::HTTP.get(uri)выполняет простой GET-запрос и возвращает тело ответа строкой.JSON.parse(...)преобразует JSON-строку в хэш Ruby.puts jsonпечатает структуру данных и помогает проверить, что API действительно отвечает.
Сканер каталога
Как запустить
- Файл:
scan_dir.rb - Команда:
ruby scan_dir.rb(из каталога, который хотите обойти). - Результат: в консоли хеш
{ files: N, bytes: M }для.rbи.mdв текущей папке рекурсивно.
Код ITЗагрузка примера кода…
Разбор:
Find.find(root)рекурсивно обходит дерево каталогов от заданной точки входа.next unless File.file?(path)отфильтровывает директории и оставляет только файлы.File.extname(path)достаёт расширение файла для фильтрации по интересующим типам.- Проверка
extensions.any? && !extensions.include?(ext)позволяет использовать как фильтр, так и режим "все файлы". stats[:files]иstats[:bytes]аккумулируют количество файлов и суммарный размер.- Возврат
statsделает функцию переиспользуемой: её можно вызывать в других скриптах.
Резервное копирование файла
Как запустить
- Файл:
backup.rb - Подготовка: любой файл для копии, например
notes.txt. - Команда: в конце скрипта вызовите
puts backup('notes.txt'), затемruby backup.rb. - Результат: копия в папке
backups/с префиксом даты в имени; путь печатается в stdout.
require 'fileutils'
def backup(source, backup_dir = 'backups')
FileUtils.mkdir_p(backup_dir)
stamp = Time.now.strftime('%Y%m%d-%H%M%S')
dest = File.join(backup_dir, "#{stamp}_#{File.basename(source)}")
FileUtils.cp(source, dest)
dest
end
Разбор:
FileUtils.mkdir_p(backup_dir)создаёт каталог для бэкапов и не падает, если он уже существует.Time.now.strftime(...)формирует временную метку, чтобы копии не перезаписывали друг друга.File.basename(source)оставляет только имя файла без пути и безопасно встраивает его в имя копии.File.join(...)собирает путь платформонезависимо.FileUtils.cp(source, dest)копирует исходный файл в каталог бэкапов.- Возврат
destпозволяет вызвать функцию из другого кода и получить путь к созданной копии.
Проверка доступности URL
Как запустить
- Файл:
check_url.rb - Команда:
ruby check_url.rb - Нужно: доступ в интернет для
https://example.com. - Результат: две строки с хешами
:url,:code,:ok(для несуществующего домена —:ok=>false).
Код ITЗагрузка примера кода…
Разбор:
URI(url)разбирает адрес и отдаёт готовые поляhost,port,scheme.Net::HTTP.new(uri.host, uri.port)подготавливает HTTP-клиент под конкретный хост.http.use_ssl = (uri.scheme == 'https')автоматически включает TLS для HTTPS.open_timeoutиread_timeoutограничивают время ожидания и защищают от подвисаний.request_head(...)отправляет HEAD-запрос, чтобы проверить доступность без загрузки тела.- Возвращается структурированный хэш с
:codeи:ok, что удобно для последующей автоматической обработки. rescue StandardErrorпревращает сетевые исключения в понятный результат с полем:error.
Характерный пример для Ruby — блоки и Enumerable
Как запустить
- Файл:
word_stats.rb - Команда:
ruby word_stats.rb - Результат: три строки — всего слов, уникальных, топ-3 по частоте.
text = 'Ruby учит думать объектами и блоками'
words = text.split(/\s+/)
stats = words
.map(&:downcase)
.group_by(&:itself)
.transform_values(&:size)
puts "Всего слов: #{words.size}"
puts "Уникальных: #{stats.size}"
puts stats.sort_by { |_, c| -c }.first(3).map { |w, c| "#{w}: #{c}" }
Разбор:
split(/\s+/)разбивает строку на слова по одному или нескольким пробельным символам.map(&:downcase)нормализует регистр, чтобыRubyиrubyсчитались одним словом.group_by(&:itself)группирует одинаковые слова в хэш видаслово => [вхождения].transform_values(&:size)превращает массивы в счётчики частоты.sort_by { |_, c| -c }сортирует по убыванию частоты.first(3)выбирает только топ-3 элемента.map { |w, c| "#{w}: #{c}" }переводит пары ключ-значение в удобные строки для вывода.
Дополнительные мини-приложения
Парсинг CSV-строки в консольной утилите
Как запустить
- Файл:
parse_csv_line.rb - Команда:
ruby parse_csv_line.rb - Результат: хэш с полями пользователя и числом
age.
line = "42, Ada Lovelace, ada@example.com, 28"
id, name, email, age = line.split(",").map(&:strip)
user = {
id: id.to_i,
name: name,
email: email,
age: age.to_i
}
p user
Разбор:
split(",")разбивает CSV-строку на колонки по запятой.map(&:strip)убирает пробелы вокруг значений.- Параллельное присваивание раскладывает список колонок в отдельные переменные.
to_iявно приводит числовые поля к целому типу.- Сниппет показывает базовую ETL-логику для CLI-скриптов без внешних библиотек.
Лог-фильтр ошибок из текстового файла
Как запустить
- Файл:
filter_errors.rb - Подготовка: создать
app.logс несколькими строками. - Команда:
ruby filter_errors.rb - Результат: печатает только строки, где есть
ERROR.
File.foreach("app.log", encoding: "UTF-8") do |line|
next unless line.include?("ERROR")
puts line.strip
end
Разбор:
File.foreachчитает файл построчно и не грузит всё содержимое в память сразу.next unless ...быстро пропускает неинтересные строки.include?("ERROR")— простая и быстрая фильтрация по подстроке.line.stripубирает перенос строки и лишние пробелы перед выводом.- Это минималистичный шаблон для первых утилит мониторинга логов.
См. также: первая программа · ООП · Rails · Sinatra и гемы
Базовый разбор HTTP и HTTPS находится в отдельной статье — HTTP как основа веб-интеграций.