認証系のgemをちょっと見てみた

はじめに


だいたいのwebサービスにはユーザー登録をしてはじめて使用することが多いと思います

ご多分にもれずに、これから実装しようとしたものでメンバースキルを鑑みるとRailsという形ですすむことになりました。

では、Railsでアプリを書くときに認証系のgemって、今は何が使えるものだろうかということを軽く見てみました。

# ちょっと実装してよと軽く言われるものの困ったものですorz

RubyToolboxを眺める


自分の個人内の観測範囲でよく聞くもの

  • warden
  • devise
  • Authlogic
  • Sorcery
  • doorkeeper
  • OmniAuth

# provider提供も関係無く書いてますが、話と毛色が違う感あるのでこの後は出てきません

メンテ厳しいらしいもの


この2つの模様

  • Authlogic
  • Sorcery(Currently Sorcery project is not actively maintained.という文章がREADMEにあった)

PR眺める限り、Authlogicは対応させようと頑張っている模様 Sorceryは、ちょっと厳しそうかな(とはいえ、一応動く&issueとPRをあげたら対応自体はしてくれる模様)

devise&warden


changelog見ると、
4.0.0rc1からRails5に対応していました
流石ですね。

# が、多機能で便利でいいのですが癖が強いのとdeviseのレールから外れた瞬間悲惨な目に遭うので避けたいところ

他に無いか?


個人的に良さそうかなと思ったのは、monbanですかね。
(ちょっとgithubのスター数が少ないのは気になりますが・・・)

Rails使ってるなぁと思ってみたら、殆どconcern(helper)と初期ロード&設定(railtie&configure)だけだった模様
案外Railsのアップデート影響も少なそうな印象でした。

実装や設定内容を読む限り、拡張の幅も広いので好印象でした
実際、Rails5でカスタム実装してみましたが問題なく認証させることができました

肌感&経験上ですが、認証機能自身はサービスによって独自の仕様、または既存機能との併用となることが多いので
拡張しやすいgemの方が対応のさせやすさ、メンテナンスさせやすいほうがやりやすいかなと思ってます

そういう意味では、(余計な機能が無いという意味で)軽量かつ、拡張可能、機能の置き換え可能なmonbanはいいなと思いました

# ぶっちゃけ、monbanカワイイよってことだけが言いたかったw

Gitのブランチ系コマンドでよく使うもの

はじめに


たまになんだっけ?ってなるものがあるのでメモしておく
基本的に削除系

ブランチ作成


普通に作る

1
$ git branch hoge

別のやり方

1
$ git checkout -b hoge

ローカルブランチの削除


マージ済みのものを削除

1
$ git branch -d hoge

マージされていないものを強制削除

1
$ git checkout -D hoge

リモートブランチの削除


pushの逆をするだけ

1
$ git push origin :hoge

マージ済みブランチの探索


こんな感じで難しくない

1
$ git branch -r --list --merged

オプションを変更するだけで、未マージも見つかる

1
$ git branch -r --list --no-merged

リモートブランチとの同期


誰かがリモートブランチが削除したとしても、その前にfetchしていたら自分のローカルブランチには残っているので同期をする
これは、放置しておくとよく忘れるやつ

1
$ git remote prune origin

# ぶっちゃけ、よく忘れる一番最後のだけ書きたかった

Kotlin 1.0リリース記念勉強会 in 京都に行ってきた

はじめに


界隈の情報を収集しておきたかったので行ってきました

結論的なところを言ってしまうと、
もうプロダクトに放り込んでも良さそうという印象でした
(kobaltやKotolin for JSのようなエコシステムはまだまだですが・・・)

とはいえ、多少は混ぜるな危険(nullとか)もあるようなので
ビジネスロジックデータクラス(所謂JavaBeanとか)からやり進めたほうがいいかなという感覚です
(swiftでobj-C混ぜて大変なことになったのは、大体一年前の話w)

AndroidだとActivityとかコアなところをやるのではなくロジック周りからかな
# 新規に作る場合、その限りではない

JetBrainsさん、ロードマップ出すぐらいに本気!!
(大したことでは無いが唯一の懸念としてあるとすれば、Androidに限ればGoogle本家のサポートでは無いというところぐらいかな)

SIerアーキテクト視点でみたKotlinの紹介


期待

  • 新しく覚えることを少なくできる
  • 一番期待しているのは後方互換性(コンパイラは古いバイナリを使える)

