Статьи

Приложения для командной строки с OptionParse

Значок командной строки вектора

Приложения командной строки могут быть не такими распространенными, как раньше, но программисты используют их почти каждый день. Даже если вы новичок в 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! 

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

Этот пример приложения командной строки работает (скопируйте и вставьте его в ваш любимый текстовый редактор и попробуйте!), Но его можно улучшить. Во-первых, некоторые флаги нельзя запускать вместе из-за порядка, в котором они проверяются, или способа, которым методы изменяют строку. Как бы вы изменили этот код, чтобы сделать его более надежным и гибким? Что произойдет, если у вас есть строки со специальными символами? Сколько аргументов вы можете отправить до того, как код взорвется (и, если есть предел, вы, скорее всего, достигнете его рукой, набрав в терминале?) Дайте мне знать в комментариях!