GroovyとJavaScriptのクロージャ
よく見るカウンタのクロージャをGroovyとJavaScriptで書いてみる。
Groovy版
def clo() { def i=0 return { i++ } } def a = clo() println "a():${a()}" // a():0 println "a():${a()}" // a():1 println "a():${a()}" // a():2 def b = clo() println "b():${b()}" // b():0 println "b():${b()}" // b():1 println "b():${b()}" // b():2 println "a():${a()}" // a():3 println "b():${b()}" // b():3
function clo() { var i=0; return function(){ return i++; }; } var a = clo(); console.log("a():" + a()); // a():0 console.log("a():" + a()); // a():1 console.log("a():" + a()); // a():2 var b = clo(); console.log("b():" + b()); // b():0 console.log("b():" + b()); // b():1 console.log("b():" + b()); // b():2 console.log("a():" + a()); // a():3 console.log("b():" + b()); // b():3
メソッド(関数)を定義しない(という表現で良いのだろうか?)場合は以下のようになる。
Groovy版
def clo = { def i = 0 return { i++ } } def a = clo() println "a():${a()}" // a():0 println "a():${a()}" // a():1 println "a():${a()}" // a():2 def b = clo() println "b():${b()}" // b():0 println "b():${b()}" // b():1 println "b():${b()}" // b():2 println "a():${a()}" // a():3 println "b():${b()}" // b():3
var clo = function(){ var i=0; return function(){ return i++; }; } var a = clo(); console.log("a():" + a()); // a():0 console.log("a():" + a()); // a():1 console.log("a():" + a()); // a():2 var b = clo(); console.log("b():" + b()); // b():0 console.log("b():" + b()); // b():1 console.log("b():" + b()); // b():2 console.log("a():" + a()); // a():3 console.log("b():" + b()); // b():3
[Groovy]追記(2012/01/11)
よくわかってないけどこうかくとエラーになる。
def clo() { x -> return { x++ } }
「->」の前に書かれたものはパラメータになるらしい。
def clo = { x -> return { x++ } } def a = clo(1) println "a():${a()}" // a():1 println "a():${a()}" // a():2 println "a():${a()}" // a():3
パラメータなしで呼び出すとエラー
def clo = { x -> return { x++ } } def a = clo() println "a():${a()}" // java.lang.NullPointerException
初期化すれば大丈夫
def clo = { x=0 -> return { x++ } } def a = clo() println "a():${a()}" // a():0 println "a():${a()}" // a():1 println "a():${a()}" // a():2 def b = clo(9) println "b():${b()}" // b():9 println "b():${b()}" // b():10 println "b():${b()}" // b():11
また、引数が一個以下なら「->」を省略可能
とあるが、
def clo = { return { x++ } } def a = clo() println "a():${a()}" // groovy.lang.MissingPropertyException
となるのはわかる。xが宣言されていないから。
ただ暗黙変数itで書いたこれが何でエラーになるのかが全然わからなかった。
def clo = { return { it++ } } def a = clo() println "a():${a()}" // java.lang.NullPointerException //def a = clo(1) //println "a():${a()}" // java.lang.NullPointerException
ちなみにこれもエラーだった。
def clo = { it=0 -> return { it++ } } def a = clo() println "a():${a()}" // java.lang.NullPointerException //def a = clo(1) //println "a():${a()}" // java.lang.NullPointerException
結果、いろいろ試したら何となくわかった。
def clo = { return { it } } def a = clo() println "a():${a()}" // null def b = clo(4) println "b():${b()}" // null
retrunで返却されるクロージャの中のitはa(とかb)の実行時の引数を見ていたらしい。
def clo = { return { it } } def a = clo() println "a(1):${a(1)}" // 1 def b = clo(4) println "b(7):${b(7)}" // 7
参考になりました。
http://groovy.codehaus.org/Japanese+Closures
groovyクロージャについて徒然と - uehaj's blog
JavaからGoogle Spreadsheetを参照する
以下を参考にGoogle Spreadsheetのデータを参照してみた。(ほぼそのまま)
GData APIでGoogleスプレッドシートを参照するには (1/3):Spreadsheets Data APIを使うための基礎知識(1) - @IT
https://sites.google.com/site/niusounds/programming/google-data-apinyuumon
本当にそのままコピーして自分のusername/passwordを設定し実行したらエラーになった。
公開範囲の影響(?)なのか分らなかったので自分でデータを作った。
使用したデータはこれ。
https://docs.google.com/spreadsheet/ccc?key=0AkxY01rLRjOfdElOZ3B0YXhQZjk0QkpWYnlPQmNaRkE
SpreadsheetSearch.java
package sample; import java.io.IOException; import com.google.gdata.client.spreadsheet.FeedURLFactory; import com.google.gdata.client.spreadsheet.ListQuery; import com.google.gdata.client.spreadsheet.SpreadsheetQuery; import com.google.gdata.client.spreadsheet.SpreadsheetService; import com.google.gdata.data.spreadsheet.CustomElementCollection; import com.google.gdata.data.spreadsheet.ListEntry; import com.google.gdata.data.spreadsheet.ListFeed; import com.google.gdata.data.spreadsheet.SpreadsheetEntry; import com.google.gdata.data.spreadsheet.SpreadsheetFeed; import com.google.gdata.data.spreadsheet.WorksheetEntry; import com.google.gdata.util.ServiceException; public class SpreadsheetSearch { /** * @param args */ public static void main(String[] args) throws IOException, ServiceException { // このアプリケーションの名称。任意の名前を設定 String applicationName = "com-SpreadsheetSearch-1"; // Google AppsもしくはGoogleアカウントのメールアドレスとパスワードを設定 String username = ""; String password = ""; // Spreadsheetsサービスへの認証を行う SpreadsheetService service = new SpreadsheetService(applicationName); service.setUserCredentials(username, password); // 検索対象のスプレッドシートを取得 FeedURLFactory urlFactory = FeedURLFactory.getDefault(); SpreadsheetQuery spreadsheetQuery = new SpreadsheetQuery(urlFactory .getSpreadsheetsFeedUrl()); spreadsheetQuery.setTitleQuery("検索データ"); // 検索対象のスプレッドシート名を指定している SpreadsheetFeed spreadsheetFeed = service.query(spreadsheetQuery, SpreadsheetFeed.class); SpreadsheetEntry spreadsheetEntry = spreadsheetFeed.getEntries().get(0); System.out.println("名前:" + spreadsheetEntry.getTitle().getPlainText()); // 検索対象のワークシートを取得 WorksheetEntry worksheetEntry = spreadsheetEntry.getDefaultWorksheet(); // ワークシート内を検索 ListQuery listQuery = new ListQuery(worksheetEntry.getListFeedUrl()); // listQuery.setSpreadsheetQuery("HEADER1 = HEADER1-1"); エラーになる // listQuery.setSpreadsheetQuery("header1 = HEADER1-1"); エラーになる listQuery.setSpreadsheetQuery("header1 = \"HEADER1-1\""); // OK // listQuery.setSpreadsheetQuery("\"HEADER1\" = \"HEADER1-1\""); ダメでした // listQuery.setSpreadsheetQuery("\"header1-9\" = \"HEADER1-1\""); // OK ListFeed listFeed = service.query(listQuery, ListFeed.class); ListEntry listEntry = listFeed.getEntries().get(0); CustomElementCollection elements = listEntry.getCustomElements(); System.out.println("HEADER1:" + elements.getValue("HEADER1")); System.out.println("HEADER2:" + elements.getValue("header2")); System.out.println("HEADER3:" + elements.getValue("header3")); } }
実行結果
名前:検索データ HEADER1:HEADER1-1 HEADER2:HEADER2-1 HEADER3:HEADER3-1
よくわからなかった点
(1)検索時はカラム部分に大文字が使えない?
Spreadsheet上ではカラムをHEADER1と記述しているのにsetSpreadsheetQueryの部分でHEADER1と記述するとエラーになる。
小文字でheader1と記述すると大丈夫だった。
そのわりにはgetValue("HEADER1")でちゃんと値がとれる。
名前:検索データ Exception in thread "main" com.google.gdata.util.InvalidEntryException: Bad Request Parse error: Invalid column name: HEADER1 at com.google.gdata.client.http.HttpGDataRequest.handleErrorResponse(HttpGDataRequest.java:594) at com.google.gdata.client.http.GoogleGDataRequest.handleErrorResponse(GoogleGDataRequest.java:563) at com.google.gdata.client.http.HttpGDataRequest.checkResponse(HttpGDataRequest.java:552) at com.google.gdata.client.http.HttpGDataRequest.execute(HttpGDataRequest.java:530) at com.google.gdata.client.http.GoogleGDataRequest.execute(GoogleGDataRequest.java:535) at com.google.gdata.client.Service.getFeed(Service.java:1135) at com.google.gdata.client.Service.getFeed(Service.java:1077) at com.google.gdata.client.GoogleService.getFeed(GoogleService.java:662) at com.google.gdata.client.Service.query(Service.java:1237) at com.google.gdata.client.Service.query(Service.java:1178) at sample.SpreadsheetSearch.main(SpreadsheetSearch.java:48)
(2)setSpreadsheetQueryでハイフンを入れるとエラー
文字通りハイフンを入れて検索を行ったらエラーになった。
ただアンスコ(_)は大丈夫だった。
// ワークシート内を検索 ListQuery listQuery = new ListQuery(worksheetEntry.getListFeedUrl()); // listQuery.setSpreadsheetQuery("HEADER1 = HEADER1-1"); //エラーになる // listQuery.setSpreadsheetQuery("header1 = HEADER1-1"); //エラーになる listQuery.setSpreadsheetQuery("header1 = \"HEADER1-1\""); // OK // listQuery.setSpreadsheetQuery("\"HEADER1\" = \"HEADER1-1\""); //ダメでした // listQuery.setSpreadsheetQuery("\"header1-9\" = \"HEADER1-1\""); // OK(header1-9というカラム名にした場合)
名前:検索データ Exception in thread "main" com.google.gdata.util.InvalidEntryException: Bad Request Parse error: null at com.google.gdata.client.http.HttpGDataRequest.handleErrorResponse(HttpGDataRequest.java:594) at com.google.gdata.client.http.GoogleGDataRequest.handleErrorResponse(GoogleGDataRequest.java:563) at com.google.gdata.client.http.HttpGDataRequest.checkResponse(HttpGDataRequest.java:552) at com.google.gdata.client.http.HttpGDataRequest.execute(HttpGDataRequest.java:530) at com.google.gdata.client.http.GoogleGDataRequest.execute(GoogleGDataRequest.java:535) at com.google.gdata.client.Service.getFeed(Service.java:1135) at com.google.gdata.client.Service.getFeed(Service.java:1077) at com.google.gdata.client.GoogleService.getFeed(GoogleService.java:662) at com.google.gdata.client.Service.query(Service.java:1237) at com.google.gdata.client.Service.query(Service.java:1178) at sample.SpreadsheetSearch.main(SpreadsheetSearch.java:50)
どうにかならないものかと適当に""でくくってみたら大丈夫だった。
ただカラム部分を大文字にして""でくくってみても駄目だった。
まとめ
- 検索時はカラム部分を小文字にする。
- ハイフンを使うときは""でくくる。
Groovy版
参考にしました。
Java使いをGroovyに引き込むサンプル集 - No Programming, No Life
Eclipseで作成。
手順
01.Groovy Projectを作成(Google Spreadsheetを参照するにあたって必要なjarも設定する)
02.SpreadsheetSearch.groovyを作成
03.SpreadsheetSearch.javaのmainメソッドの中をコピー
04.SpreadsheetSearch.groovyのmainメソッドに3.でコピーしたコードを貼り付け
05.ctrl+shift+oでインポートの編成
ここまででひとまず動いた。*1
06.行末のセミコロンを削除
07.String等の型をdefに変更する
08.ctrl+shift+oでインポートの編成
09.インポートするクラスに別名をつける
10.別名をつけたクラスに変更する
11.ちょっと手を加える
SpreadsheetSearch.groovy(コメント部分は削除)
package sample import com.google.gdata.client.spreadsheet.FeedURLFactory as FUF import com.google.gdata.client.spreadsheet.ListQuery as LQ import com.google.gdata.client.spreadsheet.SpreadsheetQuery as SQ import com.google.gdata.client.spreadsheet.SpreadsheetService as SS import com.google.gdata.data.spreadsheet.ListFeed as LF import com.google.gdata.data.spreadsheet.SpreadsheetFeed as SF class SpreadsheetSearch { static main(args) { def applicationName = "com-SpreadsheetSearch-1" def username = "" def password = "" def service = new SS(applicationName) service.setUserCredentials(username, password) def urlFactory = FUF.getDefault() def spreadsheetQuery = new SQ(urlFactory.getSpreadsheetsFeedUrl()) spreadsheetQuery.setTitleQuery("検索データ") def spreadsheetFeed = service.query(spreadsheetQuery, SF.class) def spreadsheetEntry = spreadsheetFeed.getEntries().get(0) println "名前:${spreadsheetEntry.getTitle().getPlainText()}" def worksheetEntry = spreadsheetEntry.getDefaultWorksheet() def listQuery = new LQ(worksheetEntry.getListFeedUrl()) listQuery.setSpreadsheetQuery("header1 = \"HEADER1-1\"") def listFeed = service.query(listQuery, LF.class) def listEntry = listFeed.getEntries().get(0) def elements = listEntry.getCustomElements() println "HEADER1:${elements.getValue("HEADER1")}" println "HEADER2:${elements.getValue("header2")}" println "HEADER3:${elements.getValue("header3")}" } }
もっと簡単に書けると思うけど知っている知識ではここまで。
名前の付け方によるかもしれないが別名インポートを使うと分かりにくくなりそう。
for-loopのメモ
こういう書き方も出来るんだ。
package forloop; public class ForLoop { public static void main(String[] args) { for (int i=0,j=0;j<10;System.out.println(j),j=i,System.out.println(j)) { System.out.println("(^^)"); i++; } } }
出力結果
(^^) 0 1 (^^) 1 2 (^^) 2 3 (^^) 3 4 (^^) 4 5 (^^) 5 6 (^^) 6 7 (^^) 7 8 (^^) 8 9 (^^) 9 10
エンジニアの未来サミット 0905 エンジニア・サバイバルの感想
- 【第一部】おしえて!アルファギーク ―エンジニアが幸せになる方法
- 面白かった。
- 【第二部】弾 vs. 個性派エンジニア ―サバイバル討論
- 楽しかった。
第一部でひがさんが言っていた、「会社で評価されなかった=自分には今の仕事が向いていない」という考えに違和感があった。
向いているか向いていないかの判断は自分でするのが当たり前だという考えがあったからだと思う。
ただ、向いているか向いていないか、自分自身でも分からなくなった場合の一つの判断基準として参考になった。