機能

  • NullSafe(no-null type / nullable type)
    • 言語レベルでnull safeサポート
    • Java8のOptionalは使い勝手がよくなかった(バッドコードが生まれやすかった)
  • Dataクラス
    • valueオブジェクトとして使ったほうがよい
  • smartcast
    • ソースの文脈で、判断してくれる
    • 型分岐で処理するのがやりやすい(instanceof & キャストしなくていい)
  • extension
    • 既存クラスを拡張することが可能
      • swiftとだいたい同じ
  • delegation
    • インターフェースだけ可能
    • 移譲プロパティ
      • 遅延評価とか可能
  • 演算子のオーバーロード
    • BigDecimapを演算子で計算可能

まとめ

  • 実用的で使いやすい
  • 後方互換性がある(サポートすることを名言している)
  • webで勉強できる

kotilinはじめました


  • scalaとかswiftやってれば似ているのでやりやすい
  • scalaのoptionalとkotolinのnull safeは似ているようで微妙に違う
  • scalaからbetter javaを抜き出してシュリンクした感じ
  • 言語仕様が少ないので覚えやすい
  • scalaの入り口にはなりやすい(基本構文が似ていることがいい)
  • swiftっぽい感(構文似ているけど、違うことはそれなりにある)
  • ?:はエルビス演算子(scalaのgetOrElse)って言うんだよ!

kotlinとjavaee


  • インジェクションがちょっと面倒そう(明示的に)
  • none null型にはcdiで注入するのが面倒
    • コンストラクタで初期化するとか
    • lateinit修飾子をつけるとか工夫が必要
  • JAX-RSはjavaのコードをそのままで
    • 継承するためにopenアノテーション必要
  • JPA
    • static fieldはcompanionオブジェクトにする(static backing field)
  • 混ぜるな危険はあんまり無さそう
    • どう書くかというのは悩むことは非常に多いかも
  • 少しずつkotolinに置換は現実的かも
  • 古いドキュメントが多いので注意

springboot + kotlin


  • springbootでkotlinが使えるようになった模様
  • DIはlateinit使え!
  • JRebel(ホットスポットVMかな)
    • 問題無く動く
  • Spring AOP
    • finalになっているのでopenにすることが必要
    • @Beanはfunc hoge() = “hoge”でかけるとおもいきやopen
  • getter/setter書かなくてよいのですっきり
  • none null対策にはいい
    • @NonNullアノテーションは書かないやつでてくるので、none nullを強制できる

kotlinとモダンライブラリを使ってアプリを作る


  • dagger2と相性良さそう
    • そこそこ記述量が減ってる
    • 登壇者もActivity書いたりやcontextの引き回しは気になる模様
  • databinding
    • プロパティクラス使えばいい
    • java同様に普通に使える
    • lazyやnone null、delegateでデータ作らないと表示されないかも
  • property observer
    • 変更監視可能なプロパティ
    • ListViewとかで有効
      • データが更新される
  • binding adapter
    • JvmStaticアノテーションでstaicなメソッドになる
  • value converter
    • kotolinでは使えなかった模様
    • javaで書くしかない
  • JetBrainのankoというライブラリが素敵
    • context, serviceとかに便利拡張がある
    • dslはデータバインディングと組み合わせは辛い(相性があまり良くない模様)
  • ハマりどころあるものの大体使える
    • Javaのライブラリもそのまま使える模様

Kotlinこんなん出ましたけど


  • kotlin as JS
    • JVM側はメジャーリリースで仕様が大体固まった
    • JSはもうちょい変更入る
  • kobalt
    • gradleライク
    • kobaltプロジェクトを参考するといい模様
    • ドキュメント生成可能だけど、フォーマット
  • エコシステムも作ろうとしている模様
    • Androidだけに注力している訳ではない

Dataクラスから始めるKotlin / JetBrains行ってきたよ!


  • groovy柔軟性を引き換えにパフォーマンスと型安全が犠牲
  • scalaは別の世界
  • kotolinはスムーズ
  • lombokプラグインは時々壊れる
  • データクラスからの以降がよい
  • ロジックに集中して、細かいところを以降していくといい
  • java to kotlinはたまに失敗することがある
    • コンバート後のコンパイルに失敗
    • 修正過程で勉強になるとポジティブに捉えるといいかも
  • Jankinsでビルドががが
    • サブモジュールの.ktが見つからない
  • 突然のillegalstateexception
    • javaの世界からnullが渡されると起きる
    • javaからも使うフィールドはnone nullにするか慎重になる必要
  • おしいところ
    • shift + commnad + enterが効かない
  • ゆるやかに以降できる
  • データオブジェクトとかビジネスロジックから手をつけて以降するのがオススメ

