談?wù)?DSL 以及 DSL 的應(yīng)用(以 CocoaPods 為例)

因?yàn)?DSL 以及 DSL 的界定本身就是一個(gè)比較模糊的概念,所以難免有與他人觀點(diǎn)意見相左的地方挎狸,如果有不同的意見,我們可以具體討論。

最近在公司做了一次有關(guān) DSL 在 iOS 開發(fā)中的應(yīng)用的分享砾医,這篇文章會(huì)簡(jiǎn)單介紹這次分享的內(nèi)容。

這次文章的題目雖然是談?wù)?DSL 以及 DSL 的應(yīng)用衣厘,不過文章中主要側(cè)重點(diǎn)仍然是 DSL表谊,會(huì)簡(jiǎn)單介紹 DSL 在 iOS 開發(fā)中(CocoaPods)是如何應(yīng)用的娇斩。

沒有銀彈从祝?

1987 年腻豌,IBM 大型電腦之父 Fred Brooks 發(fā)表了一篇關(guān)于軟件工程中的論文 [No Silver Bullet—Essence and Accidents of Software Engineering](No Silver Bullet—Essence and Accidents of Software Engineering) 文中主要圍繞這么一個(gè)觀點(diǎn):沒有任何一種技術(shù)或者方法能使軟件工程的生產(chǎn)力在十年之內(nèi)提高十倍。

There is no single development, in either technology or management technique, which by itself promises even one order-of-magnitude improvement within a decade in productivity, in reliability, in simplicity.

時(shí)至今日型宙,我們暫且不談銀彈在軟件工程中是否存在(這句話在老板或者項(xiàng)目經(jīng)理要求加快項(xiàng)目進(jìn)度時(shí)撬呢,還是十分好用的),作為一個(gè)開發(fā)者也不是很關(guān)心這種抽象的理論妆兑,我們更關(guān)心的是開發(fā)效率能否有實(shí)質(zhì)的提升魂拦。

silver-bullet

而今天要介紹的 DSL 就可以真正的提升生產(chǎn)力,減少不必要的工作箭跳,在一些領(lǐng)域幫助我們更快的實(shí)現(xiàn)需求晨另。

DSL 是什么?

筆者是在兩年以前谱姓,在大一的一次分享上聽到 DSL 這個(gè)詞的借尿,但是當(dāng)時(shí)并沒有對(duì)這個(gè)名詞有多深的理解與認(rèn)識(shí),聽過也就忘記了屉来,但是最近做的一些開源項(xiàng)目讓我重新想起了 DSL路翻,也是這次分享題目的由來。

DSL 其實(shí)是 Domain Specific Language 的縮寫茄靠,中文翻譯為領(lǐng)域特定語(yǔ)言(下簡(jiǎn)稱 DSL)茂契;而與 DSL 相對(duì)的就是 GPL,這里的 GPL 并不是我們知道的開源許可證慨绳,而是 General Purpose Language 的簡(jiǎn)稱掉冶,即通用編程語(yǔ)言真竖,也就是我們非常熟悉的 Objective-C、Java厌小、Python 以及 C 語(yǔ)言等等恢共。

Wikipedia 對(duì)于 DSL 的定義還是比較簡(jiǎn)單的:

A specialized computer language designed for a specific task.

為了解決某一類任務(wù)而專門設(shè)計(jì)的計(jì)算機(jī)語(yǔ)言。

與 GPL 相對(duì)璧亚,DSL 與傳統(tǒng)意義上的通用編程語(yǔ)言 C讨韭、Python 以及 Haskell 完全不同。通用的計(jì)算機(jī)編程語(yǔ)言是可以用來編寫任意計(jì)算機(jī)程序的癣蟋,并且能表達(dá)任何的可被計(jì)算的邏輯透硝,同時(shí)也是 圖靈完備 的。

這一小節(jié)中的 DSL 指外部 DSL疯搅,下一節(jié)中會(huì)介紹 內(nèi)部 DSL/嵌入式 DSL

