2011年12月23日

在 STS 中整合 Grails 與 Scala

目前看到新發佈的 Grails v2.0.0,馬上就試著加到 STS (SpringSource Tool Suite)中;但心想 open source 界熱門話題的 Scala 剛推出 v2.0,也一併來用用看。
於是在一個練習的 grails project 安裝了 scala plugin (v0.6.4),接著在 src/scala 中寫了一個 .scala ;不過 run-app 時出現了 ...

[scalaPlugin] Compiling Scala sources to target/classes
 | Error Error executing script Compile:
 : Could not compile Scala sources: BuildException:
 Compile failed because of an internal compiler error (object scala not found.);
 see the error output for details. (Use --stacktrace to see the full trace)

而網路上已有了解決的方法(如下圖所示),顯然這不構成問題。






但試想:每每得先 grails compile 出 .class 才能做單元測試,試乎沒用到 IDE 中 scala builder 的好處。所以,我將這個 project 加上 builder:

 org.scala-ide.sdt.core.scalabuilder
 

與 nature :
org.scala-ide.sdt.core.scalanature
而此舉引發了兩個的問題:
IDE 會出現要求加入 scala library 的錯誤訊息。
但加了 lib 之後,則又引起了 grails builder 的編譯錯誤。 

所以,我改了方式: 保持這個 grails project 的原樣,另起一個 scala project;
而這個新 project 的 src 目錄以 link folder 的形式連接到 grails project 的 src/scala。 如下圖所示:




























這樣子就能寫 .scala 時做單元測試,而又不影響 grails project 的任何操作了。

2011年12月3日

第一個 Android 練習題撰寫心得

學習第一個 Android 程式時,通常會在第一個 Activity 中載入 main layout (res/layout/main.xml)
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
}
但,當預期中元件相關的屬性不符需要,那就由程式碼來動態控制;如取得 layout :
LinearLayout linear = (LinearLayout)findViewById(R.id.linear);
...
只要在 layout 中定義即可:
< LinearLayout android:id="@+id/linear" >
接著,試想某些情形在 class 設計耦合上不與 layout 直接相關,那就得搬出 API :
先取得 content view:
View contentView = getWindow().getDecorView().findViewById(android.R.id.content);
取得 layout (如果預期是 LinearLayout):
LinearLayout linear = (LinearLayout)((ViewGroup)contentView).getChildAt(0);
看來只要是 ViewGroup class ,就有機會介由 .getChildAt() 取得物件;再由 instanceof 辨識 class type。
唯,物件的辨別稍微麻煩;目前為止,我只想到 android:tag="..." 來加以利用。

另外,過去維護大型系統或 class 較多的 project 時,多半不開啟 [Build Automatically] 功能;但 Android project 則是必要的,因為 layout file 任何的異動,會由 Android 的 builders 來產生新的 R class,以便在 activity class 中進行 reference。
而 resource files 之間,字串 id 的參考最為常見,所以 res/values/strings.xml 維護更需要 [Build Automatically] 功能的運作。

2011年11月29日

Groovy 的 inspect() 及 Eval.me() 應用

在 Groovy console 中, 我們常測試物件的 API,例如:
def m = [a:"A", b:"B"] 
println m
而 Map 物件 m 會呈現(display):
    [a:A, b:B]
因為預設情形下是使用 toString() method。 然而有一種情形,要試著將這樣子的 String 內容轉回 Map 物件,那勢必得先讓這個 String 呈現為:
    [a:"A", b:"B"]
    ["a":"A", "b":"B"]
這時 inspect() method 就派上用場了:
println m.inspect()
它會呈現:
    ["a":"A", "b":"B"]
只要使用 Eval.me(),就可以再創造出 Map 物件了。再如下例:
Eval.me(MyEnum.ordinals().collect{"${it}:'${MyEnum.salvage(it)}'"}.inspect())

不過,這裡 Map 中 key 及 value 的型別是 String (未用引號或使用單引號) 而不是 GString。

2011年6月20日

Groovy 的 inject() method 應用

很多時候撰寫 Java 程式處理多筆資料,大多會以 Map 的型式在呈現。應用 iteration 的技巧將 DO 轉為 TO,不外乎使用 for / while loop。

而在 Groovy 的領域,則可以使用 inject() method; HA.KI blog 中先展現了 inject() 在數值加總的應用外,又示範將 List 物件轉為 Map 的技巧:
def persons = [
    new Person(username:'mrhaki', email: 'email@host.com'),
    new Person(username:'hubert', email: 'other@host.com')
]

def map = persons.inject([:]) { result, person ->
    result[person.username] = person.email
    /*return*/ result
}
在 result 的增設上, 可以使用下列的技巧:
    result << [(person.username): person.email]

    result += [(person.username): person.email]
如此, 連最後一行的 result return 都可以省了:
def map = persons.inject([:]) { result, person ->
    result << [(person.username): person.email]
}

2011年6月1日

Grails 編譯時的中文編碼問題

暨上篇 UnsupportedClassVersionError 問題之後; 另外在程式中的中文編碼部份, 以過去常用的方法來進行編譯:


不過呢, 在 Grails v1.3.7 版本中沒有發生作用。但研究後發現了 ${GRAILS_HOME}/scripts/_GrailsClasspath.groovy
...
compConfig.sourceEncoding = "UTF-8"
...
將它改為 Big5 後去測試 ~~~ 一樣沒有作用。於是我就
>grep 'encoding' *.groovy
發現原來編碼早已固定為 UTF-8 了。所以呢, 就想到了去變更 ${GRAILS_HOME}/scripts/
_GrailsCompile.groovy 與 _GrailsPackage.groovy :
ant.groovyc(
    ...,
    encoding: System.getProperty("file.encoding","UTF-8"),
    ...)