攻めるラムダ式禁止おじさん


  • 関数参照を使えば、ラムダ式を消せる
  • 引数を取らないものもできる
  • 引数を2つとるものは、かりー化
  • メソッド参照
  • java的なメソッド参照は使えないけど、かりー化使えば対応可能
  • ラムダ式をきちんと使う方向で・・・

Railsのリクエストヘッダーを調べる

はじめに


リクエストヘッダーの中身を見ようとしたときの備忘録
ヘッダーを利用してゴニョゴニョしてた時とかに使ってましたw

Railsのリクエストで一覧を取得


requestで来たhederの一覧を調べる場合、以下のコードをbefore_actionに仕込んでおく

1
request.headers.sort.map { |k, v| logger.info "#{k}:#{v}" }

特定のヘッダーの内容確認


HTTP_ACCEPTを見たい場合は、以下のコードをbefore_actionに仕込んでおく
(多分このコードはよく使うかも)

1
accept = request.headers['HTTP_ACCEPT']

利用可能なMIME Typeの確認

Railsで定義されているMIME Typeを観る場合は以下のコードを利用する
以下はjsonに対応したMIME Typeを確認するコード

1
2
Mime::EXTENSION_LOOKUP.each { |m| puts m}
Mime::Type.lookup_by_extension(:json)

sshでX11 Forwardingをsudoコマンド時に実施する方法

あったこと


表題のようにsshでX11 Forwardingでコマンドを実行したところ
下記のようなエラーになった

1
2
3
4
5
6
7
$ ssh -XY -l hoge xxx.xxx.xxx.xxx
$ sudo virt-manager
** (virt-manager:3166): WARNING **: Could not open X display
X11 connection rejected because of wrong authentication.
X11 connection rejected because of wrong authentication.
(virt-manager:3166): Gtk-CRITICAL **: gtk_settings_get_for_screen: assertion 'GDK_IS_SCREEN (screen)' failed
(virt-manager:3166): Gtk-CRITICAL **: _gtk_settings_get_style_cascade: assertion 'GTK_IS_SETTINGS (settings)' failed

どうやら認可が正しくできていない模様
(GTKのSCREEN系のエラーっぽく見えるところが、ややこしさに拍車かけてると思う・・・)

解決案


sudoコマンドを実行する際、Xauthorityを読み込むようにして実行する
(下記では、念の為xauthをインストールしている)

1
2
3
$ ssh -XY -l hoge xxx.xxx.xxx.xxx
$ sudo yum install xorg-x11-xauth
$ sudo  XAUTHORITY=~/.Xauthority virt-manager

強引に認可させているので、セキュリティ的に果たしてこれでいいのかという疑問は残りますね
何れにせよ、ローカルネットワーク内で実行するだけなのでこれでいいかなと。

GroovyでWALKMAN用のプレイリストコンバーターを作成した

はじめに


自分の楽曲管理なのですが、以下で行っていました

  • Macを使っている&元iPhoneユーザーのためiTunes
  • 現状はAndroidユーザーでXperiaZ3Compactを活用
  • iTunesとの連携にはiSyncrアプリでAndroidアプリを連携

ここ最近、残念なことにXperiaZ3Compactのイヤホンジャックが故障してしまいました
海外版SIMFree版のため、国内で修理することもできません。

部品を調達してきて、別途修理するか悩みましたがリスクが高い
(ネットで調べる限りだいたい、何かしらミスしたという話が多かったです)

仕方ないのでWALKMANを調達するとして、以下の条件で機種が無いかをしらべました

  • WALKMANであること
  • iSyncrアプリの恩恵を預かれること
  • microSDは活用してもいい
  • ある程度の運用は許容するので、何かしらのコンバーター(アプリorスクリプト)は実装してもよい

条件に合致するものであれば・・・

  • 高額機種のWALKMAN
  • Android WALKMAN(3~4年前)で売り出していたFシリーズ
  • microSDが使用しているNW-A20シリーズ

というわけで、機能面でも最新であることたお値段も含めて一番条件に合致するWALKMAN(NW-A25)を新たに新調することとしました
(Fシリーズは別途問題があったようなので却下にしました)

何故コンバーターが必要になったか


iSyncrで作成したプレイリストは、Android向けに最適化されたもののようなので、そのままではNW-A25では活用することができませんでした
(店頭に通って挙動を確認しました)