但是在里所說的 DSL 并不是圖靈完備的濒生,它們的表達(dá)能力有限,只是在特定領(lǐng)域解決特定任務(wù)的秉撇。

A computer programming language of limited expressiveness focused on a particular domain.

另一個(gè)世界級(jí)軟件開發(fā)大師 Martin Fowler 對(duì)于領(lǐng)域特定語(yǔ)言的定義在筆者看來就更加具體了甜攀,DSL 通過在表達(dá)能力上做的妥協(xié)換取在某一領(lǐng)域內(nèi)的高效

而有限的表達(dá)能力就成為了 GPL 和 DSL 之間的一條界限琐馆。

幾個(gè)栗子

最常見的 DSL 包括 Regex 以及 HTML & CSS,在這里會(huì)對(duì)這幾個(gè)例子進(jìn)行簡(jiǎn)單介紹

  • Regex
    • 正則表達(dá)式僅僅指定了字符串的 pattern恒序,其引擎就會(huì)根據(jù) pattern 判斷當(dāng)前字符串跟正則表達(dá)式是否匹配瘦麸。


      regex
  • SQL
    • SQL 語(yǔ)句在使用時(shí)也并沒有真正的執(zhí)行,我們輸入的 SQL 語(yǔ)句最終還要交給數(shù)據(jù)庫(kù)來進(jìn)行處理歧胁,數(shù)據(jù)庫(kù)會(huì)從 SQL 語(yǔ)句中讀取有用的信息滋饲,然后從數(shù)據(jù)庫(kù)中返回使用者期望的結(jié)果。
  • HTML & CSS
    • HTML 和 CSS 只是對(duì) Web 界面的結(jié)構(gòu)語(yǔ)義和樣式進(jìn)行描述喊巍,雖然它們?cè)跇?gòu)建網(wǎng)站時(shí)非常重要屠缭,但是它們并非是一種編程語(yǔ)言,正相反崭参,我們可以認(rèn)為 HTML 和 CSS 是在 Web 中的領(lǐng)域特定語(yǔ)言呵曹。

Features

上面的幾個(gè)??明顯的縮小了通用編程語(yǔ)言的概念,但是它們確實(shí)在自己領(lǐng)域表現(xiàn)地非常出色何暮,因?yàn)檫@些 DSL 就是根據(jù)某一個(gè)特定領(lǐng)域的特點(diǎn)塑造的奄喂;而通用編程語(yǔ)言相比領(lǐng)域特定語(yǔ)言,在設(shè)計(jì)時(shí)是為了解決更加抽象的問題海洼,而關(guān)注點(diǎn)并不只是在某一個(gè)領(lǐng)域跨新。

上面的幾個(gè)例子有著一些共同的特點(diǎn):

  • 沒有計(jì)算和執(zhí)行的概念;
  • 其本身并不需要直接表示計(jì)算坏逢;
  • 使用時(shí)只需要聲明規(guī)則域帐、事實(shí)以及某些元素之間的層級(jí)和關(guān)系赘被;

雖然了解了 DSL 以及 DSL 的一些特性,但是肖揣,到目前為止帘腹,我們對(duì)于如何構(gòu)建一個(gè) DSL 仍然不是很清楚。

構(gòu)建 DSL

DSL 的構(gòu)建與編程語(yǔ)言其實(shí)比較類似许饿,想想我們?cè)谥匦聦?shí)現(xiàn)編程語(yǔ)言時(shí)阳欲,需要做那些事情;實(shí)現(xiàn)編程語(yǔ)言的過程可以簡(jiǎn)化為定義語(yǔ)法與語(yǔ)義陋率,然后實(shí)現(xiàn)編譯器或者解釋器的過程球化,而 DSL 的實(shí)現(xiàn)與它也非常類似,我們也需要對(duì) DSL 進(jìn)行語(yǔ)法與語(yǔ)義上的設(shè)計(jì)瓦糟。

compile

