Rubyのメソッドの引数あれこれメモ
配列引数
複数の引数を1つの配列として扱うにはアスタリスクをつける
def my_mthod(*args) args end my_method(1, 'hoge', 'three') #=> [1, 'hoge', 'three']
キーワード引数
Ruby 2.0からの機能(同じことは1.9系とかでもできるがハッシュを展開しないとダメ)
def my_method(name: 'test user') name end my_method(name: "test new user") #=> "test new user"
メソッド定義の際の引数にdef my_method(:name => 'test user')って書き方はできないみたい。 ただ、メソッドを呼び出す際の引数に上記は可能。つまりmy_method(:name => 'test new user')はOK
Rubyist Magazine - Ruby 2.0.0 のキーワード引数
ブロック引数、Procの引数に関しては下記のQiitaの記事が非常にわかりやすかったのでぜひご一読下さい。
MySQLのデータを定期実行でバックアップ
サービス運用してるとバックアップ取ると思うのですが、
毎回調べるので自分のブログにメモ。
backup_db.shとかで。 このシェルスクリプトをcronで定期実行するイメージです。
#!/bin/bash TODAY=`date +%Y%m%d` BACKUP_DIR=/data/backup/db BACKUP_INTERVAL='+3' for database in `mysql -uroot -N -s -e"show databases"`; do if [ $database == 'DB名' ]; then nice mysqldump -uroot --single-transaction --no-autocommit ${database} | pbzip2 -cv -p4 > ${BACKUP_DIR}/${database}-${TODAY}.sql.bz2 fi done find ${BACKUP_DIR} -type f -name "*.bz2" -mtime ${BACKUP_INTERVAL} | xargs rm -Rf
mysqldumpのオプション http://open-groove.net/mysql/autocommit/ http://blog.lampetty.net/blog_ja/index.php/archives/292
findコマンドのmtimeオプション http://doruby.kbmj.com/SK/20090731/find_mtime_
findしたやつをxargsコマンドで削除 http://openlab.dino.co.jp/2008/02/20/133431188.html
pbzip2 http://blog.cloudpack.jp/2011/08/aws-news-c1xlarge-pbzip2.html
ちなみにcronはこんな感じ
0 4 * * * root sh /path/to/backup_db.sh > /dev/null 2>&1
Rubyでxls(Excelファイル)を簡単にパースする方法
すごく簡単でドキュメント通りな内容なのですが、非常に便利だったのでメモ。
その名もSpreadsheetというgemを使います。 https://github.com/zdavatz/spreadsheet/blob/master/GUIDE.md
# Gemfile gem 'spreadsheet'
# vim hoge.rb Spreadsheet.client_encoding = 'UTF-8' book = Spreadsheet.open '/path/to/an/excel-file.xls' sheet1 = book.worksheet 0 # スプレッドシートの1枚目を指定 sheet1.each do |row| # do something interesting with a row end
たったこれだけです!超簡単! 配列でrowの部分にデータが入ってくるので扱いやすくてよいです。
スプレッドシートの指定の仕方はindexで指定しているのですが(なので2枚目だと1を指定すればよいです)、シート名をそのまま書いても大丈夫なようです。(ex. sheet1 = book.worksheet 'Sheet1')
また、Spreadsheet.open部分はRailsの場合だとexpand_pathとか使えなくてめんどくさそうと思ったのですが、普通にアプリルートからのパスで通りました。
なのでbatchスクリプト内で実行する際は
book = Spreadsheet.open 'bin/batch/excel-file.xls'
などと書いておいて、コンソールから
$ rails r bin/batch/hoge.rb
で大丈夫です。
メタプログラミングRubyメモ
Object#extend
module MyModule def my_method; 'hello'; end end
を使いたいときに
class MyClass class << self include MyModule …. end end
↓
class MyClass extend MyModule …. end
これでもMyClassの特異メソッドとしてmy_methodを呼べる。
( MyClass.my_method #=> 'hello' )
falseの時なにか決まったものを返すとき、三項演算子じゃなくていいよ!的な
class MyClass def initialize @hoge = false end def hoge? @hoge || false end end irb(main):009:0> MyClass.new => #<MyClass:0x007ff499890fe0 @hoge=false> irb(main):010:0> a = MyClass.new => #<MyClass:0x007ff49987a8d0 @hoge=false> irb(main):011:0> a.hoge? => false
って感じでいける。or演算子やから当たり前やけど、こう書けてなかったな、、っていう自分のレベルの低さを感じたのでメモ
alias :m(新しいメソッド名) :my_method(古いメソッド名)
★アラウンドエイリアス
module Kernel alias gem_original_require require def require(path) gem_original_require path rescue LoadError => load_error if load_error.message =~ /#{Regexp.escape path}\z/ and spec = Gem.searcher.find(path) then Gem.activate(spec.name, "= #{spec.version}") gem_original_require path else raise load_error end end end
エイリアスは元のメソッドを変更するのではなく、新しいメソッドを定義して元のメソッドの名前をつける。
なので元のものをラップして新しいのに飛ばすようなことができてアラウンドエイリアスと呼ぶ。
クラスマクロ
クラスマクロはクラス定義の中で使えるクラスメソッド
class Book def self.deprecate(old_method, new_method) .. end deprecate :GetTitle, :title end
attr_accessorとかがそう。
module CheckedAttributes def self.included(base) base.extend ClassMethods # baseにはincludeしたクラスが入ってくるのでそれにたいしてClassMethodsを渡してる。 # こうすることで渡ってきたクラスのクラスメソッドにClassMethodsを設定できる end module ClassMethods def attr_checked(attribute, &validation) define_method "#{attribute}=" do |value| raise 'Invalid attribute' unless validation.call(value) instance_variable_set("@#{attribute}", value) end define_method attribute do instance_variable_get "@#{attribute}" end end end end
これで
class Person include CheckedAttributes attr_checked :age do |v| v >= 18 end end
とかできるようになるわけ。
RSpecでsessionを使用したテスト(ログイン機能)
内容としてはajaxのテストを書こうとして、それにはsessionが必要というような場合です。(渡しの場合、ログインしていないとajax通信ができないという仕様でした。)
ここけっこう困って、前回こういったsessionを使うテストを実装した際にはgrapeというRails向けのREST APIのフレームワークを使っていたのでこれはまた別問題でした。(grapeはrackを使ってsession設定できます)
想定したアプローチは2つあって
controller specを使ってテスト
postで実際にログインさせてからテストを実行
1つ目はやってみたのですがテスト内ではsessionを使えたのですがアプリ内での引き継ぎができなくてうまくいきませんでした、が、ブログ書きながらちょろちょろ調べて見てると出来そうな雰囲気もあるのでまた次回試してみます。。
2つ目が今回の実装でやったのですが、挙動的にはこっちのほうがいいのかなと。
require 'spec_helper' describe CalendarController do before do @user = create(:user) post '/login', {:username => @user.name, :password => @user.password} end context 'create' do … it do xhr :post, 'hoge/fuga', {:hoge => 1, :fuga => 'fuga'} expect(response.body).to eq({:success => true, :data => {…}.to_json}) response.code.should == "200" end end end
というような感じです。
実際のログインユーザーが行う処理という流れに沿っている分テスト的には良いかなと思いました。
xhrでajax通信を使ったgetやpostが行えます。その後に中身とステータスコード200をチェックしているというような形です。
ただ、普通にsession[:calendar_id]みたいなのを使いたいというような時は1つ目のアプローチが必要と思いますので、また解決し次第ブログに書きたいと思います。
Ruby(Rails)からExcelで文字化けしないCSVファイル作成
CSVファイル作成でハマったのでメモ。
今回作ろう思っていたのはリンクになっているボタンを押したらCSVファイルがダウンロードされるという単純なものです。
HTML載せようと思いましたがはてブ内での書き方わからないので省略、、
バージョンはRuby2.0, Rails4です。
controllerは下記のような感じで処理はmodelに。
# controllers/management_controller.rb def event_csv respond_to do |format| format.csv { send_data Event.event_csv(start_date, end_date), :filename => "events_#{start_date}-#{end_date}.csv" } end end
もともとはここで:type => ""でcontent-typeをcsvと指定していたのですがそれではうまくいきませんでした。
modelは下記
# models/event.rb class Event < ActiveRecord::Base class << self def event_csv(start_date, end_date) data = self.all csv_data = CSV.generate do |csv| csv << %w(ユーザー 所属 合計) # headerになる部分を先にpush data.each do |record| csv << [record[:username], record[:belonging], record[:sum]] end end csv_data end end end
ここでもまだ文字コード指定はしていません。
CSV.generate自体ウェブ上にあまり情報がなくて、しかもdocumentを見るとgenerate('', :encoding => 'sjis')みたいな感じで:encodingで指定できるよ!って書いてあるのですが できませんでした。。(文字コードは上記の場合、csv_data.encodeで調べられます。)
なのでさらに戻ってcontrollerから最後吐き出すときにafter_filterでnkfを使ってShift_JISにエンコードするという方法で解決しました。
class ApplicationController < ActionController::Base after_filter :cahnge_charset_to_sjis, :if => csv? ... private def csv? return request.original_url.match(/csv/) ? true : flase end def change_charset_to_sjis require 'nkf' response.body = NKF::nkf('-Ws', response.body) headers["Content-Type"] = "text/csv; charset=Shift_JIS" end end end
パスがcsvだったらsjisに文字コードを変えるメソッドを通してるって感じです。ここでheader["Content-Type"]も設定しています。
ちなみに念のためconfig/routes.rbにはこんな感じで書いてます。
get 'management/event_csv/(:start_date)/(:end_date)', :to => 'management#event_csv'
controllerの中でrespond_toでcsvを指定しているので上記のパスに.csvでアクセスするとcsvファイルがダウンロードされる、という感じです。(ex. /management/event_csv.csv)
文字化けは相変わらず辛い・・・。
うまく行かなかったところはもうちょい追求しなければ。
もっと良い実装があればぜひコメント下さい!m(_ _)m
プライベートプロジェクトでのリーン・スタートアップ by ffab0
先日、友人と2人で立ち上げたffab0というチームで
最初のサービス"PositionStrategy"をリリースした。
http://position-strategy.ffab-0.com/
今回はサービス企画からファーストリリースまでの1ヶ月間をまとめてみた。
仕事をしながらプライベートでサービスを出したい、学生同士で友人となにかサービスを作りたいと考えている方たちの参考に一部でもなれば。それと自分用に備忘録としても。すべて隠さずに書いているつもり。
目次はこんな感じ。
- サービス概要 ~ 宣伝も兼ねて ~
- 前提 ~ 開発環境と連絡手段などチームマネジメント ~
- 1週目 ~ 企画、そして挫折。新たなメンバー ~
- 2週目 ~ 企画MTG。表参道での誓い ~
- 3週目 ~ 2人で開発することによる成功と失敗。本業による多忙・・ ~
- 4週目 ~ リリースまでの長い道のり ~
■サービス概要
サービスの概要を説明しておくと、最近よく「LINEの売上が前年比◯◯%アップ!」や「グリーがついに赤字転落」など、決算や業績に関するニュースがピックアップされるが、それが実感としてどの程度すごいのか、どの程度良くないことなのかつかみにくいと思う。(少なくともビジネス感覚の低い僕はそうです。。)
そこを解決するために、代表的な財務指標をいくつかピックアップし、グラフ化して、前年はどうだった、他企業と比べてどうか、業界的にはどうなのかなどが視覚的に、直感的に理解できてるようにしたツールです。それを見る人の立場、役割によって様々な戦略を立てる手助けになりえるのではないかと考えています。
■前提 ~ 開発環境と連絡手段などチームマネジメント~
今回のPositionStrategyの使っている技術をざっと上げると
- Ruby on Rails 4.0
- Ruby2.0
- coffeescript
- chartJS
- MySQL5.6
- slim
- unicorn
- nginx
ざっとこんな感じ。コードの管理はgitホスティングサービスのbitbucketを使った。
チームのマネジメントという点では僕は東京で友人Kは大阪だったので基本的には
LINEとTwitterで相談、それでも難しい場合はGoogleハングアウトで会話+画面共有しながら相談という感じ。
また、土日など時間が取れる時に1日ハッカソンみたいな感じでずっとハングアウトつなぎっぱなしで開発をしていた。
ドキュメントはGoogleドライブ。
こんな感じで1ヶ月間で企画からリリースまで。
それでは次から1ヶ月間を振り返っていく。文章が稚拙なのでおもしろくないかも。。
■1週目 ~ 企画、そして挫折。新たなメンバー ~
このサービスは兼ねてから僕が考えていて勉強も兼ねてひとりで作ろうと思っていた。そこに同期のプログラマーが乗ってきたので2人でやることになったのだが、ここで最初の大きな挫折が。
- 仕事を言い訳にできてしまう
- 2人ともデザインのセンスがなかった
- 同期はユーザビリティよりもシステムに関心がいっている時期だった
- サービスを創れる状態になかった
同期同士なのでお互い忙しいのがわかるのと、仕事内容も把握していて催促できないことで甘えが出てしまっていた。さらにふたりともデザインセンスがほぼ皆無だった(僕はデザインが好きなだけに非常に残念だ笑)。同期はシステムやアクセスをどうさばくかというところに強い関心があったが、2人で創るにはその前の段階でクリアしなければならないことが多すぎた。どっちが悪いでもなかったがサービスを創るチームではなかったのだというのが結論だと感じている。
そんな中、救世主の友人Kがジョインしてくれた。どうやって呼び込んだかというと、この挫折しきった状態を大いに包み隠してビジョンだけ情熱的に話して呼び込んだ(笑) もちろんKがこのサービスに共感してくれたのが大きかったのと、高校時代からの友人で彼となら遠隔でも(Kは大阪在住で僕は東京)できるとお互いが思ったことが大きかった。実はKとは前に一度サービスを作ったことがあってある程度次はもっとうまくやれるとお互いに思いがあったこともある。
■2週目 ~ 企画MTG。表参道での誓い ~
Kと僕でやることになった時のチームのスペックとしては
- 僕はコード(主にサーバーサイドだがマークアップも)は多少書ける。ビジネスを考えるのは好き。
- Kはデザインが得意でマークアップもできる。サーバーサイドはほぼ素人だがターミナルで作業できるのとgitは教えた。ビジネスを考えるのは好き。
この2週目にKがたまたま東京に来る機会があったので、2泊3日の合宿で企画MTGと最初の環境構築をした。ふたりで振り返ってもここが重要なポイントだった。何が今回の成功(?)の鍵だったかというと、初回リリースの機能を洗い出して期限と担当を決めたこと。これは非常に重要なのだが、これをするためにはお互いに厚い信頼がないと仕事でない場面ではうまくいかないと思う。これを2人が守り切ったからこそ1ヶ月でのリリースができた。
もともと信頼はあったが、この合宿の最後に表参道でチーム論と人生について2人で話し合った。そしてffab0をスタートすることに決めた。これで2人でやっていく結束がさらに固まったように思う。ffab0がどうなるかは一定の結論が出た段階でまた書きたい。
■3週目 ~ 2人で開発することによる成功と失敗。本業による多忙・・ ~
ここは少し技術的な苦労が多かった。。まずKがgitを扱ったことがなかったのと、僕の伝え方がいまいちだったのが相まってコンフリクトからの激しいマージの嵐(笑) JSは最初Kに任せていたが途中から僕が巻き取ったのだがリファクタがかなり大変だった。。ただ、動くところまでやってくれていたので動きを見なくても綺麗に書きなおしてディレクトリ構造を綺麗にすればいい感じだったので助かったが。 あとは途中からKにもサーバーサイドで簡単なところは任せたのだが僕の中でのコーディング規約みたいなものを全く伝えていなかったのでお互いに苦労がうまれた。。ただbitbucketを使ってコミットを追いながらコメントしていたので修正はなんとかできた(それほどお互いに交わり合う実装が無いと思ったのでブランチ切ったりプルリクやったりはしなかった)
さらに仕事でのリリースがあってこっちに使える時間があまりなかった。ただそれは先ほど重要といった期限を守るという絶対の約束を守るという気持ちでなんとかした。自分が大変でも相方がちゃんとサービスを前進させてくれているというのはかなり気持ち的にも助けになる。
■4週目 ~ リリースまでの長い道のり ~
これは僕がrailsのassets piplineでつまったせいがかなりの比重を占める・・・。。それからどうしてもバグがでまくる。最後はずっとハングアウトで画面共有しながらお互いに指摘・説明・修正を繰り返してリリースまでこぎつけた、という感じだった。1年ほど前にCTOに「サービスは出来たと思ったところでだいたい2割くらい。あと8割残ってる」と言われたことがあるのでが、まさに今回もそんな感じだった・・。ここはちゃんとドキュメント化して無理なくできるようにしたい。
----
こんな感じの1ヶ月間でした。これからはリーンな感じで徐々にこのPositionStrategyをブラッシュアップしつつ、ffab0は1ヶ月1サービスを目標にしているので来月あたりまた新たなサービスを世に出せればと思っています。(ちなみに今週はこのブログに書いた企画MTGを再び実施予定)
...
最後に、シェアの時代なのでKPT法で振り返った僕らの反省会を載せておきます
KPT:
【K】
役割分担(デザインとサーバーサイド)
マイルストーンの置き方(この日までにこうしようという期日をしっかり定めて守った)
お互いが進めてる感がわかった(ツイッターとか通して)
ハングアウト
合宿形式で一旦認識を深め合ったのが良かった
サーバーサイド担当からのデザインに対する感想・指摘・アドバイスがあったこと
Kがrailsとコンソールを触れるようになったこと
slimいいね
【P】
gitのやりとりがうまくいってない(Kがもっと覚えるべき by K)
cssとslimをもっときれいに書く。今後はsassで書く
cssの構造を練ってからとりかかるべきだった
認識のすり合わせができていない(コードレベルでのズレが多くて書きなおすことが多々)
モデルやコントローラーの書き方(K)
本番リリース
いらないgemとか早めに消しとくべき
本番を意識した書き方ができていない&むずい。認識がなかった。
【T】
もっとKがサーバーサイド触る
ブランチ切ってプルリクを機能させる
技術をパッケージ化したい
年末年始合宿
ビジネスをもう少し考えてやりたい(マネタイズ、集客など)
⇛ 作るときにどういうビジネスモデルで行くのか、どういう集客方法でやるのかを
考えてから作る