RubyMotionでのExceptionの謎(というか疑問
次のもくもく会などで聞いてみようと思うのでそのメモ&駄文
まずRubyでの実行結果
irb(main):001:0> begin; [1].fetch(1); rescue IndexError => e; puts e.class; end
IndexError
=> nil
irb(main):002:0>
次にRubyMotionでの実行結果
(main)begin; [1].fetch(1); rescue IndexError => e; puts e.class; end
2014-02-16 03:41:48.476 hello_world[3087:707] index 1 out of array (IndexError)
IndexError
=> nil
(main)>
Exceptionをキャッチしても2014-02-16 03:41:48.476 hello_world[3087:707] index 1 out of array (IndexError)
のような発生した際のメッセージは表示される。
個人的に、ちゃんとキャッチしてるのにメッセージが表示されていて気になったので。
ProMotion::TableScreenでViewCellにviewを追加する方法
ProMotion::TableScreenでは、デフォルトでTableViewで使うデータに追加したいviewをsubviewsというキーで含めておけば追加してくれます。
class MyScreen < ProMotion::TableScreen def table_data @table_data = [ cells: [ { title: 'cell 1', subviews: [label_1_1, label_1_2] }, { title: 'cell 2', subviews: [label_2_1, label_2_2] }, ] ] end end
label_1_1 label_1_2 等はViewCell中での表示位置や表示内容などを設定済み。
こうすることで、PM::TableScreenがcellを作成する際に、subviewsから追加するviewを拾ってaddSubviewしてくれます。
しかもdequeuereusablecellwithidentifierでcellが再利用される際、(度々大抵の人が陥るであろう)"再利用される前にaddSubviewされているview" あるいは "多重にaddSubviewしてしまう" 問題についても、PM::TableScreenがうまくremoveFromSuperviewしてから再度addSubviewしてくれるので安心です。
ProMotion gem すばらしい
しかし、cellへ追加したいviewのコードがScreen(ViewController)に書かなくてはいけないため、自分のコードが"糞コードの海"に沈みかねません。
そこでProMotionでは ProMotion::TableViewCell というUITableViewCellを継承してProMotionでViewCellをうまく扱うためのmoduleをincludeしたクラスが用意されてます。
例に、title(textLabel)もsubtitle(detailLabel)も使ってしまっているので、一つlabelを追加してcountを表示するViewCellを作ってみることにしましょう
今回はtable_dataのcellsにはsubviewsは使わずに、cell_classとcell_styleを追加し、それぞれ作成したMyTableViewCellとsubtitleを使うのでUITableViewCellStyleSubtitleを設定します。
あとは、MyTableVlewCellでsetupメソッドを上書きしてsuperを呼んでデフォルトの初期化処理をさせつつ、追加したいviewを準備した後に再度setup_subviewsを呼びます。
class MyScreen < ProMotion::TableScreen def table_data @table_data = [ cells: [ { title: 'cell 1', subtitle: 'sub title 1', count: 100, cell_class: MyTableViewCell, cell_style: UITableViewCellStyleSubtitle, }, { title: 'cell 1', subtitle: 'sub title 1', count: 0, cell_class: MyTableViewCell, cell_style: UITableViewCellStyleSubtitle, }, ] ] end end class MyTableVlewCell < ProMotion::TableViewCell attr_accessor :count def setup(data_cell, screen) super # super呼んで本来の初期化処理とかさせる1度目のset_subviewsも呼ばれる count_label = UILabel.new.tap do |label| # frameとかfontとか略 l.text = self.count end data_cell[:subviews] = [count_label] # data_cellはtable_dataのcellsの配列が1つ入ってる感じ set_subviews # 2度目のset_subviews self end end
この方法だと、"data_cell[:subviews] が(nilなので実質処理されないけど)、superにより1度に無駄に呼ばれる" などの無駄っぽい処理がありますが、ViewCellに関する処理が1カ所にまとめられるのは利点じゃないでしょうか。
以上、ProMotionのwikiにも書かれていないsubviewの追加方法でしたー
今gemを作るなら bundle gem より ore gem
jweler から移行して bundle gem で作られた(であろう) gem もよく見かけるようになってきたけれど、最近は ore gem が良い感じ
個人的に bundle gem の場合、テストケース関係のファイルが generate してくれないなど、今ひとつかゆいところに手が届かないなーと思っていたので、
bundle plugin みたいなのがあれば良いなーと思っていて作るかーとか思っていたのだけれど、その前にそれっぽい gem があることを発見。
$ mine example --bundler --rspec create lib create lib/example create spec create Gemfile create .gitignore create .rspec create spec/example_spec.rb create spec/spec_helper.rb create .document create example.gemspec create ChangeLog.rdoc create LICENSE.txt create README.rdoc create Rakefile create lib/example/version.rb create lib/example.rb run git init from "." run git add . from "." run git commit -m "Initial commit." from "."
うーん、rspec関係のファイルまで生成してくれる。すばらしい!
(--rspec 以外にも他のオプションもあるけど
あと gem project の generate 以外にもいろいろと出来るので、詳しくは ore gem のREADME見てみると良い感じ
.simplecov でSimpleCovの設定をスマートに
SimpleCov を使ってcode coverageを取るときに spec_helper.rb にこんな感じで書いていた
if ENV['COVERAGE'] # <= rake spec / rake coverage を分けたい派なので require "simplecov" SimpleCov.start :test_frameworks do add_filter "/vendor/bundle/" end end # 以下略 RSpec.configure do |config| # ここも略... end
プログラムのroot pathに .simplecov という名前のファイルを作り、SimpleCov の設定部分を書いてしまうことが出来るようになっているらしい (ということに気付いた
.simplecov
SimpleCov.start :test_frameworks do add_filter "/vendor/bundle/" end
ソースはここら辺
https://github.com/colszowka/simplecov/blob/master/lib/simplecov
/defaults.rb#L56
ElixirでDynamoのsample実行とExUnitを使ってみた
Shinjuku.ex第1回目ということで、新宿 Brooklyn Parlorにて、命の水ビールをぐびぐびしながら、6人ぐらいElixirについてもくもくしてきました。
ちなみに、チュートリアルが2つめなのは、チュートリアルをもくもくするのも良いけれど、動く物を試した用が良いよね!ってことでDynamoを動かそうと、なかなかうまく動くところまでいかなくて、途中で心が折れそうになり、横道反れた結果です。
あと、結論だけ書いてもおもしろくないので、失敗/躓いたところ多めで。
Dynamo を動かしてみる
必要なのは以下の3つ
- erlang
- rebar
- Elixir
erlang / rebar は、macならhomebrewから簡単にインストール出来る
(自分は、rebarがhomebrewにあるとは思ってなかったので、試行錯誤しました)
Elixir のインストールは Getting Started の 1.1.2 Manual install あたりを参照すれば良いかと
http://elixir-lang.org/getting_started/1.html
rebar というのは、erlangにおけるビルドツールらしい。makeやRubyのrakeみたいなもので、rebar.config というファイルにそのタスクが書かれているっぽい
$ git clone https://github.com/josevalim/dynamo.git $ cd ./dynamo $ make setup
make setup で dynamo が依存しているsubmoduleのセットアップとcompileを行う・・・が、普通に失敗する
$ make setup git submodule update --init # 中略 Compiled src/ibrowse_http_client.erl cd deps/cowboy && make make[1]: rebar: No such file or directory # ← ここら辺 make[1]: *** [deps] Error 1 make: *** [setup] Error 2
どうやら、deps/cowboy の make で rebarが無い模様
(homebrew等でインストールしてパスが通っていればこのエラーには遭遇しないはず。たぶん)
rebar がないので、もう一つのsubmoduleで依存しているdeps/ibrowse のrebarを拝借することに
$ cd ./deps/cowboy $ ../ibrowse/rebar get-deps $ ../ibrowse/rebar compile <|| これで cowboy の準備はokで、dynamo の make setup タスクは完了 なお、get-deps / compile はcowboyのMakefileを見ると書いてある 次に dynamo のディレクトリに戻って make compile >|| $ cd ../../ $ make compile
ダメな場合、直接下記を実行してみる
$ elixirc -pa deps/cowboy/ebin lib/*/*/*.ex lib/*/*.ex lib/*.ex -o ebin
これで、 ebin ディレクトリの中にコンパイル済み(?)のファイルが出来ているはず
examples/simple.exs の実行
実行の方法は simple.exs 自体に書かれている
$ cat ./examples/simple.exs [master] # Run this app from root with: # # elixir -pa ebin --no-stop examples/simple.exs defmodule MyApp do # 以下略
$ elixir -pa ebin --no-stop examples/simple.exs Running ::MyApp on port 3000 with Cowboy # この行が表示されれば起動完了
"Running ::MyApp on port 3000 with Cowboy" が表示されない(listenに失敗してる?)場合もあり、どうやら原因不明に失敗している人もいた。
無事に表示された場合、http://localhost:3000/foo/bar にアクセスしてみる (http://localhost:3000/ じゃないよ) と Hello World! が表示されるはず
ExUnit を使ってみる
ExUnitの使い方をいろいろ見てみたいなら、やっぱりリポジトリの /test/ ディレクトリ下を見るのが良いかも
https://github.com/josevalim/dynamo/tree/master/test
基本的には、Rubyなどでもおなじみの /test ディレクトリ下にテストファイルがあり /test/test_helper.exs みたいなのがある感じ
以下、チュートリアルにあったサンプルにテストを追加してみたファイル
例では math.ex として保存して実行してみた
ExUnit.start [] defmodule Math do def sum(a, b) do a + b end end defmodule AssertionTest do use ExUnit::Case def test_pass do assert_equal 30, Math.sum(10, 20) end def test_failed do assert_equal 10, Math.sum(10, 20) end end
$ elixir ./math.ex .F 1) test_failed (::AssertionTest) ** (::ExUnit::AssertionError) Expected 30 to be equal to 10 stacktrace: lib/elixir/builtin.ex:1023: ::Elixir::Builtin.raise/2 lib/ex_unit/assertions.ex:374: ::ExUnit::Assertions.assert/2 lib/ex_unit/runner.ex:78: ::ExUnit::Runner.run_test/3 lib/enum.ex:556: ::Enum.do_each/3 lib/enum.ex:136: ::Enum.each/3 lib/enum.ex:131: ::Enum.each/2 lib/ex_unit/runner.ex:69: ::ExUnit::Runner.run_tests/2 2 tests, 1 failures.
テストケースが2個しかないので表示が寂しいけれど、こんな感じでテストを書くことが出来る
ExUnit でキモになるところは、ExUnit.start [] と書かないと下記のようなエラーになります。
** (exit) "ExUnit::Server is not running. Are you sure you used exunit from command line?" lib/ex_unit/server.ex:59: ::ExUnit::Server.check/1 lib/ex_unit/case.ex:6: ::ExUnit::Case.__using__/2 /Users/toshiwo/var/misc/elixir/math.ex:8: ::ExUnit::Case.__using__/2 src/elixir_dispatch.erl:104: :elixir_dispatch.dispatch_macro/6 lists.erl:1278: :lists.mapfoldl/3 lists.erl:1279: :lists.mapfoldl/3 src/elixir_translator.erl:44: :elixir_translator.translate_each/2 lists.erl:1278: :lists.mapfoldl/3
個人的には ::ExUnit::Server って単語だけで、erlangの message passingなんかを使って、テストケースを並列や分散させて走らせたり出来るのかな〜と妄想全開なところが気になってます
(実際のところの事実はまだ(知らない|調べてない)けれど・・・
Ruby製password manager "pws" を使ってみた
pws というRuby製のパスワードマネージャを使ってみたのでメモ
1Passwordとかでも良いんだけど、ちょっとしたパスワードを貯めておくには良いかも
簡単な使い方
マスターパスワードを決めて、test に対するパスワードを決める
$ pws add test No password safe detected, creating one at /Users/toshiwo/.pws Please enter a new master password: # マスターパスワードを決めて ACCESS GRANTED Please enter a password for test: # test に対するパスワードを決める The password for test has been added
ちょっと変わった使い方
パスワードファイルをgit(など)で管理したい
PWS という環境変数でパスワードファイルを指定出来る
ただし、ディレクトリは予め作っておく必要がある
$ export PWS=~/.pws/pws $ pws add test No password safe detected, creating one at /Users/toshiwo/.pws/pws # <= 変わる
これで、~/.pws/ ディレクトリ下を git で管理できる
namespace
pws コマンドに -NAMESPACE を付けると、namespace を使うことが出来る
パスワードファイルが pws + namespace になる
また、マスターパスワードもnamespace単位で指定出来る
$ pws -namespace add test No password safe detected, creating one at /Users/toshiwo/.pws/pws-namespace Please enter a new master password: 0
追加したパスワードの取り出し方
pws get を使えば、マスターパスワードの認証後パスワードがクリップボードに規定時間(デフォルトでは10秒間)コピーされる
ここでおもしろいのが、規定時間後 pws get が実行される直前のクリップボードに戻るところがおもしろい
$ pws get test ACCESS GRANTED The password for test is now available in your clipboard for 10 seconds # <= ここで止まる (デフォルトでは10秒間
クリップボードにコピーされる時間を変更したい場合
$ pws get test 100 ACCESS GRANTED The password for test is now available in your clipboard for 100 seconds # <= ここで100秒間止まる
help アクションやその他のアクション
pws help で help を出力してくれる
pws のアクションには多種な alias が用意されてる模様
例えば、add と同様のアクションは add / set / store / create があるらしい
ちなみに、各種アクションの後ろの方に書かれている (...) のはそのアクションの引数です
例えば、pws add の場合
NAME の後に PASSWORD を指定すれば、対話式ではなくパスワードが追加できる
$ pws add KEY PASSWORD
まとめ
- ちょっとしたパスワードの管理に使えそう
- pws get の際のクリップボードの処理がおもしろい
- ただし、pws help 以外のコマンドを実行する場合、毎回マスターパスワードが必要になるのがちょっと面倒
rbenv install が失敗する場合の対処方法
TMPDIR を指定して実行してやるとたぶんうまくいく
$ TMPDIR=~/var/tmp rbenv install 1.9.3-p0
さくらのレンタルサーバにrbenvでRubyをインストールしようとして困ったときにこの方法でうまくインストールできた