症状としては以下のような形です

  • プレイリストは認識するが曲が存在しない扱いとなる
  • プレイリストを通さない、ミュージック一覧では楽曲の認識と再生可能

何故こういう状態が起こるかというと、WALKMANはOSがAndroidではない為、ファイルパスの扱いが異なるようです
なので、改善として以下のようにしてあげれば、プレイリストから楽曲再生ができるようになりました
(こちらも店頭で確認)

変更前

1
2
3
#EXTM3U
/hoge/fuga.mp3
/hoge/fugafuga.mp3

変更後

1
2
3
#EXTM3U
hoge/fuga.mp3
hoge/fugafuga.mp3

つまり、うまく認識させるためには相互変換できるようなものがあればよいということになります

何故Groovy?


以下の打算があったので、Groovyでやってみました

  • iSyncrはAndroidアプリなので、コンバーターもAndroidアプリでやれば運用が楽になるのではないか
  • AndroidはJavaで動作し、JVM言語であるGroovyが動作することも確認取れている
  • GroovyはJavaよりもライトに(Clojureを活用してですが)ファイル変更処理を実装することができる
  • ライトにできるので実装モック作成も割りと早めにできるのではないか

が、結局Android上での外部ストレージ周りのファイル操作の挙動が変わってる(DocumentFileを通したファイル作成、変更がスクリプトと相性悪い為)ので
後述のスクリプト処理が活用しづらいのでアプリ内での変換処理は諦めました

なのでコマンドラインツールとして実装&運用する方向としました
(運用できなくなるのが困るので、多少の労力(SDの抜き差し回数が増える)ぐらいなら労力を割いてもいい方向にしました)

iSyncr向けのプレイリストからWALKMAN向けのプレイリストに変換


少し手間ですが、以下のような形をとりました

  1. WALKMAN向けのプレイリストファイルを作成する(この時点では一時ファイルとして)
  2. iSyncr向けのプレイリストファイルを開く
  3. iSyncr向けのプレイリストファイルの内容をWALKMAN向けのプレイリストファイルに書き込む
  4. このとき行の先頭文字が/で始まっている場合、空文字に置換
  5. ファイル名を正しいもの変更する
  6. iSyncr向けプレイリストは、識別可能なファイル名に変更
  7. 一時ファイルのWALKMAN向けのプレイリストファイルは、正しいプレイリストファイル名になるよう変更

