FontAwesomeKitはそれ自体に組み込まれてないアイコンフォントを使う場合にも役立つ
例えば、 https://github.com/erikflowers/weather-icons を使いたいって時の例。
weather-icons.css
とweathericons-regular-webfont.ttf
とかをリポジトリに入れておく。- コードジェネレータを準備(
CodeGenerator.rb
,gen.rb
) FAKWeatherIcons.fakgen.[h|m]
を生成(ruby gen.rb
)
$ tree WeatherIcons WeatherIcons ├── FAKWeatherIcons.fakgen.h ├── FAKWeatherIcons.fakgen.m ├── code_generator.rb ├── gen.rb ├── weather-icons.css └── weathericons-regular-webfont.ttf
weathericons-regular-webfont.ttf
をリソースに追加FAKIcon
を継承したTQWeatherIcons
を作るTQWeatherIcons
にFAKWeatherIcons.fakgen.[h|m]
をコピペして、singleton生成のためのクラスメソッド書く。
※ コードジェネレータを準備のとこで、提供されてるCSSに合わせたgen.rb
を適当に書く
require './CodeGenerator.rb' # https://github.com/PrideChung/FontAwesomeKit/blob/master/CodeGenerators/CodeGenerator.rb names = [] codes = [] _lines = File.read("./weather-icons.css").lines lines = [] _lines.each_with_index do |l, index| case l when /^\.wi-.+{/ lines << l + _lines[index + 1] + _lines[index + 2] end end lines.each do |line| name = '' line.gsub(/(?<=wi-).*(?=:before)/i) { |match| name = match } nameParts = name.split('-') nameParts = nameParts.each_with_index.map do |p, i| if i < 1 p else p = p.capitalize end end name = nameParts.join names.push name code = '' line.gsub(/".*"/) { |match| code = match[2..(match.length-2)] } codes.push "\\u#{code}" end generator = CodeGenerator.new('WeatherIcons', names, codes) generator.generate
こういう風に元々FontAwesomeKitに入ってないフォントでも、UIImage化したりとかFAKIconが提供している便利機能を使えて良い。
main packageが複数ファイルで構成される時のgo run
main.go
package main func main() { some() }
some.go
package main import ( "fmt" ) func some() { fmt.Println("some") }
というのがある時に、go run main.go
ってやると動きそうな気がするんだけど、動かない。
Run compiles and runs the main package comprising the named Go source files. A Go source file is defined to be a file ending in a literal ".go" suffix.
とあるように、go run main.go
とやっただけでは、main.goだけがコンパイルされる。同一packageゆえにmain.goからのimportなど明示的な依存関係があるわけではないので、some.goがコンパイルされることはない。
go run main.go some.go
なり go run *.go
なりしてやる必要がある。
iosのフォームバリデーションみたいなの
tableViewで作ってたので、その例で。
tableViewControllerをtextfieldのdelegateにしちゃうと、「これは何文字」とか、「これは必須」とかどうこうとか面倒なことになるなーと思って、そういう形にはしなかった。
一個のcellに一個のフィールドがあることが多いし、UITableViewCellをサブクラス化して、バリデーションすることにした。バリデーションメッセージを出すのもCellだけでやりたかったけど、cellからはみ出る吹き出しみたいにしたかったので、それはtableViewControllerにさせてる。
@protocol TQValidatableFieldDelegate - (void)cell:(UITableViewCell *)cell didResolveValidationErrorWithErrorView:(UIView *)errorView; - (void)cell:(UITableViewCell *)cell didOccurValidationErrorWithErrorView:(UIView *)errorView; @end // ---------- Custom Cell ---------- - (BOOL)validate { if ([self TQ_validate]) { [self.delegate field:self didResolveValidationErrorWithErrorView:_validationErrorView]; } else { [self.delegate field:self didOccurValidationErrorWithErrorView:_validationErrorView]; } return isValid; } - (BOOL)TQ_validate { if (_inputField.text.length == 0) { _validationErrorView.message = @"入力してください。"; return NO; } if (_inputField.text.length <= _minLength) { _validationErrorView.message = [NSString stringWithFormat:@"%d文字以上で入力してください。", _minLength + 1]; return NO; } if (_inputField.text.length > _maxLength) { _validationErrorView.message = [NSString stringWithFormat:@"%d文字以内で入力してください。", _maxLength]; return NO; } _validationErrorView.message = @""; return return YES; } // ---------- TableViewController ---------- - (void)cell:(UITableViewCell *)cell didReceiveValidationErrorWithErrorView:(UIView *)errorView { if (![errorView isDescendantOfView:self.tableView]) { [self.tableView addSubview:errorView]; [self.tableView bringSubviewToFront:errorView]; } } - (void)cell:(UITableViewCell *)cell didRemoveValidationErrorWithErrorView:(UIView *)errorView { if ([errorView isDescendantOfView:self.tableView]) { [errorView removeFromSuperview]; } }
textFieldのdelegateになってるcellが変更があったりした適当なタイミングでvalidateするのと、フォームをsubmitする時のtableViewControllerが全部のcellに対してvalidateするみたいな感じにしてる。その辺は省略。
best practiceとか大体こうやってるよみたいなのは知らない。
rsenseがドックに表示される時
いつのころからか、起こるようになったので、アドホックな対応を。
- そもそもは
-Dapple.awt.UIElement=true
を設定しないといけないアプリケーションではないと思う(しなくてもDockに出ないはずだと思う) - javaのバージョンが関係してた気がするけど、その辺詳しくない
ので、pull reqとかはせずこんな感じで。
--- /Users/toqoz/brew/Cellar/rsense/0.3/libexec/bin/rsense.orig 2010-05-11 11:52:52.000000000 +0900 +++ /Users/toqoz/brew/Cellar/rsense/0.3/libexec/bin/rsense 2013-12-12 12:07:54.000000000 +0900 @@ -103,7 +103,7 @@ def server_process(cont_proc = nil) begin - command = %W(java -cp #@classpath org.cx4a.rsense.Main script) + command = %W(java -cp -Dapple.awt.UIElement=true #@classpath org.cx4a.rsense.Main script) command += %W(--home=#@rsense_home --no-prompt --end-mark=#{END_MARK} --config=#@config) command << '--debug' if @debug command << "--log=#@log" if @log
$GOPATH内のリポジトリを楽に移動する
必要なもの
こんな感じ
$ cat ~/.zshrc | grep anything-gorepo alias gogo='cd $(anything-gorepo)'
#!/usr/bin/env ruby # anything-gorepo unless ENV['GOPATH'] STDERR.puts '$GOPATH should not be empty' exit 1 end require 'ruby-anything' def directories path Dir.entries(path).select do |filename| File.directory?(File.join(path, filename)) end.select do |filename| filename != '.' && filename != '..' end end gosrc = File.expand_path("#{ENV['GOPATH'].dup}/src") repo_paths = [] directories(gosrc).each do |host| directories(File.join(gosrc, host)).each do |user| directories(File.join(gosrc, host, user)).each do |repo| repo_paths << File.join(host, user, repo) # diplay without gopath end end end STDOUT.puts File.join(gosrc, _anything_(repo_paths))
anything-gorepoは適当な名前でgem化するかも知れない。
追記
anything-gorepoはgemにした。
gorpでSQL書いてレコード取得する時には必ず個別にカラムを指定したほうが良い話
SQLとして何が好ましいかという話はしないし関係ない。
SQL書いてSELECTするような場合、gorp.DbMap.Select
とか gorp.DbMap.SelectOne
とか。gorp.rawselect
ってのが呼ばれて、
そこでは、取得したカラムの全てがstructに無い場合エラーを吐くようになってる。
https://github.com/coopernurse/gorp/blob/87135bba705725c26b805636fd548fae440a1c6b/gorp.go#L1495
なので、例えばだけど、
dbmap.Select(&User{}, "SELECT * from users")
とかってしている- User struct にname追加, users tableにname追加するmigration作成
- migration実行
- app再起動
とかって場合、app再起動が終わるまでその部分はエラーを吐く。
gorp.DbMap.Get
とかはそもそもフィールドを指定しないけど、そういうことは起こらない。
https://github.com/user.keys をとってくるgemつくった
似たようなのありそうだけど、探すより作ったほうが早そうだったからつくった。
chefとかでpub key登録する時により楽にしたかった。 コマンドラインからも使えるので、手動で登録するような時もちょっとだけ役に立つと思う。
duplicate symbol _OBJC_IVAR_$_TQHOGEHOGE._name in:
#import "TQHOGEHOGE.m"
のせいだった。
けっこう気付かずやりそうなので、こういうの作っておいた。
$ cat checker/check_import_m #!/bin/sh ag -i '#import ".+.m"' **/*.h **/*.m
標準出力がパイプされてる時でもcursesが動くようにする
STDOUT.isattyがfalseだったら/dev/tty
reopenして、あとで戻すみたいな感じにしたら大丈夫だった。
何もしてないと、command | grep 'hoge'
とか hoge=$(command)
とかで動かない。
plistのシンタックスチェック
plistをロードできなくて、なにかしらダメなんだろうけど、launchctl: no plist was returned for: /Users/toqoz/Library/LaunchAgents/<PLIST_FILE>
とだけ言ってくる。
とりあえずシンタックスエラーでもチェックしようと思って調べたら、plutil -lint ~/Library/LaunchAgents/<PLIST_FILE>
というので出来た。
homebrewで入れたgoの$GOROOT
$BREW_HOME/Cellar/go/1.1.1
でよかったんだけど、https://github.com/mxcl/homebrew/commit/743bf42e2e0a5f0fc217b114e88c24f84c1fed97 以降は $BREW_HOME/Cellar/go/1.1.2/libexec
としてやらないといけなくなった。
なんだけど、このtweetをたまたま見て、そもそもGOROOTはビルド時と違う場所に置いたりしてない限り別に設定しなくて良いらしい。ということを知った。
@__gfx__ 利用時であれば、 go 本体にビルド時のGOROOTが入っているので、ビルド時と違うディレクトリに go を移動して使いたいときに設定します。バイナリパッケージだと /usr/local/go でビルドされてるので、それ以外の場所に置くなら GOROOT 必要
— INADA Naoki (@methane) December 4, 2013
で少し調べた。
$ echo $GOROOT $ go env GOARCH="amd64" GOBIN="" GOCHAR="6" GOEXE="" GOHOSTARCH="amd64" GOHOSTOS="darwin" GOOS="darwin" GOPATH="" GORACE="" GOROOT="/Users/toqoz/brew/Cellar/go/1.1.2/libexec" GOTOOLDIR="/Users/toqoz/brew/Cellar/go/1.1.2/libexec/pkg/tool/darwin_amd64" CC="gcc" GOGCCFLAGS="-g -O2 -fPIC -m64 -pthread -fno-common" CGO_ENABLED="1"
pkg/runtime/zversion.go
が defaultGoroot
って定数で持ってた。build時に http://golang.org/src/cmd/dist/buildruntime.c#L18 でそれを作ってる。
iOS remindersとかcalendarみたいな日付選択
iOSやるやる言いつつ、本読んでちょっと試して放置して2年ぐらい経つ気がするけど、先月ちょっと作ろうと思うものがあって始めた。
remindersとかcalendarみたいな日付選択を作りたくなって試してみた。
_datePickerCell
,_dateFieldCell
ってクラス作ってnilと紐付ける。_dateFieldCell
を押した時に、_datePickerCell
が_cells
になかったら追加し、あれば削除_datePickerCell
編集開始時に_dateFieldCell
の色を編集中の色にする、終れば確定の色にする。_datePickerCell
の値が変った時に_dateFieldCell
の値を変える。
みたいなことをやった。(実際のコードから流れを簡易化するためにsectionを1個にしたり適当に手を加えた)
- (void)viewDidLoad { // initialize _dateFieldCell, _datePickerCell // ... _cells = @{ // ... _dateFieldCell } } - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { if ([self cellForIndexPath:indexPath] == _datePickerCell) { return _datePickerCell.picker.frame.size.height; } return [super tableView:tableView heightForRowAtIndexPath:indexPath]; } - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { return 1; } - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { return [_cells count]; } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { return [_cells indexPath.row]; } - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { UITableViewCell *selectedCell = [self cellForIndexPath:indexPath]; if (selectedCell == _dateFieldCell) { [self toggleDatePickerCell]; } else { // ... } [self closeSoftKeyboard]; } - (void)toggleDatePickerCell { if ([_cells containsObject:_datePickerCell]) { [self _hideDatePickerCell]; } else { [self _showDatePickerCell]; } } - (void)_showDatePickerCell { int targetIndex = [NSIndexPath indexPathForRow:[_cells indexOfObject:_dateFieldCell] + 1; [self.tableView beginUpdates]; [_cells insertObject:_datePickerCell atIndex:targetIndex]; [self.tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:[NSIndexPath indexPathForRow:targetIndex inSection:0]] withRowAnimation:UITableViewRowAnimationFade]; [self.tableView endUpdates]; // 日付を編集中の色にしたり [_dateFieldCell didStartEditing]; } - (void)_hideDatePickerCell { int targetIndex = [NSIndexPath indexPathForRow:[_cells indexOfObject:_dateFieldCell] + 1; [self.tableView beginUpdates]; [self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:targetIndex inSection:0]] withRowAnimation:UITableViewRowAnimationFade]; [_cells removeObjectAtIndex:targetIndex]; [self.tableView endUpdates]; // 日付を確定の色にしたり [_dateFieldCell didEndEditing]; } // DatePickerCell delegate(DatePickerCellが変更された時) - (void)dateDidChange:(UIDatePicker *)datePicker { _dateFieldCell.date = datePicker.date; } - (void)closeSoftKeyboard { [self.tableView endEditing:YES]; }
bundle install --path=PATH で入れたgemを認識してほしい、Intellij
.bundle/config
を見てくれないっぽくて困ってて、File -> Project Structure -> Modules
にそのプロジェクトのLOAD_PATH設定する所を発見したけど
... "/Users/toqoz/dev/[a project]/vendor/gems/ruby/2.0.0/gems/uglifier-x.x.x/lib", "/Users/toqoz/dev/[a project]/vendor/gems/ruby/2.0.0/gems/turnip-x.x.x/lib", "/Users/toqoz/dev/[a project]/vendor/gems/ruby/2.0.0/gems/susy-x.x.x/lib", ....
みたいなのを一々追加できる人はいないのでどうしたものかと思っていたら、File -> Project Structure -> SDKs -> [a ruby version]
にClasspathってのがあって、
/Users/toqoz/dev/[a project]/vendor/gems/ruby/2.0.0/gems
を追加してやれば良かった。これだとプロジェクトごとにSDK作る必要ありそうだけど、とりあえずはこれでいいかなという感じ。
goで特定のエラーに対して別々にハンドリングする
- エラーメッセージの比較
- errorの比較
- errorの型の比較
errorの比較
がシンプルで好きだけど、それだけだと、動的にエラーメッセージ変えたい時とかに困る。