Аз, Буки, Веди! Читаем конфиги

Все мы рано или поздно читаем конфиги. Даже если начинаем с прописанных где-то в начале тела программы статических переменных, содержащих что-нибудь неизменное наподобие логина и пароля и даже если потом в силу давления обстоятельств, требующих от нас максимальной гибкости, начинаем использовать ключи командной строки (если это вообще возможно) — вот ну точно вам говорю, рано или поздно от чтения конфига всё равно никуда не деться.

Как-то и мне понадобилось нечто подобное… а потом ещё миллион раз :) И приступая к изучению нового для себя языка программирования, каковым для меня пока является и Crystal, я неизменно возвращаюсь к одному и тому же вводному вопросу: а как бы здесь прочитать конфиг в моём любимом простейшем BASH-совместимом формате (том, который легко подключается source'м из BASH-скрииптов): переменная=«зна 'че' ние» или переменная='зна «че» ние' или даже переменная=значение?

Для Crystal я тоже написал подобный пример. Вот он:


begin
        raise "Hey! You must specify file name as a first parameter" if ARGV.size==0
        rows=File.read_lines(ARGV[0])
        rows.reject! { |line| line =~ /^\s*(?:#.*)?$/ }
        conf=rows.map{ |line|
                if
                 line.match(/^([^#=\s]+)\s*=\s*(?:(?<Q>["'`])((?:(?!\k<Q>|\\).|\\.)*)\k<Q>)(?:\s+(?:#.*)?)?$/)
                        [$1,$3]
                elsif line.match(/^([^#=\s]+)\s*=\s*([^#\s"']+)(?:\s+(?:#.*)?)?/)
                        [$1,$2]
                else
                        raise "invalid-formatted config line: #{line}"
                end
        }.to_h

        p conf
rescue ex
        puts ex.message
        exit(1)
end


Поясню:

в секции rescuе обрабатываются любые возникающие исключения, в числе которых и ошибка открытия файла

ARGV[0] содержит первую опцию командной строки

Метод reject! изменяет список, являющийся экземпляром класса Array, так, чтобы в нём не осталось пустых строк и комментариев.

Метод map на том же самом rows возвращает «список списков», т.е. список, состоящий из элементов, каждый из которых представляет собой этакий крохотулечный «списочек» всего из 2-х элементов. В первый из элементов каждого такого «списочка» благодаря «усилиям» оператора match и скобкам в регулярном выражении — попадает переменная из конфига, а во второй элемент (благодаря всё тем же действующим лицам) — значение для переменной.

to_h преобразует наш список списков… во что бы вы думали? Да, точно, в Hash-массив, в котором каждый «списочек» магическим образом превращается в пару ключ-значение.

«p conf» — это на самом деле такой отладочный «хак» языка Crystal: инструкция p попросту выводит «дамп» любого переданного ей объекта. В данном случае — дамп Hash'а.

В реальной программе вы бы конечно использовали conf неким полезным образом. Ну а конфиг с паролями у вас конечно же защищён правами доступа «rw-------», оно же 600? Вот и молодцы!

Сохраняйте код в файл, запускайте «crystal your_funny_code.cr имя_файла» (обратите внимание на собственное расширение для языка Crystal) — и, как говорят, enjoy!

А получить удовольствие есть от чего: ведь вы написали настоящий компилируемый код — и обошлись без груды закорючек, спецификаций типов и возни с выделением/освобождением памяти :)

0 комментариев