Rubyチートシート
たまに使おうと思うと忘れていて毎回リファレンスを見る→理解する→書くが面倒なので、自分が一瞬で思い出せるようにメモ。
文字列処理
特定の文字列を切り出したい
- slice : 何文字目から何文字分切り出すって時に使う。戻り値は切り取られた値。[]と同義。
str = "hello" str.slice(0, 2) => "he" # str[0,2]と同義 str.slice(/\w+/) => "hello" # 正規表現も使える
- match : 正規表現を引数にしてMatchDataを返す。(MatchDataに対する理解がイマイチ)
str = "おじいさんは山へ芝刈りにおばあさんは川へ洗濯に行きました。 str.match(/おじいさん/) => #<MatchData "おじいさん">
特定の文字列にマッチするものを全て切り出したい
- scan : マッチしたものを全て配列に格納して返す
str = "hello goodmorning goodnight" str.scan(/\w+/) =>["hello", "goodmorning", "goodnight"]
特定の文字列を特定の文字列で置換したい
- gsub
str = "good morning hello good night" str.gsub("good", "great") => "great morning hello great night"
特定の文字列を削除したい
- delete: 特定の文字列を削除したい時に使う。削除する文字列があった場合は削除後の文字列、ない場合はnilが戻り値になる。
str = "hejamallojama" str.delete("jama") => "hello" str.delete("nai") => nil
配列
配列をくっつけて文字列にしたい
- join
array = ["東京", "大阪", "名古屋"] array.join("|") => "東京|大阪|名古屋"
配列から特定の条件に合う要素を取得したい
- select : ブロック内の条件に合う要素を配列で返す
array = %i(10 20 30 40) array.select{|num| num > 20} => [30, 40] array.select{|num| num > 30} => [40] #要素が1つでも配列として返るので注意が必要 array.select{|num| num > 50} => []
その他よく忘れる系
- tap :tapメソッドは、ブロック変数にレシーバ自身を入れてブロックを実行します。戻り値はレシーバ自身です。メソッドチェーンの中にtapメソッドをはさみ込み、ソースコードを簡潔にする目的で使われます。ポイントはブロック内にレシーバ自身が入ること。 理解するためだけの単純な例
array = [10, 20, 30] array.tap{ |array| array << 40 } #array自身がブロックに渡される。 => [10, 20, 30, 40]
Railsでぺージ内タブを実装する(powerd by BootStrap)
今回はBootstrapを使ってRailsアプリにぺージ内タブを実装します。
Rails内でBootstrapを使うにはtwitter-bootstrap-rails gemを導入しておく必要がありますので、あらかじめこのあたりのぺージを参考に 導入しておいてください。
seyhunak/twitter-bootstrap-rails · GitHub
RailsにTwitter Bootstrapの導入と簡易な使い方 - Rails Webook
htmlを作成
導入できたらhtmlを作成します(別途 application.htmlはある前提です)
"nav nav-tabs"クラス配下がタブリストになっていて、"tab-content"クラス配下が各タブの内容になっています。
"active" クラスが現在選択されているタブです。
tab_sample.html
<div> <ul class="nav nav-tabs" role="tablist"> <li class="active" role="presentation"> <a aria-controls="tab_a" data-toggle="tab" href="#tab_a" role="tab">A</a> </li> <li role="presentation"> <a aria-controls="tab_b" data-toggle="tab" href="#tab_b" role="tab">B</a> </li> <li role="presentation"> <a aria-controls="tab_c" data-toggle="tab" href="#tab_c" role="tab">C</a> </li> </ul> <div class="tab-content"> <div class="tab-pane active" id="tab_a" role="tabpanel"> <p> タブAだよ </p> </div> <div class="tab-pane" id="tab_b" role="tabpanel"> <p> タブBです </p> </div> <div class="tab-pane" id="tab_c" role="tabpanel"> <p> タブC!! </p> </div> </div> </div>
画面で確認
画面で確認してみます。
Bootstrapっぽい、いい感じなタブになってますね!
思っていたよりも遥かに簡単でした!Bootstrapすごい!
Railsでfaviconを設定する
前回に引き続き超基本ですが、検索した時に一番上に出てきた
favicon_link_tagメソッドを使ったファビコンの設定 - Ruby on Rails入門
でうまくいかなかったのでうまくいった方法を書いておきます。
faviconを作成する
既成のものを使ってもいいですが、せっかくなので自分で作成しました。適当なペイントソフトで書いて
作ったのがこれです。うまですね。
favicon_link_tagを追加
app/views/layouts/application.html.erbにfavicon_link_tagを追加します。
<!DOCTYPE html> <html lang="en"> <head> 〜中略〜 <%= favicon_link_tag %> </head>
オプションとかありますが、あまり使わないと思うので気にしません。
favicon.icoを保存する
上で作成したファビコンをfavicon.icoという名前で/app/assets/imagesフォルダに保存します。
確認
ページで確認してみましょう。出来ましたね!
MySQLのユーザーを作成する
基本中の基本ですが、僕のように初心者の人には役に立つかなと思うので残しておきます。
サーバーを起動
$ mysql.server start
rootでログイン
$ mysql --user=root;
userを作成('ユーザー名'@'ホスト名'で作成)
CREATE USER 'user'@'localhost' IDENTIFIED BY 'password';
権限付与
GRANT ALL PRIVILEGES ON *.* TO 'user'@'localhost' WITH GRANT OPTION;
ログイン確認
$ mysql --user='user' -p $ 上で設定したパスワードを入力 mysql>
ユーザー確認(実際はrootとかも表示されます。)
mysql> select User,Host from mysql.user; # ユーザー、ホストの一覧が表示される。上で作成したユーザーがいればOK
VCRを使って開発中にあほみたいにリクエストを飛ばさないようにする
RubyでWebサイトからスクレイピングしまくってデータを取得しまるくるようなプログラムを書いていると開発のテスト中にリクエストをあほみたいに飛ばしてしまうときがあります。
そうするとそのサーバーに迷惑がかかってしまいますし、あんまりいい気持ちのするものでもありません。そこで今回はVCRというgemを使ってこの問題を解決してみたいと思います。
VCRとは
VCRとはテスト中に過去に投げたリクエストをカセット(cassete)に記録しておいて、その後再度同じリクエストが投げれられた場合はサーバーではなく、記録しておいたカセットからリクエストの結果を取り出すというものです。
これによって、上記のようにサーバーに迷惑がかかることもなくなりますし、テストのスピードも格段に早くなります。
簡単な使い方
とりあえずどんな感じになるのか、上記githubに載っているsampleをrspecバージョンで書き換えて簡単なサンプルを試してみたいと思います。
まず必要なgemがインストールされていない場合はしておきます。
gem install vcr rspec webmock
そして
spec --init
を実行 するとspecファイルが生成されます
create .rspec create spec/spec_helper.rb
続いて、sample_spec.rbを生成します。
touch sample_spec.rb
まずはspec_helperの末尾にVCRの設定を書き込んでいきます。
# spec_helper.rb VCR.configure do |config| config.cassette_library_dir = "vcr/vcr_cassettes" config.hook_into :webmock end
config.cassette_library_dirで記録したリクエストのymlファイルを保存しておくディレクトリを設定して、config.hook_intoでHTTPリクエストをどのようにhookするかを設定しています。
その他の設定できる項目については公式サイトに記載がありますので興味のある方は見てみてください。 Configuration - Vcr - VCR - Relish
続いてsample_spec.rbに実行するテストを書き込んでいきます
# sample_spec.rb require_relative './spec_helper.rb' require 'vcr' RSpec.describe 'sample' do it 'sample' do VCR.use_cassette("get_google") do 100.times do response = Net::HTTP.get_response(URI('https://www.google.com')) end end end end
googleに100回getアクセスするというプログラムです。google先生なら100回くらい大丈夫でしょう。
ポイントはVCR.use_cassette(カセット名) do endの部分です。こちらでどのカセットを使うのかを指定しています。
今はまだget_googleという名前のカセットはありませんが、1度このプログラムを実行することで、カセットが作成されます。
では1度目のテストを実行してみましょう。
rspec sample.rb
すると以下のような結果が出力されました。
Finished in 5.16 seconds (files took 0.66782 seconds to load) 1 example, 0 failures
100回getをするのに5.16秒かかりました。
ここでvcr/vcr_cassetes/ディレクトリを見てみるとget_google.ymlができているのがわかります。
中身を見てみると1回目のテストで実行されたリクエストが記録されているのがわかります。
ではもう一度テストを実行してみます
$ rspec sampler.rb $ Finished in 0.24276 seconds (files took 0.47402 seconds to load) 1 example, 0 failures
!!!早い!!超早い!!!これは実際にリクエストを投げたわけではなくカセットに記録しておいたリクエストの結果を読み込んでいるからです。
VCRすごいですね!問題が見事に解決されました。
こんなところで簡単な使い方はOKかと思います。
よく出るエラーの対策
例えば先ほどのsample_spec.rbをこんな風に書き換えたとします。
# sample_spec.rb require_relative './spec_helper.rb' require 'vcr' RSpec.describe 'sample' do it 'sample' do VCR.use_cassette("get_google") do 100.times do response = Net::HTTP.get_response(URI('https://www.yahoo.co.jp')) #google→yahooに書き換え end end end end
で同じテストを実行しようとするとこんなエラーが吐かれます
1) sample sample Failure/Error: response = Net::HTTP.get_response(URI('https://www.yahoo.co.jp')) VCR::Errors::UnhandledHTTPRequestError: ================================================================================ An HTTP request has been made that VCR does not know how to handle: GET https://www.yahoo.co.jp/ VCR is currently using the following cassette: - /Users/user_name/Desktop/GitHub/vcr_sample/spec/fixtures/vcr_cassettes/get_google.yml - :record => :once - :match_requests_on => [:method, :uri] Under the current configuration VCR can not find a suitable HTTP interaction to replay and is prevented from recording new requests. There are a few ways you can deal with this: * If you're surprised VCR is raising this error and want insight about how VCR attempted to handle the request, you can use the debug_logger configuration option to log more details [1]. * You can use the :new_episodes record mode to allow VCR to record this new request to the existing cassette [2]. * If you want VCR to ignore this request (and others like it), you can set an `ignore_request` callback [3]. * The current record mode (:once) does not allow new requests to be recorded to a previously recorded cassette. You can delete the cassette file and re-run your tests to allow the cassette to be recorded with this request [4]. * The cassette contains 100 HTTP interactions that have not been played back. If your request is non-deterministic, you may need to change your :match_requests_on cassette option to be more lenient or use a custom request matcher to allow it to match [5]. [1] https://www.relishapp.com/vcr/vcr/v/3-0-0/docs/configuration/debug-logging [2] https://www.relishapp.com/vcr/vcr/v/3-0-0/docs/record-modes/new-episodes [3] https://www.relishapp.com/vcr/vcr/v/3-0-0/docs/configuration/ignore-request [4] https://www.relishapp.com/vcr/vcr/v/3-0-0/docs/record-modes/once [5] https://www.relishapp.com/vcr/vcr/v/3-0-0/docs/request-matching ================================================================================
ooops
An HTTP request has been made that VCR does not know how to handle: GET https://www.yahoo.co.jp/
とあるようにそんなリクエストの返し方知らねーよバカって書いてます。
当たり前といえば当たり前で1回目に記録したgoogleに対するアクセス記録を使ってyahooにアクセスしようとしてるわけですから知らなくて当然です。
このことから、デフォルトでは保存されているアクセスはカセットから返して、保存されていないものは新たに記録するといったよしなな感じになっていないことが分かります。
でも結構親切に対策方法を書いてくれているので安心です。1つずつ見ていきましょう
1つ目
If you're surprised VCR is raising this error and want insight about how VCR attempted to handle the request, you can use the debug_logger configuration option to log more details [1].
「エラーの原因とかもうちょい詳しく知りたかったらログとか出してみたらいいと思うよ」って言ってます。
ログを取ってみましょう。spec_helper.rbにログファイルを生成する設定を記載します。
# spec_helper.rb VCR.configure do |config| config.cassette_library_dir = "fixtures/vcr_cassettes" config.hook_into :webmock # or :fakeweb config.debug_logger = File.open("log","w") end
これでテストを実行すると、logファイルが生成されるので中身を見てみます。
上略... [Cassette: 'get_google'] Checking if [get https://www.yahoo.co.jp/] matches [get https://www.google.com/] using [:method, :uri] [Cassette: 'get_google'] method (matched): current request [get https://www.yahoo.co.jp/] vs [get https://www.google.com/] [Cassette: 'get_google'] uri (did not match): current request [get https://www.yahoo.co.jp/] vs [get https://www.google.com/] [webmock] Identified request type (unhandled) for [get https://www.yahoo.co.jp/]
ひたすら100回分のgoogleに対するgetが読み込まれたのに(なのでほんとはdo loopの中にuse cassetteを書くべきでしたね。。) 最後にyahooに対するgetが呼ばれてそれは知らないとなってますね。 今回に関して言えば原因がわかっているのであまり有用な情報ではありませんが、原因がわからないときには有効な手法です。
続いて2つ目
You can use the :new_episodes record mode to allow VCR to record this new request to the existing cassette [2].
「:new_episodesっていうオプションつけたらこの新しいリクエストをexisting cassetteに記録できるよ!」って言ってます。
これやりたかったことっぽいですね。やってみましょう
# sample_spec.rb VCR.use_cassette("get_google", :record => :new_episodes) do #:record => :new_episodesオプションを追加 100.times do response = Net::HTTP.get_response(URI('https://www.yahoo.co.jp')) end end
これで実行すると先ほどのエラーは出ずに、get_google.ymlの末尾にyahooへのgetが記録されているのがファイルをみると確認できるかと思います。どんどん新しいものを同じカセットに記録していきたいならこの設定にしておけば良さそうです。
続いて
If you want VCR to ignore this request (and others like it), you can set an `ignore_request` callback
「VCRに無視してほしかったらignore_requrestして無視してちょーだい」って言ってます。
やってみましょう。
まずsample_spec.rbを書き換えます
# sample_spec.rb require_relative './spec_helper.rb' require 'vcr' RSpec.describe 'sample' do it 'sample' do VCR.use_cassette("get_google") do response = Net::HTTP.get_response(URI('https://github.com/')) #githubに書き換え end end end
これをこのまま実行すると、上記のunhandledのエラーが出てしまいます。
そこでgithubへのリクエストは無視するという設定をspec_helper.rbに追加します
# spec_helper.rb VCR.configure do |config| config.cassette_library_dir = "fixtures/vcr_cassettes" config.hook_into :webmock # or :fakeweb config.debug_logger = File.open("log","w") config.ignore_request do |request| #config.ignoreを追記 request.uri == 'https://github.com/' #uriがgithubの場合は無視する end end
これで再度テストを実行するとテストが通って、うまくgithubが無視されているのが分かります。
4つ目
The current record mode (:once) does not allow new requests to be recorded to a previously recorded cassette. You can delete the cassette file and re-run your tests to allow the cassette to be recorded with this request [4].
「今のrecord mode(once)だと新しいリクエストを記録できないっす。ファイル消してもう一回実行したらできます。」って言ってます。
ファイルを消してもう一回実行したらできるのは当たり前として、record modeが気になるところですね
こちらに詳しく書いていますが、ざっくりまとめると
:once
過去のものを再生できる
同名カセットファイルの記録は1度のみ
同名のカセットファイルがある場合はエラーを吐く(←今回出ているエラーはこれですね)
:new_episodes
過去のものを再生できる
同名のカセットファイルがあれば追記する
:none
過去のものを再生できる
新たな記録は行わない
:all
- 過去に記録されててもとにかく全部記録する
のような感じになっています。
1つ注意点としてallにすると過去のものを記録して再生できるというvcrの利点が生かされずに全てカセットに記録するということになってしまいます。
なので先ほどやったnew_episodesというオプションはこのrecord_modeを設定していたのです。
最後
The cassette contains 101 HTTP interactions that have not been played back. If your request is non-deterministic, you may need to change your :match_requests_on cassette option to be more lenient or use a custom request matcher to allow it to match [5].
「カセットに101(Switching Protocol)が含まれてると再生できないよー。match_requests_onの条件もっとゆるくするかカスタムのrequest matcher定義してね。」って言ってます
要は記録したリクエストに101が含まれていると、同じリクエストを再生しても違うリクエストと判断されるからうまくリクエストmatcherを設定してくれってことだと思います。
軽く調べてみましたが、match_requests_onの条件をゆるくする方法についてはちょっと良く分かりませんでした。
また、request matchを自前で定義する方法については
describe "#fetch_info", vcr: {match_requests_on: [:method, VCR.request_matchers.uri_without_param(:timestamp)]} do # この場合timestampはmacherの条件がから除外される end
こんな感じで書くといいみたいです。
最後だけちょっと曖昧になってしまいましたが、こんなところで終わりにしたいと思います。
参考:
追記 VCRで記録したcasetteが間違ったレスポンスを返していることがありハマりました。もしリクエストのログとブラウザで実際アクセスしたリクエスト内容が合ってるにも関わらずレスポンスがおかしい時はcassetteの記録がおかしいことを疑ってみてもいいかもしれません。
Mechanizeを使ってページ遷移
Mechanizeを使って簡単なページ遷移を書きました。
googleのトップページから
- リンクをクリック
- フォームに値を入力してサブミット
を実行したものです。
scraper.rb
main.rb
あとは
$ ruby main.rb
で実行されてコンソールに色々表示されるはずです。 ほとんどこのサイトの翻訳なので、より詳しいところはこちら参考にしてみてください。 http://docs.seattlerb.org/mechanize/GUIDE_rdoc.html
jQueryでよく使う処理をどんどんまとめていく[随時更新]
何度も使う基本的な操作をどんどんここにまとめていく。複数処理にまたがりそうなものはUtilとして作成 ※ coffeescriptで書いてるのでjavascriptの方は随時補完してください。
Utilはこちら
DOM操作
普通のテキストボックスや数字ボックス
チェックボックス
チェックされているかを取得
$("#checkBoxId").is(":checked")
チェックをつける
$("#checkBoxId").prop("checked",true(false))
テーブル
列の削除
$(#rowId).remove()
構文
for each文
$(".someClass").each -> $(this). dosomething