總結(jié)下來筒愚,實(shí)現(xiàn) DSL 總共有這么兩個(gè)需要完成的工作:

  1. 設(shè)計(jì)語(yǔ)法和語(yǔ)義,定義 DSL 中的元素是什么樣的菩浙,元素代表什么意思
  2. 實(shí)現(xiàn) parser巢掺,對(duì) DSL 解析,最終通過解釋器來執(zhí)行

以 HTML 為例劲蜻,HTML 中所有的元素都是包含在尖括號(hào) <> 中的陆淀,尖括號(hào)中不同的元素代表了不同的標(biāo)簽,而這些標(biāo)簽會(huì)被瀏覽器解析成 DOM 樹先嬉,再經(jīng)過一系列的過程調(diào)用 Native 的圖形 API 進(jìn)行繪制轧苫。

dom-tree

再比如,我們使用下面這種方式對(duì)一個(gè)模型進(jìn)行定義疫蔓,實(shí)現(xiàn)一個(gè) ORM 領(lǐng)域的 DSL:

define :article do
  attr :name
  attr :content
  attr :upvotes, :int
  
  has_many :comments
end

在上面的 DSL 中含懊,使用 define 來定義一個(gè)新的模型,使用 attr 來為模型添加屬性衅胀,使用 has_many 建立數(shù)據(jù)模型中的一對(duì)多關(guān)系岔乔;我們可以使用 DSL 對(duì)這段“字符串”進(jìn)行解析,然后交給代碼生成器來生成代碼滚躯。

public struct Article {
    public var title: String
    public var content: String
    public var createdAt: Date
    
    public init(title: String, content: String, createdAt: Date)

    static public func new(title: String, content: String, createdAt: Date) -> Article
    static public func create(title: String, content: String, createdAt: Date) -> Article?
    ...
}

這里創(chuàng)建的 DSL 中的元素?cái)?shù)量非常少雏门,只有 define attr 以及 has_many 等幾個(gè)關(guān)鍵字,但是通過這幾個(gè)關(guān)鍵字就可以完成在模型層需要表達(dá)的絕大部分語(yǔ)義哀九。

設(shè)計(jì)原則和妥協(xié)

DSL 最大的設(shè)計(jì)原則就是簡(jiǎn)單剿配,通過簡(jiǎn)化語(yǔ)言中的元素,降低使用者的負(fù)擔(dān)阅束;無論是 Regex呼胚、SQL 還是 HTML 以及 CSS,其說明文檔往往只有幾頁(yè)息裸,非常易于學(xué)習(xí)和掌握蝇更。但是沪编,由此帶來的問題就是,DSL 中缺乏抽象的概念年扩,比如:模塊化蚁廓、變量以及方法等。

抽象的概念并不是某個(gè)領(lǐng)域所關(guān)注的問題厨幻,就像 Regex 并不需要有模塊相嵌、變量以及方法等概念。

由于抽象能力的缺乏况脆,在我們的項(xiàng)目規(guī)模變得越來越大時(shí)饭宾,DSL 往往滿足不了開發(fā)者的需求;我們?nèi)匀恍枰幊陶Z(yǔ)言中的模塊化等概念對(duì) DSL 進(jìn)行補(bǔ)充格了,以此解決 DSL 并不是真正編程語(yǔ)言的問題看铆。

css-sass

在當(dāng)今的 Web 前端項(xiàng)目中,我們?cè)陂_發(fā)大規(guī)模項(xiàng)目時(shí)往往不會(huì)直接手寫 CSS 文件盛末,而是會(huì)使用 Sass 或者 Less 為 CSS 帶來更強(qiáng)大的抽象能力弹惦,比如嵌套規(guī)則,變量悄但,混合以及繼承等特性棠隐。

nav {
  ul {
    margin: 0;
    padding: 0;
    list-style: none;
  }

  li { display: inline-block; }

  a {
    display: block;
    padding: 6px 12px;
    text-decoration: none;
  }
}

也就是說,在使用 DSL 的項(xiàng)目規(guī)模逐漸變大時(shí)算墨,開發(fā)者會(huì)通過增加抽象能力的方式宵荒,對(duì)已有的 DSL 進(jìn)行拓展;但是這種擴(kuò)展往往需要重新實(shí)現(xiàn)通用編程語(yǔ)言中的特性净嘀,?所以一般情況下都是比較復(fù)雜的。

Embedded DSL(嵌入式 DSL)

那么侠讯,是否有一種其它的方法為 DSL 快速添加抽象能力呢挖藏?而這也就是這一小節(jié)的主題,嵌入式 DSL厢漩。

在上一節(jié)講到的 DSL 其實(shí)可以被稱為外部 DSL膜眠;而這里即將談到的嵌入式 DSL 也有一個(gè)別名,內(nèi)部 DSL溜嗜。

這兩者最大的區(qū)別就是宵膨,內(nèi)部 DSL 的實(shí)現(xiàn)往往是嵌入一些編程語(yǔ)言的,比如 iOS 的依賴管理組件 CocoaPods 和 Android 的主流編譯工具 Gradle炸宵,前者的實(shí)現(xiàn)是基于 Ruby 語(yǔ)言的一些特性辟躏,而后者基于 Groovy。

cocoapods

CocoaPods 以及其它的嵌入式 DSL 使用了宿主語(yǔ)言(host language)的抽象能力土全,并且省去了實(shí)現(xiàn)復(fù)雜語(yǔ)法分析器(Parser)的過程捎琐,并不需要重新實(shí)現(xiàn)模塊会涎、變量等特性。

嵌入式 DSL 的產(chǎn)生其實(shí)模糊了框架和 DSL 的邊界瑞凑,不過這兩者看起來也沒有什么比較明顯的區(qū)別末秃;不過,DSL 一般會(huì)使用宿主語(yǔ)言的特性進(jìn)行創(chuàng)造籽御,在設(shè)計(jì) DSL 時(shí)练慕,也不會(huì)考慮宿主語(yǔ)言中有哪些 API 以及方法,而框架一般都是對(duì)語(yǔ)言中的 API 進(jìn)行組合和再包裝技掏。

我們沒有必要爭(zhēng)論哪些是框架铃将,哪些是 DSL,因?yàn)檫@些爭(zhēng)論并沒有什么意義零截。

Rails 和 Embedded DSL

最出名也最成功的嵌入式 DSL 應(yīng)該就是 Ruby on Rails 了麸塞,雖然對(duì)于 Rails 是否是 DSL 有爭(zhēng)議,不過 Rails 為 Web 應(yīng)用的創(chuàng)建提供大量的內(nèi)置的支撐涧衙,使我們?cè)陂_發(fā) Web 應(yīng)用時(shí)變得非常容易哪工。

rails

Ruby、 DSL 和 iOS

為了保證這篇文章的完整性弧哎,這一小節(jié)中有的一些內(nèi)容都出自上一篇文章 CocoaPods 都做了什么雁比?

筆者同時(shí)作為 iOS 和 Rails 開發(fā)者接觸了非常多的 DSL撤嫩,而在 iOS 開發(fā)中最常見的 DSL 就是 CocoaPods 了偎捎,而這里我們以 CocoaPods 為例,介紹如何使用 Ruby 創(chuàng)造一個(gè)嵌入式 DSL序攘。

Why Ruby茴她?

看到這里有人可能會(huì)問了,為什么使用 Ruby 創(chuàng)造嵌入式 DSL程奠,而不是使用 C丈牢、Java、Python 等等語(yǔ)言呢瞄沙,這里大概有四個(gè)原因:

  • 一切皆對(duì)象的特性減少了語(yǔ)言中的元素己沛,不存在基本類型、操作符距境;
  • 向 Ruby 方法中傳入代碼塊非常方便申尼;
  • 作為解釋執(zhí)行的語(yǔ)言,eval 模糊了數(shù)據(jù)和代碼的邊界垫桂;
  • 不對(duì)代碼的格式進(jìn)行約束师幕,同時(shí)一些約定減少了代碼中的噪音。

一切皆對(duì)象

在許多語(yǔ)言伪货,比如 Java 中们衙,數(shù)字與其他的基本類型都不是對(duì)象钾怔,而在 Ruby 中所有的元素,包括基本類型都是對(duì)象蒙挑,同時(shí)也不存在運(yùn)算符的概念宗侦,所謂的 1 + 1,其實(shí)只是 1.+(1) 的語(yǔ)法糖而已忆蚀。

得益于一切皆對(duì)象的概念矾利,在 Ruby 中,你可以向任意的對(duì)象發(fā)送 methods 消息馋袜,在運(yùn)行時(shí)自省男旗,所以筆者在每次忘記方法時(shí),都會(huì)直接用 methods 來“查閱文檔”:

2.3.1 :003 > 1.methods
 => [:%, :&, :*, :+, :-, :/, :<, :>, :^, :|, :~, :-@, :**, :<=>, :<<, :>>, :<=, :>=, :==, :===, :[], :inspect, :size, :succ, :to_s, :to_f, :div, :divmod, :fdiv, :modulo, ...]

比如在這里向?qū)ο?1 調(diào)用 methods 就會(huì)返回它能響應(yīng)的所有方法欣鳖。

一切皆對(duì)象不僅減少了語(yǔ)言中類型的數(shù)量察皇,消滅了基本數(shù)據(jù)類型與對(duì)象之間的邊界;這一概念同時(shí)也簡(jiǎn)化了組成語(yǔ)言的元素泽台,這樣 Ruby 中只有對(duì)象和方法什荣,這兩個(gè)概念,極大降低了這門語(yǔ)言的復(fù)雜度:

  • 使用對(duì)象存儲(chǔ)狀態(tài)
  • 對(duì)象之間通過方法通信

block

Ruby 對(duì)函數(shù)式編程范式的支持是通過 block怀酷,這里的 block 和 Objective-C 中的 block 有些不同稻爬。

首先 Ruby 中的 block 也是一種對(duì)象,即 Proc 類的實(shí)例蜕依,也就是所有的 block 都是 first-class 的桅锄,可以作為參數(shù)傳遞,返回样眠。

下面的代碼演示了兩種向 Ruby 方法中傳入代碼塊的方式:

def twice(&proc)
    2.times { proc.call() } if proc
end

def twice
    2.times { yield } if block_given?
end

yield 會(huì)調(diào)用外部傳入的 block友瘤,block_given? 用于判斷當(dāng)前方法是否傳入了 block

twice do 
    puts "Hello"
end

twice { puts "hello" }

twice 方法傳入 block 也非常簡(jiǎn)單檐束,使用 do商佑、end 或者 {} 就可以向任何的 Ruby 方法中傳入代碼塊厢塘。

eval

早在幾十年前的 Lisp 語(yǔ)言就有了 eval 這個(gè)方法,這個(gè)方法會(huì)將字符串當(dāng)做代碼來執(zhí)行肌幽,也就是說 eval 模糊了代碼與數(shù)據(jù)之間的邊界晚碾。

> eval "1 + 2 * 3"
 => 7

有了 eval 方法,我們就獲得了更加強(qiáng)大的動(dòng)態(tài)能力喂急,在運(yùn)行時(shí)格嘁,使用字符串來改變控制流程,執(zhí)行代碼并可以直接利用當(dāng)前語(yǔ)言的解釋器廊移;而不需要去手動(dòng)解析字符串然后執(zhí)行代碼糕簿。

格式和約定

編寫 Ruby 腳本時(shí)并不需要像 Python 一樣對(duì)代碼的格式有著嚴(yán)格的規(guī)定探入,沒有對(duì)空行、Tab 的要求懂诗,完全可以想怎么寫就怎么寫蜂嗽,這樣極大的增加了 DSL 設(shè)計(jì)的可能性。

同時(shí)殃恒,在一般情況下植旧,Ruby 在方法調(diào)用時(shí)并不需要添加括號(hào):

puts "Wello World!"
puts("Hello World!")

這樣減少了 DSL 中的噪音,能夠幫助我們更加關(guān)心語(yǔ)法以及語(yǔ)義上的設(shè)計(jì)离唐,降低了使用者出錯(cuò)的可能性病附。

最后,Ruby 中存在一種特殊的數(shù)據(jù)格式 Symbol

> :symbol.to_s
 => "symbol"
> "symbol".to_sym
 => :symbol

Symbol 可以通過 Ruby 中內(nèi)置的方法與字符串之間無縫轉(zhuǎn)換亥鬓。那么作為一種字符串的替代品完沪,它的使用也能夠降低使用者出錯(cuò)的成本并提升使用體驗(yàn),我們并不需要去寫兩邊加上引號(hào)的字符串嵌戈,只需要以 : 開頭就能創(chuàng)建一個(gè) Symbol 對(duì)象覆积。

Podfile 是什么

對(duì) Ruby 有了一些了解之后,我們就可以再看一下使用 CocoaPods 的工程中的 Podfile 到底是什么了:

source 'https://github.com/CocoaPods/Specs.git'

target 'Demo' do
    pod 'Mantle', '~> 1.5.1'
    ...
end

如果不了解 iOS 開發(fā)后者沒有使用過 CocoaPods咕别,筆者在這里簡(jiǎn)單介紹一下這個(gè)文件中的一些信息技健。

source 可以看作是存儲(chǔ)依賴元信息(包括依賴的對(duì)應(yīng)的 GitHub 地址)的源地址;

target 表示需要添加依賴的工程的名字惰拱;

pod 表示依賴雌贱,Mantle 為依賴的框架,后面是版本號(hào)偿短。

上面是一個(gè)使用 Podfile 定義依賴的一個(gè)例子欣孤,不過 Podfile 對(duì)約束的描述其實(shí)是這樣的:

source('https://github.com/CocoaPods/Specs.git')

target('Demo') do
    pod('Mantle', '~> 1.5.1')
    ...
end

Podfile 中對(duì)于約束的描述,其實(shí)都可以看作是代碼的簡(jiǎn)寫昔逗,在解析時(shí)會(huì)當(dāng)做 Ruby 代碼來執(zhí)行降传。

簡(jiǎn)單搞個(gè) Embedded DSL

使用 Ruby 實(shí)現(xiàn)嵌入式 DSL 一般需要三個(gè)步驟,這里以 CocoaPods 為例進(jìn)行簡(jiǎn)單介紹:

  • 創(chuàng)建一個(gè) Podfile 中“代碼”執(zhí)行的上下文勾怒,也就是一些方法婆排;
  • 讀取 Podfile 中的內(nèi)容到腳本中;
  • 使用 eval 在上下文中執(zhí)行 Podfile 中的“代碼”笔链;

原理

CocoaPods 對(duì)于 DSL 的實(shí)現(xiàn)基本上就是我們創(chuàng)建一個(gè) DSL 的過程段只,定義一系列必要的方法,比如 source鉴扫、pod 等等赞枕,創(chuàng)造一個(gè)執(zhí)行的上下文;然后去讀存儲(chǔ) DSL 的文件,并且使用 eval 執(zhí)行炕婶。

信息的傳遞一般都是通過參數(shù)來進(jìn)行的姐赡,比如:

source 'https://github.com/CocoaPods/Specs.git'

source 方法的參數(shù)就是依賴元信息 Specs 的 Git 地址,在 eval 執(zhí)行時(shí)就會(huì)被讀取到 CocoaPods 中柠掂,然后進(jìn)行分析项滑。

實(shí)現(xiàn)

下面是一個(gè)非常常見的 Podfile 內(nèi)容:

source 'http://source.git'
platform :ios, '8.0'