javac(
    ...,
    encoding: System.getProperty("file.encoding","UTF-8"),
    ...)
這樣子, 生活又變得美好了。

2011年5月4日

Grails project 發佈時 UnsupportedClassVersionError 問題

經歴過 Grails v1.0.4 / v1.0.1 / v1.3.7 等版本, 也用過 Eclipse + Groovy plugin 工具; 對於開發軟體的過程而言, 並不會跳脫指令的使用。像是 create-controller ... 等, 這不過是 terminal 模式與 [External Tools] 的 launching 方式不同。當然, 這些是環境變數 JAVA_HOME、GRAILS_HOME ... 等(範疇), 在工具外或工具內的應用而已。

對於寫過 Eclipse plugin 的人, 像是 STS v2.5.x 這樣的工具, 就像是把部份的指令模式做成 context menu; 用起來當是比先前用 [External Tools Configuration] 方便許多; 但是為解決 "linked resource" 問題, SpringSource.com 將功能做在 v2.6.0 版本之中。雖然問題克服了, 但相對上使用這樣更新一版的 IDE 工具, 無形之中已經改用了不同版本的 groovy ; 可能存在著一些編譯的風險跟問題。

除此之外, 在新版的 Grails 中, 編譯 script 用到不同版本的 ANT; 對於已熟悉 Eclipse 的設定、或慣用 ANT script 的人來說, 控制編譯的版本 (source / target options), 似乎不能一下了解新版的運作情形。最常見的就是使用 Java 6 的 JDK (通常會去控制 Eclipse / project 設定 / ANT build file 等), 經過工具的 packing 並 deploy 至 Java 5 run-time 環境時, 會發生 UnsupportedClassVersionError !

解決的方法, 如同這篇的敍述, 是去變更 grails 安裝目錄下的 build.properties。

但, 我們所知道的是, ANT 這樣子的工具是支援 system properties 的; 也就是說, 可以在進行編譯 script 時加 VM options , 就可以變更 system properties。所以, 可以在 STS v.2.6.0 的 context menu 操作時輸入相關 options, 如下所示:







不過試過之後, 並沒有發生作用。也許之前的版本可以, 但沒有多餘的時間去測試了。

2011年5月3日

OS X 的 Fax modem 安裝

曾經因為軟體開發而測試 windows 平台的刷卡機, 但因使用 MacBook 而尋求 solution 時, 買了 RS232 轉 USB 的連接線 (RS232 頭接在刷卡機); 主要的方法是建立一個 windows 的 VM, 並分享這個 USB device 給它。

當時買的時候很怕買錯, 經 survey 後決定買了 FTDI 相容的連接線, 也順利地安裝、分享給 VM; 並且, 在 Mac 上寫好的 Java 程式能很順利偵測及接收自 windows VM 傳過來的訊號。 當然, 除了沒影響工作之外, 正好有傳真的需要而開始 K 資料, 依這篇 設定 printer/fax 的方法來設定 fax modem, 將可以算是古董的 56K/v.92 modem 利用 9pin轉 25pin 的接頭接上, 並順利使用列印傳真功能。

正當這一切是如此美好; 索幸工作之需而取得新的 MacBook Pro, 有很多工作上的檔案都移至新機來作業; 但不巧的是, 這份美好只留給 v10.4 的 Tiger 而不是 v10.6 的 Snow Leopard。
可惜我不是 Mac Geek, 沒法 K 懂一些 port 文, 殘念!只好需要傳真時, 回頭使用那台 MacBook 了。

2011年5月1日

Groovy 中 Map 的新增操作

延續前一篇 Groovy中Map的鍵值型別, 就 Map 物件的新增操作也需小心處理。

通常在做記憶體的複製處理時, 將必要的資料以鍵值識別存放在 Map 物件之中,
所以操作時常會使用:
def container = [:]
...
container += [ "${string_object}" : some_object ]
...
但, 我們知道 "${string_object}" 實為 GString, 而不是 String; 在存取 Map 時就可會找不到物件。
所以, 可以的做法是使用 API 的方式來解決:
...
container.put(string_object, some_object)
...

2011年1月11日

Mac OS X - 倉頡輸入法字根查詢

對於常被問到 Mac OS X 的平台轉換與使用的經驗, 我總是回答這個作業系統如此、如此、這般、這般的美好; 尤其我從事的是 Java 軟體開發, 並沒有太多各種平台間的差異。
但由於使用過 Linux 一些時日, 有機會接觸到與以前 Windows 平台竭然不同的經驗, 那就是: 輸入法, 無論是輸入方式或者是程式控制。當然, 在 Mac OS X 的環境裡也必然有著明顯的不同。
過去年代進入電腦領域的人, 很多使用了倉頡輸入法做為文件的編寫工具, 但輸入法對於拆解字型「形」的部份, 隨著這些年字體的修正而有了幾代的改變, 也就直接影響了字根的組合。
在學過倉頡輸入法 N 年後, 並不會回頭去重新檢視這期間有多少的差異, 然而在使用不同作業系統的當下, 面對這些改變確實讓我拆解不了一些文字已熟識的字根。於是, 免不了要利用其他像是注音輸入來查得它倉頡的字根。
在 Snow Leopard 中以「面」字來說,
首先切換到「注音輸入法」,
接著進入到 Find Input Code 功能:
輸入要查詢的字, 系統接著呈現結果; 而倉頡輸入法(Cangjie)當然也在其中:
That's all.