これらを実装したものが以下になります

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
def isyncrToWalkman() {
  def sdCardDirPath = "/Volumes/WALKMAN/syncr"
  def files = new File(sdCardDirPath).listFiles()

  playList = files.findAll { it.getName() =~ /.*\.m3u$/ }
  if (playList.empty) {
    println "PlayList not found!"
    return
  }

  playList.each { file ->
    def playListName = file.canonicalPath

    def newPlayListName = "${file.canonicalPath}.new"
    def newPlayListFile = new File(newPlayListName)

    newPlayListFile.withWriter('UTF-8') { writer ->
      file.newReader().transformLine(writer) { line ->
        if (line.startsWith("/")){
          line.replaceFirst(/\//,"")
        } else {
          line
        }
      }
    }

    file.renameTo("${file.canonicalPath}.isyncr")
    newPlayListFile.renameTo("${playListName}")
  }
  println "Convert iSyncr To WALKMAN Complete!!"
}

WALKMAN向けのプレイリストからiSyncr向けのプレイリストに変換


こちらは以下を実装するだけでよいので簡単です

  1. WALKMAN向けのプレイリストを削除
  2. iSyncr用のプレイリストの名前を変更

上記を実装したものが以下になります

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
def walkmanToIsyncr() {
  def sdCardDirPath = "/Volumes/WALKMAN/syncr"
  def files = new File(sdCardDirPath).listFiles()

  def isyncrPlayList = files.findAll { it.getName() =~ /.*\.m3u.isyncr$/ }
  if (isyncrPlayList.empty) {
    println "PlayList not found!"
    return
  }

  def walkmanPlayList = files.findAll { it.getName() =~ /.*\.m3u$/ }
  walkmanPlayList.each { file -> file.delete() }

  isyncrPlayList.each { file ->
    def name = file.canonicalPath.replaceFirst(/\.isyncr$/, "")
    file.renameTo(name)
  }
  println "Convert WALKMAN TO iSyncr Complete!!"
}

コマンドライン部分


こちらはGroovyのBuilderを実装しているCliBuilderを活用しました これは、コマンドラインから実行する際、どちらの変換を実行するかを選択させるようにしたかった為です。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
def cli = new CliBuilder(usage:"PlayList Converter")
cli.w("Playlist : iSyncr TO WALKMAN")
cli.i("Playlist : WALKMAN TO iSyncr")


def opt = cli.parse(args)
if (opt.w) {
  isyncrToWalkman()
  return
}

if (opt.i) {
  walkmanToIsyncr()
  return
}
cli.usage()

コードみれば非常に簡単なのですが・・・

オプションにwを付けて実行すると、前述のiSyncrのプレイリストからWALKMAN向けのプレイリストに変換する処理を実施
オプションにiを付けて実行すると、前述のWALKMAN向けのプレイリストからiSyncrのプレイリストに変換する処理を実施
何もつけなければ、実行方法を表示するようになっています

運用


前提

  1. PCが認識するSDカードのパスが/Volume/WALKMANになるように設定
  2. 前述のコードをまとめたGroovyファイルをplaylist_converter.groovyとする
  3. sdkmanを使って、Groovyをインストール

運用手順

  1. iSyncrでAndroid上のSDカードとプレイリストを同期
  2. 同期完了後、AndroidのSDカードを取外しPCにSDを接続
  3. WALKMAN向けプレイリストになるように以下のコマンドで変換
  4. $ groovy playlist_converter.groovy -w
  5. WALKMANにSDカードをさして、ミュージックを楽しむ
  6. WALKMANからSDを取り外し、PCにSDを接続
  7. WALKMAN向けプレイリストになるように以下のコマンドで変換
  8. $ groovy playlist_converter.groovy -i
  9. AndroidにSDをさして、更にプレイリストの同期を実施

少し煩雑な感じもしますが、手作業でプレイリストを修正するよりも多少マシかなぁと思ってます
(実際に自分は運用できてます)

AndroidでGroovyを使ってみる

はじめに


現在常用のスマホとしてAndroid端末を使っています。
(つい半年前まではiPhoneを使っていました)

端末機としては海外版、XperiaZ3 Compactです。
(昨今の大型化している流れの中軽量かつ音楽プレイヤーとしても優れている機種として選定しました。)

元々iPhoneユーザーかつ環境が全てApple製品で統一されているので、音楽管理もiTunesで行っています。

そういう状況下であったので、iSyncrというアプリでiTunesのプレイリストと端末を同期させて利用していました

どうもXperiaZ3 Compact側のイヤホンジャック(ヘッドホンジャック)が壊れたようで、
音楽プレイヤーとしてはまともには利用できなくなりました

とはいえ、Youtubeを見て修理するのはリスクが高いのと、パーツが個人輸入になるので調達までのハードルが高いので修理方向は諦めました

が、どうも最近のwalkmanでは、microSDを使えプレイリストを少し調整すれば認識できるようなことを聞きつけました
(店頭モックでも、プレイリストを認識し再生可能であることを確認しました)
なので、microSDとの同期はiSyncrに任せ、同期したプレイリストの変更を独自のアプリでやればいいのではないかと思い今回やってみました

やりたいこと


まずはiSyncrで作ったプレイリストがウォークマンから認識できるかどうかを確認しました。
結論的に言うとそのままでは不可能で、一旦編集が必要のようです。

どうやらiSyncrを使ってiTunesの曲を転送したときは、iSyncrの作ったm3uプレイリストを正しく認識出来ないようです
これは、ウォークマン側のプレイリスト内のパスの解釈の問題のようです。
対処方法としては、パスの先頭の「/」を削除することで認識させることできます
(ウォークマン内部では、パスが補完されているのかもしれませんがその辺りは不明です)

こんな感じになるようにします

1
2
/hoge/fuga.mp3     -> hoge/fuga.mp3
/hoge/fugafuga.mp3 -> hoge/fugafuga.mp3

ということで実装としてやりたいことは至ってシンプルです

  • 編集後のプレイリストファイルを作成する
  • iSyncrで作成したプレイリストの内容を、ほぼそのまま編集後のプレイリストに書き込む
  • この時、行の最初の文字が「/」の場合、上記のように先頭の「/」を空文字に置換する

何故Groovy


Javaで書くと、以下の内容が面倒だったりするわけなのです

  • StreamだとかWriterやらReaderやらでコード自体が肥大化、冗長化すること
  • ファイルの中身の操作や置換とか結構大変で面倒

なので、今回その辺もサクッと実装できるGroovyで書いてみました

他にあるとすれば・・・

  • GroovyがAndroidでも動くということ
  • 置換検証用のコードをサクッと移植したかったこと
  • 個人的にGroovyでコード書くというリハビリ(書かなくなって久しいので)

当該Groovyコード


やりたいことを実施するファイルの置換用コードは以下のようになります

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
def files = new File('Your Path').listFiles()
playList = files.findAll { it.getName() =~ /.*\.m3u$/ }

playList.each { file ->
  def playListName = file.canonicalPath

  // 変更版プレイリスト
  def newPlayListName = "${file.canonicalPath}.new"
  def newPlayListFile = new File(newPlayListName)

  // 変更版プレイリストに現行プレイリストの修正内容を出力
  newPlayListFile.withWriter('UTF-8') { writer ->
    file.newReader().transformLine(writer) { line ->
      if (line.startsWith("/")){
        // 行の最初の文字の場合、「/」を置換する
        line.replaceFirst(/\//,"")
      } else {
        // それ以外の場合はそのまま出力
        line
      }
    }
  }

  // ファイル名を変更する
  file.renameTo("${file.canonicalPath}.old")
  newPlayListFile.renameTo("${playListName}")
}

本当であれば上書き保存という形にしたいところですが、
元のファイルが無くなってしまうと今度は同期が取れなくなる可能性があるので別ファイルとしました

GroovyをAndroidに導入


まずはGroovyのインストールをします。
以下のような形でsdkmanを使いましょう

1
2
3
4
$ curl -s http://get.sdkman.io | bash
$ sdk ls groovy
$ sdk install groovy 2.4.5
$ sdk use groovy 2.4.5

次にAndroidStudioでAndoridプロジェクトを用意します
Androidプロジェクトに対して、groovy-android-gradle-pluginを導入します

プロジェクトROOTにあるbuild.gradleを以下のようにします
(プラグインを導入するのみです)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
buildscript {
    repositories {
        jcenter()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:1.3.0'
        classpath 'org.codehaus.groovy:gradle-groovy-android-plugin:0.3.6'
    }
}

allprojects {
    repositories {
        jcenter()
    }
}

task clean(type: Delete) {
    delete rootProject.buildDir
}

次にアプリ側のbuild.gradleを変更します
(プラグインの適用と、コンパイルライブラリの追加、プラグインの設定追加)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
apply plugin: 'com.android.application'
apply plugin: 'groovyx.grooid.groovy-android'

android {
    中略
}

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    testCompile 'junit:junit:4.12'
    compile 'com.android.support:appcompat-v7:23.1.1'
    compile 'com.android.support:design:23.1.1'
    compile 'org.codehaus.groovy:groovy:2.4.3:grooid'
}

project.androidGroovy {
    options {
        configure(groovyOptions) {
            encoding = 'UTF-8'
            forkOptions.jvmArgs = ['-noverify'] // maybe necessary if you use Google Play Services
        }
        sourceCompatibility = '1.7'
        targetCompatibility = '1.7'
    }
}

ソースの配置を「src/main/java/MainActivity.java」から「src/main/groovy/MainActivity.groovy」変更します

最後にソースを以下のようにしてGroovyライクに実装します

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

@CompileStatic
public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        def hello = { lang ->
            def toast = Toast.makeText(this, "Hello ${lang}!", Toast.LENGTH_LONG)
            toast.setGravity(Gravity.CENTER, 0, 0)
            toast.show()
        }
        hello("Hello Groovy on Android!")
    }
}

