pod
命令解析是用 CLAide
来实现的,在之前的文章Ruby和Cocoapods文章合集中,我们介绍了使用VSCode
来调试Cocoapods
源码。
CLAide命令解析
我们在调试工程中,通过pod install --clean-install --project-directory=${workspaceRoot}/TestLibrary
来感受下,pod
命令是如何解析的。launch.json
如下所示
{
"configurations": [
{
"name": "Debug CocoaPods Plugin",
"showDebuggerOutput": true,
"type": "Ruby",
"request": "launch",
"useBundler": true,
"cwd": "${workspaceRoot}/TestLibrary", // pod 命令执行的路径
"program": "${workspaceRoot}/CocoaPods/bin/pod",
"args": ["install", "--clean-install", "--project-directory=${workspaceRoot}/TestLibrary"], // `pod` 命令的参数
}
]
}
我们摁下F5
进入调试环境,解析函数的函数调用栈如图所示:
ARGV
我们传入的是一个数组 ["install", "--clean-install", "--project-directory=${workspaceRoot}/TestLibrary"]
。
首先会将其包装为 ARGV对象
。
在其初始化方法里面,来解析参数数组。
# @param [Array<#to_s>] argv
# A list of parameters.
#
def initialize(argv)
@entries = Parser.parse(argv)
end
参数的三种类型
CALide
定义了三种参数类型:
option
:可选参数, 以 --
开头,且包含=
的参数。
flag
: 限定为 bool
,类型的option
参数 以 --
开头,且不包含=
的参数。
arg
: 普通的实参。 所谓的实参就是直接跟在命令后面,且不带任何 -- 修饰字符。
参数解析后,格式如下
[ [:arg, "install"],
[:flag, "clean-install"],
[:option, "project-directory","${workspaceRoot}/TestLibrary"]
]
CLAide:ARGV参数处理
arguments
新建一个调试工程,在Gemfile
中引入 CLAide
。
source 'https://rubygems.org'
gem 'ruby-debug-ide'
gem 'debase'
gem 'claide'
我们自定义一个CLAide::ARGV
对象:
require 'claide'
argv = CLAide::ARGV.new(['tea','green','--no-milk', '--sweetener=honey'])
puts argv.arguments
输出
tea
green
上面参数的含义我们定义为:来一杯 绿茶
, 不加牛奶
,甜度
选择为蜂蜜
等级
arguements
:获取所有的普通参数。
shift_argument
oneARGU = argv.shift_argument
puts "oneARGU: #{oneARGU}" # tea
twoARGU = argv.shift_argument
puts "twoARGU: #{twoARGU}" # green
threeARGU = argv.shift_argument # nil
puts "threeARGU: #{threeARGU}"
输出结果:
oneARGU: tea
twoARGU: green
threeARGU:
shift_argument
: 获取第一个普通参数,并在entries
元组中移除。
flag?
flagMilk1 = argv.flag?('milk') # false
puts "flagMilk1: #{flagMilk1}"
flagMilk2 = argv.flag?('milk') # nil
puts "flagMilk2: #{flagMilk2}"
输出结果:
flagMilk1: false
flagMilk2:
flag?()
: 返回一个bool
, 如果 以 --no-
开头,返回false
, 并在entries
元组中移除。
option
option1 = argv.option('sweetener') # honey
puts "option1 #{option1}"
option2 = argv.option('sweetener') # nil
puts "option2 #{option2}"
输出结果:
option1 honey
option2
option()
:获取可选参数
,以key
,value
的形式获取可选参数。并在entries
元组中移除。
自制饮料售卖机
需求:提供两种饮料tea
和 coffee
:
选择tea
时,需选择 红茶,绿茶,黑茶,其中的一种,可选择是否加冰。
选择tea
或者coffe
,都可以选择是否添加牛奶,可以选择甜度(加糖或者加蜂蜜)
创建Gem工程
1, 我们创建一个bundle gem BeverageMaker
。我们将gemspec
文件修改成如下所示
require_relative "lib/BeverageMaker/version"
\
Gem::Specification.new do |spec|
spec.name = "BeverageMaker"
spec.version = BeverageMaker::VERSION
spec.authors = ["LYC"]
spec.email = ["1260197127@qq.com"]
spec.summary = "BeverageMaker"
spec.description = "BeverageMaker"
spec.homepage = "http://www.baidu.com"
spec.license = "MIT"
spec.required_ruby_version = ">= 2.4.0"
# Specify which files should be added to the gem when it is released.
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
spec.files = Dir.chdir(File.expand_path(__dir__)) do
`git ls-files -z`.split("\x0").reject do |f|
(f == __FILE__) || f.match(%r{\A(?:(?:test|spec|features)/|\.(?:git|travis|circleci)|appveyor)})
end
end
spec.bindir = "bin"
spec.executables = "beverage-maker"
spec.require_paths = ["lib"]
spec.add_runtime_dependency 'claide'
spec.add_runtime_dependency 'colored2'
end
2, 创建 launch.json
{"configurations": [
{
"name": "Debug CocoaPods Plugin",
"showDebuggerOutput": true,
"type": "Ruby",
"request": "launch",
"useBundler": true,
"cwd": "${workspaceRoot}", //
"program": "${workspaceRoot}/bin/beverage-maker", // 入口
"args": [
"tea", "green", "--no-milk", "--sweetner=honey" // 参数
]
}]
}
3,核心代码 Tea.rb
:
module BeverageMaker
class Tea < Command
self.summary = 'Drink based on cured leaves'
self.description = <<-DESC
An aromatic beverage commonly prepared by pouring boiling hot water over cured leaves of the Camellia sinensis plant.The following flavors are available: black, green, oolong, and white.
DESC
# tea 后面 要跟一个 FLAVOR 参数
self.arguments = [
# represent individual arguments to present to
# the command help banner
# def initialize(names, required, repeatable = false)
CLAide::Argument.new('FLAVOR',true)
]
# 可选参数 help banner
def self.options
[['--iced','the ice-tea version']].concat(super)
end
# 初始化方法
def initialize(argv)
# 给 实例变量 flavor 和 iced 赋值
@flavor = argv.shift_argument
@iced = argv.flag?('iced')
super
end
# 检查参数是否合理
def validate!
super
# 如果 flavor 变量为空,输出 help banner
if @flavor.nil?
help! 'A flavor argument is Required.'
end
# @flavor 值: 应该为 black green red 里面的一种
# %w(black red green) == ["black", "red", "green"]
unless %w(black red green).include?(@flavor)
help! "#{@flavor} is not a valid favor"
end
end
def run
super
puts "* Infuse #{@flavor} tea..."
sleep 1
if @iced
puts '* Cool off...'
end
sleep 1
puts '* Enjoy!'
end
end
end
F5
进行命令调试,运行结果如下
总结
Cocoapods
使用 CLAide
来解析命令的,它定义了三种参数: :arg
,:flag
和:option
。分别通过 shift_argument()
、flag?()
和 option("key")
来读取相对应的值。并且 CLAide
还提供了 参数说明模版help banner
,来展示 参数规则。
本文Demo地址Git
参考文章: