sbt筆記六 More Kinds of Setting(待續)

http://www.scala-sbt.org/release/docs/Getting-Started/More-About-Settings.html html

Refresher: Settings

記住,構建定義建立一個Setting列表,而後這個列表用於轉換sbt的構建描述(它是鍵值對的映射)。一個Setting是一個將sbt早先的映射做爲輸入、一個新的映射做爲輸出的轉換。這個新映射做爲sbt的新狀態。 java

不一樣的setting經過不一樣的方式轉換這個映射。早些時候,你已經讀到:=方法了。 app

:=建立的Setting在新的,改變了的映射中設置了固定的,常量的值。例如,若是你用setting name := "hello"來轉換一個映射,新的映射有一個字符串"hello"存儲在name鍵。 less

Settings must end up in the master list of settings to do any good(看不懂)(在build.sbt中的行都自動結束在list中,可是在.scala文件中你能夠錯誤地建立一個Setting卻沒有放到sbt可以發現的地方(but in a .scala file you can get it wrong by creating a Setting without putting it where sbt will find it)) ide

追加到原先的值:+=和++=

用:=替換是最簡單的轉換,可是key也有其餘的方法,若是SettingKey[T]中的T是一個序列,也就是說,key的值類型是一個序列,你能夠向序列追加值,而不是替換它。 函數

  • +=能夠向序列追加單個元素。
  • ++=能夠與另外一個序列鏈接。

例如,Compile做用域中的sourceDirectories鍵有一個Seq[File]的值。默認狀況下,它的值包含src/main/scala。若是你也想編譯source文件夾下的源碼,能夠添加這個文件夾: ui

sourceDirectories in Compile += new File("source")
或者,用sbt包中更便利的file()函數:
sourceDirectories in Compile += file("source")
(file()僅建立一個新的File。)

能夠用++=同時添加多個文件夾:
sourceDirectories in Compile ++= Seq(file("sources1"), file("sources2"))

Seq(a, b, c, ...)是Scala中建立序列的標準語法。 spa

完整替換默認源碼文件夾,無疑要用:=: scala

sourceDirectories in Compile := Seq(file("sources1"), file("sources2"))

轉換一個值(Transforming a value):~=

若是想向前追加Compile中的sourceDirectories,或過濾掉默認文件夾中的一個,要怎麼作呢? code

你能夠建立一個依賴於先前值的Setting。

  • ~=將一個函數應用到setting先前的值,並建立一個相同類型的新值。

修改Compile中的sourceDirectories,能夠以下方式使用~=:

// filter out src/main/scala
sourceDirectories in Compile ~= { srcDirs => srcDirs filter(!_.getAbsolutePath.endsWith("src/main/scala")) }

在這裏,srcDirs是匿名函數的入參,而且Compile中的sourceDirectories會被傳入匿名函數。這個函數的結果將做爲Compile中sourceDirectories的新值。

一個簡單的例子:

// make the project name upper case
name ~= { _.toUpperCase }

若是key是SettingKey[T]或TaskKey[T]類型,則傳入的函數必須是T => T類型的。這個函數將key的值轉換爲類型相同的另外一個值。

基於另外一個key的值,計算一個值:<<=

~=根據key先前的值來定義一個新值。但若是你想根據另外一個key的值來定義一個新值呢?

  • <<=容許你用另一個任意的key的值,來計算一個新的值。

<<=有一個Initialize[T]類型的參數。一個Initialize[T]的實例是一個計算,他將一個key集合所關聯的值做爲輸入,並返回一個T類型的值(基於其餘的值)。它初始化了一個T類型的值。

給定一個Initialize[T],<<=返回一個Setting[T](就像:=,+=,~=等)。

微不足道的Initialize[T]:用<<=依賴於另外一個key

全部的key都擴展自Initialize特質。因此key就是最簡單的Initialize:

// useless but valid
name <<= name

看成爲一個Initialize[T],一個SettingKey[T]計算它當前的值。因此name <<= name將name的值,設爲name已有的值。

若是你要將一個key設爲另外一個key,這就比較有用。兩個key必須擁有相同的值類型。

// name our organization after our project (both are SettingKey[String])
organization <<= name
若是值類型不一致,你須要從Initialize[T]轉換成另外一個類型,就像Initialize[S]。這在Initialize的apply方法中完成,像這樣:
// name is a Key[String], baseDirectory is a Key[File]
// name the project after the directory it's inside
name <<= baseDirectory.apply(_.getName)
在Scala中apply很特別,這意味着你能夠用函數語法調用這個對象;因此能夠這麼寫:
name <<= baseDirectory(_.getName)

它用_.getName函數轉換baseDirectory的值,函數_.getName獲得一個File並返回String。getName是標準java.io.File對象的方法。

Setting依賴

在setting name <<= baseDirectory(_.getName)中,name有一個baseDirectory的依賴。若是把上文放在build.sbt中,而且運行sbt交互控制檯,而後輸入inspect name,你就會看到(局部):

[info] Dependencies:
[info]  *:base-directory

這就是sbt如何知道一個setting依賴於另外一個setting。牢記一些setting是描述任務的,因此這種方式也建立任務間的依賴。

例如,若是你運行inspect compile,你將看到它依賴於另外一個key compile-inputs,而且若是你運行inspect compile-inputs,它依次依賴於其餘的key。跟隨依賴鏈而後奇蹟發生了。例如當你輸入compile,sbt會自動執行update。它可以工做是由於,compile計算所需的值,須要sbt先執行update計算。

經過這種方式,全部sbt中的構建依賴都是自動的,而不是明確地定義。若是你在另外一個計算中使用一個key的值,那麼這個計算就依賴於那個key。這很管用!

複雜的Initialize[T]:用<<=依賴多個key

爲了支持多個key的依賴,sbt爲Initialize對象元組添加apply和identity方法。在Scala中,元組寫成(1, "a")(它的類型是(Int, String))。

2013-1-28 22:40



2012-1-28 不要問爲何這篇沒有內容,我不會告訴你我把它扔家裏了。 家裏電腦沒有啊,爲何找不到了呢,我明明記得這篇我看過的,難道是光看沒寫下來嗎?好吧,再找時間寫吧。 找到了,哈哈,不過就完成了一半,先粘上來吧,別不當心又找不到了。前面好幾篇都忘了原文,這篇把原文連接加上,而後趕忙睡覺去,扛不住了。

相關文章
相關標籤/搜索