一応いっておきますが、@CompileStaticアノテーションで静的コンパイルしなくても動作はします
が、動的コードはパフォーマンス的にきびしいので@CompileStatic推奨されているようです

ビルド時の注意点


Android Studioでビルドを実行したとき、エラーがあった場合以下のような形でEventLogに出力されてビルドが停止します。
メッセージを見ても、何が悪いか分かりません。正直、自分は困惑しました

1
2
3
4
5
6
7
0:52:06 Platform and Plugin Updates: The following components are ready to update: Google Play services, Google Repository, Android SDK Platform-tools
1:14:33 Gradle sync started
1:14:57 Gradle sync completed
1:14:57 Executing tasks: [:app:generateDebugSources, :app:generateDebugAndroidTestSources]
1:15:01 Gradle build finished in 4s 168ms
1:15:41 Executing tasks: [:app:generateDebugSources, :app:generateDebugAndroidTestSources, :app:compileDebugSources, :app:compileDebugAndroidTestSources]
1:15:47 ExternalSystemException: String index out of range: -105

そのときはGradle Consoleを確認しましょう
以下のような形でエラーメッセージが表示されています
(この場合、Syntaxエラーですね)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
:app:compileDebugJavaWithJavac UP-TO-DATE
:app:compileDebugGroovyWithGroovyc
startup failed:
MainActivity.groovy: 53: expecting ')', found '}' @ line 53, column 13.
               }
               ^