target 'Demo' do
    pod 'AFNetworking'
    pod 'SDWebImage'
    pod 'Masonry'
    pod "Typeset"
    pod 'BlocksKit'
    pod 'Mantle'
    pod 'IQKeyboardManager'
    pod 'IQDropDownTextField'
end

因?yàn)檫@里的 sourceplatform陪踩、target 以及 pod 都是方法杖们,所以在這里我們需要構(gòu)建一個(gè)包含上述方法的上下文:

# eval_pod.rb
$hash_value = {}

def source(url)
end

def target(target)
end

def platform(platform, version)
end

def pod(pod)
end

使用一個(gè)全局變量 hash_value 存儲(chǔ) Podfile 中指定的依賴,并且構(gòu)建了一個(gè) Podfile 解析腳本的骨架肩狂;我們先不去完善這些方法的實(shí)現(xiàn)細(xì)節(jié)摘完,先嘗試一下讀取 Podfile 中的內(nèi)容并執(zhí)行 eval 看看會(huì)不會(huì)有問題。

eval_pod.rb 文件的最下面加入這幾行代碼:

content = File.read './Podfile'
eval content
p $hash_value

這里讀取了 Podfile 文件中的內(nèi)容傻谁,并把其中的內(nèi)容當(dāng)做字符串執(zhí)行孝治,最后打印 hash_value 的值。

$ ruby eval_pod.rb

運(yùn)行這段 Ruby 代碼雖然并沒有什么輸出审磁,但是并沒有報(bào)出任何的錯(cuò)誤谈飒,接下來我們就可以完善這些方法了:

def source(url)
    $hash_value['source'] = url
end

def target(target)
    targets = $hash_value['targets']
    targets = [] if targets == nil
    targets << target
    $hash_value['targets'] = targets
    yield if block_given?
end

def platform(platform, version)
end

def pod(pod)
    pods = $hash_value['pods']
    pods = [] if pods == nil
    pods << pod
    $hash_value['pods'] = pods
end

在添加了這些方法的實(shí)現(xiàn)之后,再次運(yùn)行腳本就會(huì)得到 Podfile 中的依賴信息了态蒂,不過這里的實(shí)現(xiàn)非常簡(jiǎn)單的杭措,很多情況都沒有處理:

$ ruby eval_pod.rb
{"source"=>"http://source.git", "targets"=>["Demo"], "pods"=>["AFNetworking", "SDWebImage", "Masonry", "Typeset", "BlocksKit", "Mantle", "IQKeyboardManager", "IQDropDownTextField"]}

不過使用 Ruby 構(gòu)建一個(gè)嵌入式 DSL 的過程大概就是這樣,使用語(yǔ)言內(nèi)建的特性來進(jìn)行創(chuàng)作钾恢,創(chuàng)造出一個(gè)在使用時(shí)看起來并不像代碼的 DSL手素。

寫在后面

在最后,筆者想說的是瘩蚪,當(dāng)我們?cè)谀骋粋€(gè)領(lǐng)域經(jīng)常需要解決重復(fù)性問題時(shí)泉懦,可以考慮實(shí)現(xiàn)一個(gè) DSL 專門用來解決這些類似的問題。

而使用嵌入式 DSL 來解決這些問題是一個(gè)非常好的辦法疹瘦,我們并不需要重新實(shí)現(xiàn)解釋器崩哩,也可以利用宿主語(yǔ)言的抽象能力。

同時(shí)言沐,在嵌入式 DSL 擴(kuò)展了 DSL 的范疇之后邓嘹,不要糾結(jié)于某些東西到底是框架還是領(lǐng)域特定語(yǔ)言,這些都不重要险胰,重要的是吴超,在遇到了某些問題時(shí),我們能否跳出來鸯乃,使用文中介紹的方法減輕我們的工作量。

Reference

其它

GitHub Repo:iOS-Source-Code-Analyze

Follow: Draveness · GitHub

