Podfile 解析最佳实践
基本語(yǔ)法
首先需要做的是,看懂一個(gè) Podfile。那么需要了解一些最基本的 ruby 語(yǔ)法,這部分非常簡(jiǎn)單:
source 'https://github.com/CocoaPods/Specs.git' platform :ios, '8.0' pod 'FLEX', :configurations => ['Debug'], :branch => 'develop' use_frameworks!以上三行代碼是 Podfile 中最為常見(jiàn)的,其實(shí)這三行是在調(diào)用不同的方法。
方法調(diào)用
Ruby 中,方法調(diào)用的參數(shù)列表可以以空格形式接在方法名后,多個(gè)參數(shù)以逗號(hào)隔開(kāi),所以等價(jià)于:
source 'https://github.com/CocoaPods/Specs.git' # => source('https://github.com/CocoaPods/Specs.git')platform :ios, '8.0' # => platform(:ios, '8.0')如果是最后一個(gè)參數(shù)是字典,那么字典的大括號(hào)也可以省略,所以 pod 的調(diào)用等價(jià)于:
pod 'FLEX', :configurations => ['Debug'], :branch => 'develop' #=> map = {:configurations => ['Debug'],:branch => 'develop' } pod('FLEX', map)符號(hào)(Symbol)
Symbol 是 Ruby 中的一種對(duì)象類(lèi)型,一般作為名稱(chēng)標(biāo)簽,為了不影響閱讀,我把 Symbol 的定義放在最后,這里可以暫且把它當(dāng)做前面加了 : 的 string。
所以,上面的代碼中,出現(xiàn)的 :ios,:configuration,:branch 以及常見(jiàn)的 :git,:tag 等都是 Symbol。
方法定義
Ruby 的方法定義更加靈活,語(yǔ)義也更加豐富。
方法名
比如 :nil?, empty?, merge! 這類(lèi)方法。
方法名小寫(xiě),可包含 !,? 這類(lèi)符號(hào)。用法可以學(xué)習(xí)系統(tǒng)的定義:
? 常用于判斷,取代了 is_ 開(kāi)頭的定義習(xí)慣。
! 常用于需要注意的方法,比如 arr.merge!(other_arr) 表示合并到 arr;與之對(duì)應(yīng)的是 arr.merge(other_arr),表示合并,但不修改 arr,而是返回合并后的結(jié)果。
在很多開(kāi)源庫(kù)中,! 的用法就比較巧妙,有可能并不表示在當(dāng)前對(duì)象上進(jìn)行修改,僅僅為了優(yōu)雅好看也是可能的。
所以,Podfile 中出現(xiàn)的 use_frameworks! 也是在調(diào)用方法。
參數(shù)列表
為了簡(jiǎn)單,這里僅介紹可空的參數(shù)定義。還是以 pod 方法舉栗子:
常見(jiàn)的 pod 調(diào)用如上,通過(guò)調(diào)用就能猜出 pod 方法的聲明:
# pname: 庫(kù)名 # version: 指定版本,且可空 # map: 用鍵值對(duì)接收其他參數(shù) def pod(pod_name, version = nil, **map)# ... end大致就是這樣,這里的 * 和指針沒(méi)關(guān)系 🌚。完整參數(shù)列表的定義方式,我寫(xiě)在文末吧。
返回值
其實(shí)解析這部分用不上返回值,不過(guò)可以介紹一下。Ruby 返回值有以下幾個(gè)特點(diǎn):
如果是最后一行,可以不寫(xiě) return。
支持多個(gè)返回值。
代碼塊(Block)
這個(gè)和 Objective-C 差不多,常用于回調(diào)。當(dāng)然 Podfile 也不缺少:
do…end 可以看成大括號(hào),:Meitu 是 target 方法的第一個(gè)參數(shù)。綜合之前介紹的語(yǔ)法,target 的定義就呼之欲出了:
# tname: target 名稱(chēng) # block: 回調(diào) def target(tname, &block)# ...# 調(diào)用yield if block_given? end語(yǔ)法到這里就基本夠用了,接著介紹如何解析。
解析
既然 Podfile 中是 Ruby 代碼,也就表示,可以通過(guò)調(diào)用 Ruby 腳本的方式,直接執(zhí)行 Podfile。
ruby ~/Desktop/Podfile然后就報(bào)錯(cuò)了…(編譯器又不知道 source,pod 這都是些什么方法…
定義方法
首先需要定義解析需要調(diào)用的方法,讓指定的變量乖乖的被對(duì)應(yīng)參數(shù)接收。最簡(jiǎn)易的版本,需要實(shí)現(xiàn) target 和 pod 兩個(gè)方法:
target
工程可能對(duì)應(yīng)多個(gè) target,具體要解析哪個(gè) target,需要對(duì)應(yīng)到打包時(shí)指定的 target,所以采用外部傳入的方式:$target_argv:
def target(target_name = nil, &block = nil)# target name 可能是 String,可能是 Symbol,統(tǒng)一 to_s 一下# 如果不是當(dāng)前打包的 target,直接返回就行了return if target_name.to_s != $target_argv# 調(diào)用 blockyield if block_given? endpod
實(shí)現(xiàn) pod 以后,就可以通過(guò)參數(shù)讀取這種值了。同樣,pod 可能包含 configuration 信息,這也是需要對(duì)應(yīng)打包的 configuration 參數(shù)的:
def pod(pod_name, version = nil, **args)git = args[:git]branch = args[:branch]tag = args[:tag]commit = args[:commit]configurations = args[:configurations]# 如果 pod 指定了 configuration,則判斷是否包含當(dāng)前 configurationunless configurations.nil?return unless configurations.include?($configuration)end# 通過(guò)哪種方式引用,這里可以通過(guò) tag、commit、branch 的 nil? 來(lái)判斷來(lái)源comes_from = "tag"# $map 為全局變量$map[pod_name] = {comes_from: comes_from,version: version} endmethod_missing
除了 target 和 pod 方法外,Podfile 中還存在 source、platform 等各種各樣的方法,一一實(shí)現(xiàn)是不可能的。對(duì)此,Ruby 提供了 method_missing 方法,該方法的作用類(lèi)似于消息轉(zhuǎn)發(fā)。當(dāng)程序調(diào)用沒(méi)有實(shí)現(xiàn)的方法時(shí),統(tǒng)一走 method_missing。
因?yàn)槲覀儾恍枰幚砦磳?shí)現(xiàn)方法的邏輯,所以方法體是空的,不需要實(shí)現(xiàn)。
導(dǎo)出
到此,整個(gè)解析就已經(jīng)完成了,比起以前用正則寫(xiě)的版本,清爽了很多。最后一步,將解析結(jié)果導(dǎo)出為 JSON 文件。代碼很簡(jiǎn)單:
Podfile.lock
這里簡(jiǎn)單提一下 lock 文件,因?yàn)?lock 文件中有準(zhǔn)確的版本號(hào),所以對(duì)應(yīng)引用版本都從 lock 當(dāng)中讀取。而 lock 文件其實(shí)是 yaml 格式的,可以通過(guò) yaml 庫(kù)將它解析為 hash 和 array 進(jìn)行讀取。
整個(gè)流程
那么,應(yīng)該如何將解析和導(dǎo)出兩個(gè)步驟串起來(lái)呢?方法需要定義在代碼開(kāi)頭,導(dǎo)出需要放在代碼末尾,所以有了以下結(jié)構(gòu):
定義
eval(File.read(podfile_path))導(dǎo)出
這里用到了非常強(qiáng)大的 eval 函數(shù),也就是將 podfile 內(nèi)容讀取為將字符串并當(dāng)做代碼執(zhí)行。
ruby inject_template.rb target_name configuration_name result_path podfile_path🚣? 🚣 🚣? 🚣?
最后
Symbol
Symbol 是 Ruby 中最為基礎(chǔ)的對(duì)象類(lèi)型,存儲(chǔ)在 Symbol Table 中,可以看做 name 和 ID 的對(duì)應(yīng)。Symbol 不可寫(xiě),地址不變,全局唯一。這和 String 不同,兩個(gè)值相同的 String,其實(shí)是不同的地址。
類(lèi)似于 Java 的 String 和 static String,一個(gè)是用完重新分配,一個(gè)是始終是一個(gè)存儲(chǔ)單元。針對(duì)于這個(gè)特性,Symbol 的效率會(huì)比 String 高一些。常用于成員變量名,hash 的 key 等。
如果想繼續(xù)了解 Symbol,推薦閱讀:
Understanding Differences Between Symbols & Strings in Ruby
Ruby Symbols
官方文檔
方法定義
a:Positional argument,位置參數(shù)。也就是說(shuō),聲明在第一個(gè),第一個(gè)傳入的就一定是 a 接收。
b:和 a 含義相同,且有默認(rèn)值。
c:連續(xù)多個(gè) Positional argument。
d:Keyword argument,對(duì)位置沒(méi)要求,接收指定 keyword 對(duì)應(yīng)的值。
e:和 d 含義相同,且有默認(rèn)值。
f:連續(xù)多個(gè) Keyword argument。
g:block。
總結(jié)
以上是生活随笔為你收集整理的Podfile 解析最佳实践的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 电力系统matlab建模视频,MATLA
- 下一篇: 模拟CMO-拉扎维