1 error


 FAILED

FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':app:compileDebugGroovyWithGroovyc'.
> Compilation failed; see the compiler error output for details.

* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output.

BUILD FAILED

Total time: 5.687 secs

因みに上記のような形になった場合、何故かそのままではビルドの再開が出来ませんでした。
対応としては一度「Clean Project」を実行する必要があります

結果的に・・・


ここまで読めば、分かる方はわかりますが実現はサクッとは出来ませんでした。

何故かと言うとAndroid4.4あたりから導入されたStorage Access Frameworkのことをスッカリ忘れていたのでやりたいことは出来ませんでしたorz

当初の運用自体は、iSyncrの同期先をSDカードにしてSDカードに対して同期
その後同期されたSDカードをPC側にマウントして、上記コードを通してやればよいので無理にAndroid経由させなくていいかなぁと思った次第です

とはいえGroovyでAndroidアプリを書いてみることはまぁできたのでよしとします。
GroovyでGroovy GDKの便利なAPIやクロージャの恩恵を最大限に受けてて、簡潔に書くことが出来て素晴らしいなと思いました

RubyKaigi3日目に行ってきた

The OMR GC Talk


OMRというランタイム

  • 多くの言語に対応している
  • (plugin機構で実現?)

調査はこれを使っていた模様 https://www.ibm.com/developerworks/jp/java/library/j-ibmtools5/

allocationを早くした

  • スレッドローカルヒープ
  • ロック無しでallocate

可変長のバッファを作る OMRのランタイム上で動作するGCがMRIに比べてよかった

GCのmark速度は早い(MRI)

OMR GCを確認するのはこれ https://github.com/rubyomr-preview/rubyomr-preview

Refinements - the Worst Feature You Ever Loved


method aliasとかモンキーパッチだと元の動きの振る舞いが全体に影響するからよくない

assertとかの振る舞いもかわってしまう

refinementsなら影響範囲を制御できる

スコープは働くので継承とかcalss_evalでも有効

文字列で与えたもので使えるeval ‘using SomeClass; hoge.fuga’みたいな感じなの

Discussion on Thread between version 1.8.6 and 2.2.3


Thread#status スレッドの状態が取れないような状況が起きた →mission crtalなシステムでも使えるThreadの使い方

  • 子スレッドでforを同期的に上がった場合
  • 同期的にraiseが上がった場合

Ruby2.2.3でも早くなったけど、CPU負荷も上がった 実行回数は変わらなかった

raiseのインスタンスは重い メモリ消費は少ない selectで対応することができる

早くなったけど、リソース消費も多いのでスレッドとかはメモリ消費量を意識したほうがよい

Plugin-based software design with Ruby and RubyGems


  • 多くの機能
  • コアコードがシンプル
  • testが簡単
  • developerコミュニティが活発

デザインパターン

  1. ホストアプリを拡張する(拡張ポイントを用意している、コールバックで実行)
  2. DIでプラグインを追加(I/Fとか決めてDIコンテナを置き換え、ホストからアプリを実行)
  3. 動的にプラグインをロードする方法
  4. 1と2を組み合わせる方法

プラグインのバージョンコントロール(依存ライブラリのコンフリクト解消)

fluentdは動的にpluguin emblukは組み合わせ

Actor, Thread and me


アクター

  • メッセージを適当なタイミングで送る
  • レシーブ
  • 仕事をする

破綻の予兆

  • 複数のイベントを待つ
  • DBへの問い合わせとか
  • 資源の協調

RubyKaigi2日目に行ってきた

はじめに


RubyKaigi2日目に参加してきました。

気になるセッションもチラホラあり期待していました

ただ、盛大に寝坊しましたorz

という訳で、メモ

Data Analytics Service Company and Its Ruby Usage


ミドルウェア * データ処理をする上でスループットが重要 * 一度書いたものはそのまま運用されるので、固めにつくることが多い

集めてくるところとか、加工整形した結果などは固くつくる必要はない (書捨ても多いから)

要素

  • データを集めて保存
  • 総うさするコンソr−るapi
  • データしゅべつ、型だとかのスキーマ管理
  • 計算処理(batch,query)-> Java
  • キューイングやスケジュール処理
  • データを格納&エクスポート

