Приложения командной строки могут быть не такими распространенными, как раньше, но программисты используют их почти каждый день. Даже если вы новичок в ruby, вы, вероятно, использовали IRB и, возможно, немного мерзавца (а если еще не сделали, то сделаете!) «Опции», «Флаги опций» или просто «Флаги» ускоряют взаимодействие с этими утилитами. , проще и мощнее, и Руби развлекается.
Когда большинство людей думают о ruby, они думают о веб-приложениях и скриптах. Это правда, что ruby хорош в обеих этих вещах, но вы можете использовать его и для создания утилит командной строки, вместо того, чтобы использовать что-то вроде bash или C. Создание логики для параметров в вашем приложении с нуля каждый раз будет хлопотным, и, к счастью, стандартная библиотека ruby включает в себя модуль OptionParse
который делает тяжелую работу за нас.
Сначала давайте посмотрим, что такое опция и что она делает. «Параметры» и «аргументы» выглядят одинаково в CLI, но они разные. Вот обычная команда терминала git
:
$ git commit -m "Initial commit"
В этом примере:
-
git
это приложение -
commit
— команда для запуска приложения -
-m
это флаг опции -
"Initial commit"
— это аргумент, передаваемый команде через опцию
Приведенная выше команда терминала указывает git
зафиксировать текущие файлы, а флаг -m
позволяет вам напечатать сообщение фиксации (обратите внимание, как они использовали -m
для «сообщения»? Умный! ) Все в одной строке. Если вы просто git commit
в терминале, он откроет редактор и запросит сообщение о коммите, а также вспомогательный текст. Это выглядит примерно так:
# Please enter the commit message for your changes. Lines starting # with '#' will be ignored, and an empty message aborts the commit. # On branch master # # Initial commit # # Changes to be committed: # new file: README.markdown
Это полезно, когда вы новичок в git. Однако есть вероятность, что после того, как вы сделали несколько коммитов, вам не нужно бросаться в редактор и снова и снова видеть этот вспомогательный текст. При использовании флага опции -m
как мы делали выше, все значительно ускоряется.
Модуль OptionParse позволяет легко создавать флаги параметров и вспомогательный текст, объясняющий пользователю, что делает каждый параметр.
Поскольку OptionParse является частью стандартной библиотеки, вы можете добавить ее в свой проект с помощью
require 'optparse'
Чтобы показать, как работает библиотека optparse
, давайте взглянем на простой инструмент для работы со словами, который я написал для этого случая.
require 'optparse' options = {} OptionParser.new do |opts| opts.banner = "\nSimple word manipulator Ruby CLI app.\n" opts.on("-u", "--upcase", "Capitalize all letters") do |u| options[:upcase] = u end opts.on("-d", "--downcase", "Downcase all letters") do |d| options[:downcase] = d end opts.on("-c", "--capitalize", "Capitalize first character") do |c| options[:capitalize] = c end opts.on("-r", "--reverse", "Reverse the order of letters") do |r| options[:reverse] = r end opts.on("-h", "--help", "Displays help") do puts opts exit end end.parse! words = [] ARGV.each do |word| words << word.dup end words.each do |word| word.upcase! if options[:upcase] word.downcase! if options[:downcase] word.capitalize! if options[:capitalize] word.reverse! if options[:reverse] puts word end
Итак, что делает этот код? Он принимает аргументы в виде строк из командной строки, выполняет одно или несколько преобразований, а затем puts
результат в терминал. Вот что мы получим, если запустим этот код с «Hello» и «World» в качестве аргументов с параметром --reverse
:
$ ruby words.rb Hello World -r #=> olleH #=> dlroW
Первые две строки не требуют особого объяснения: нам нужен модуль optparse
и создаем пустой хеш с именем options
.
require 'optparse' options = {}
Прыгните OptionParse
блок OptionParse
и вы увидите глобальный ARGV
. Именно здесь аргументы, введенные в командной строке (но не параметры, подробнее об этом в секунду), собираются в массив. Здесь происходит одна особенность: все аргументы (#frozen) [http://www.ruby-doc.org/core-1.9.3/Object.html#method-i-freeze), поэтому я копирую Аргументы в другой массив с помощью метода Object # dup .
words = [] ARGV.each do |word| words << word.dup end
Последний блок выполняет итерации по каждому слову в массиве words
(дубликат аргументов, введенных в командной строке), выполняет манипуляции, основанные на любых параметрах, и puts
результат в терминал.
words.each do |word| word.upcase! if options[:upcase] word.downcase! if options[:downcase] word.capitalize! if options[:capitalize] word.reverse! if options[:reverse] puts word end
Наконец-то магия. Блок кода из OptionParser.new do |opts|
до end.parse!
где параметры определены, и во время выполнения анализируются из ввода командной строки. Есть много удобств, встроенных в класс OptionParser
:
-
OptionParser#banner
позволяет показывать произвольный текст пользователю при просмотре справки -
OptionParser#on
позволяет вам объявить каждый из ваших параметров, включая сокращенный флаг (т.--upcase
), подробный флаг (т.--upcase
), описательный вспомогательный текст (т.--upcase
«С заглавными буквами все буквы») и поведение параметра. -
end.parse!
интеллектуально извлекает флаги опций из списка аргументов, оставляя фактические аргументы для обработки вашим кодом. Это означает, что если вам нужно несколько флагов, вы можете выполнить любое из следующих действий и получить тот же результат:-
$ ruby words.rb Hello World -r -u
-
$ ruby words.rb -r Hello World -u
-
$ ruby words.rb -ru Hello World
-
Давайте еще раз посмотрим на блок OptionParser.new
:
OptionParser.new do |opts| opts.banner = "\nSimple word manipulator Ruby CLI app." opts.on("-u", "--upcase", "Capitalize all letters") do |u| options[:upcase] = u end opts.on("-d", "--downcase", "Downcase all letters") do |d| options[:downcase] = d end opts.on("-c", "--capitalize", "Capitalize first character") do |c| options[:capitalize] = c end opts.on("-r", "--reverse", "Reverse the order of letters") do |r| options[:reverse] = r end opts.on("-h", "--help", "Displays help") do puts opts exit end end.parse!
В нашем примере каждый параметр просто используется как логическое значение, которое является обычным, но вы можете делать практически все, что захотите. В простом приложении, которое я написал для предыдущей работы, большинство моих флагов опций добавляли или удаляли расширения файлов из глобального массива до выполнения остальной части кода.
Этот пример приложения командной строки работает (скопируйте и вставьте его в ваш любимый текстовый редактор и попробуйте!), Но его можно улучшить. Во-первых, некоторые флаги нельзя запускать вместе из-за порядка, в котором они проверяются, или способа, которым методы изменяют строку. Как бы вы изменили этот код, чтобы сделать его более надежным и гибким? Что произойдет, если у вас есть строки со специальными символами? Сколько аргументов вы можете отправить до того, как код взорвется (и, если есть предел, вы, скорее всего, достигнете его рукой, набрав в терминале?) Дайте мне знать в комментариях!