Source: http://draveness.me/dsl

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市缨睡,隨后出現(xiàn)的幾起案子鸟悴,更是在濱河造成了極大的恐慌,老刑警劉巖奖年,帶你破解...
    沈念sama閱讀 206,378評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件细诸,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡陋守,警方通過查閱死者的電腦和手機(jī)震贵,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,356評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來水评,“玉大人猩系,你說我怎么就攤上這事≈性铮” “怎么了寇甸?”我有些...
    開封第一講書人閱讀 152,702評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)疗涉。 經(jīng)常有香客問我拿霉,道長(zhǎng),這世上最難降的妖魔是什么咱扣? 我笑而不...
    開封第一講書人閱讀 55,259評(píng)論 1 279
  • 正文 為了忘掉前任绽淘,我火速辦了婚禮,結(jié)果婚禮上闹伪,老公的妹妹穿的比我還像新娘沪铭。我一直安慰自己,他們只是感情好祭往,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,263評(píng)論 5 371
  • 文/花漫 我一把揭開白布伦意。 她就那樣靜靜地躺著,像睡著了一般硼补。 火紅的嫁衣襯著肌膚如雪驮肉。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,036評(píng)論 1 285
  • 那天已骇,我揣著相機(jī)與錄音离钝,去河邊找鬼。 笑死褪储,一個(gè)胖子當(dāng)著我的面吹牛卵渴,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播鲤竹,決...
    沈念sama閱讀 38,349評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼浪读,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起碘橘,我...
    開封第一講書人閱讀 36,979評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤互订,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后痘拆,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體仰禽,經(jīng)...
    沈念sama閱讀 43,469評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,938評(píng)論 2 323
  • 正文 我和宋清朗相戀三年纺蛆,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了吐葵。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,059評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡桥氏,死狀恐怖温峭,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情识颊,我是刑警寧澤诚镰,帶...
    沈念sama閱讀 33,703評(píng)論 4 323
  • 正文 年R本政府宣布,位于F島的核電站祥款,受9級(jí)特大地震影響清笨,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜刃跛,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,257評(píng)論 3 307
  • 文/蒙蒙 一抠艾、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧桨昙,春花似錦检号、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,262評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至桂塞,卻和暖如春凹蜂,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背阁危。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評(píng)論 1 262
  • 我被黑心中介騙來泰國(guó)打工玛痊, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人狂打。 一個(gè)月前我還...
    沈念sama閱讀 45,501評(píng)論 2 354
  • 正文 我出身青樓擂煞,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親趴乡。 傳聞我的和親對(duì)象是個(gè)殘疾皇子对省,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,792評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容

  • 稍有 iOS 開發(fā)經(jīng)驗(yàn)的人應(yīng)該都是用過 CocoaPods官辽,而對(duì)于 CI蛹磺、CD 有了解的同學(xué)也都知道 Fastla...
    Draveness閱讀 6,690評(píng)論 9 77
  • CocoaPods 是什么? CocoaPods 是一個(gè)負(fù)責(zé)管理 iOS 項(xiàng)目中第三方開源庫(kù)的工具同仆。CocoaPo...
    朝洋閱讀 25,633評(píng)論 3 51
  • 項(xiàng)目組件化、平臺(tái)化是技術(shù)公司的共同目標(biāo)裙品,越來越多的技術(shù)公司推崇使用pod管理第三方庫(kù)以及私有組件俗批,一方面使項(xiàng)目架構(gòu)...
    swu_luo閱讀 21,471評(píng)論 0 39
  • 一、異同對(duì)比選擇1市怎、Python和ruby的相同點(diǎn): * 都強(qiáng)調(diào)語(yǔ)法簡(jiǎn)單岁忘,都具有更一般的表達(dá)方式。python是縮...
    沃倫蓋茨閱讀 4,134評(píng)論 2 24
  • 扶光綠柳堤区匠,草漫入蛙畦干像。 且見清風(fēng)去,歸時(shí)暮色西驰弄。
    詩(shī)酒慰年華的夏川閱讀 387評(píng)論 0 0