キューとワーカーの話

perfedtsched(スケジューラー) →SPOFのないcrontabと思えばよい →1回も実行されないよりも2回実行されたほうがよい(別途担保が必要だが・・・)

リトライ可能かは、状況やエラー内容による 実行時間 jobの実行内容が重いものやら軽いものまで

perfectqueue(キュー)

  • 優先どの高いキューは高いものは素早く処理
  • graceful restart(字工事のjobは分離して実行)
  • RDBMSのようなinsertで実現
  • RDS(MySQL)を使ってる

パフォーマンスコントロールとかでジョブ実行を制御している 安全側に倒している(顧客情報のisolationとか)

何故Rubyを使っているか

  • ワーカーのコードが複雑だけど重要
  • テストが一番重要なので、書きやすいのでrspecを採用
  • テストコードの書きやすさが重要だった(可読性とか、オーバーライドとか)
  • 新しい機能とか新しいライブラリは使っていく

スケジューラーとキュー気になる

Ruby for one day game programming camp for beginners


京大マイコンクラブで事例

Windowsの環境が殆どなので以下を実行するようにした

  • Ruby1.8.4(starter kit)
  • MyGame and Ruby/SDL(ゲーム用)
  • sakura editor

インストールして終わりぐらいの単純なものがよい

  • 講義みたいなことはしない
  • 1対1のペアプロ
  • 楽しいRubyが教本

プログラム未経験の参加者の8割が大体できる →やる気に繋がる →自信によって自分が勉強する

考察してみる

  • 教えかたが勉強できる
  • つくるものが決まっている
  • 締め切り
  • 教えるものが少ない(基本的な制御構造)

Ruby and PostgreSQL, a love story


plmruby zombodb

  • producael language handler(他の言語のサポート)
  • indexがすぐれてる(通常indexだけなく、elastic searchとかのラッパーにもできる)
  • foreginData(他にデータが投げられる, csvなりなんなりにdけいる)

postgresql fdl

  • callbackルーチンで駆動するライフサイクル(コールバックチェーンかな)
  • rubyがサポートする

holycorn

Rhebok, High Performance Rack Handler


Rhebok

  • rack handler
  • unicorn比較で1.5x
  • gazelle(perlnのpluck)の置き換え

使いドコロ

  • 高いトラフィックのあるところ
  • 最適化が進んでるところに最適(SNS, gameとか)
  • rackがネックになったとき

使えないところ

  • websocket
  • streaming
  • リバースプロキシかまさないといけない

性能

  • http1.1(keepaliveは未サポート)
  • unix socket
  • ホットデプロイ可能
  • rackアプリの起動でOK

Rack

  • 仕様(webserverとF/WをつなぐI/F)
  • middleware
  • Rack::Handlerの名前空間の下に同時実装をすれば自動認識できる

パフォーマンス上げる

  • マルチプロセス
  • マルチスレッド
  • IO多重化

timeoutの実現

  • IO.selectを使用する
  • pollを使うことで実現

parser

  • pico_http_parserに渡すように変更

tcp

  • tco_nodelayをオフにする
  • バッファリング遅延対策
  • tcpのやり取りが増えるのでフラグメンテーションいっぱい
  • 書き込み回数を1回にしておく

Pragmatic Testing of Ruby Core

テストを実行してみる テストが落ちた報告をするといい

Makefleにテストがなく、common.mkにある btest-ruby => bootstraptest sample/test.rbが通った後に実行(runner.rb経由で実行) make test-allなどは、標準ライブラリのテスト

make test-all TESTS=”-j4”すると並列で動く

test/ruby : 組み込み test/logger : 添付ライブラリ test/-ext- : C拡張

envutil.rb <- ヤバイ leakchecker.rb

rubyspecは現行の振る舞いだけしか書いてないので、 言語仕様ではない(by Matz)

ActiveRecord単体で使用した際に単一モデルにdefault_timezoneを設定する

はじめに


DBアクセスがあるような検証用のプログラムを書いたりするときってActiveRecord便利ですよね

このとき、timezoneの設定がうまくいって無くてすごく嵌ったので備忘録代わりにメモしておきます

設定方法


単純にこれだけです

1
2
3
class TestModel < ActiveRecord::Base
  self.default_timezone = :local
end

もしくはこちらでもよいかと

1
2
3
4
5
class TestModel < ActiveRecord::Base
  def self.default_timezone
    :local
  end
end

簡単でしたね