メソッドの引数にメソッドの返り値を渡す場合、blockの渡し方に注意する
たとえば、 こんなメソッドがあるとします。
def foo(arg) puts "#{arg}, #{block_given?}" end def var if block_given? yield else 'no block' end end
下記のようにブロックの渡し方でfoo
メソッド側のblockとなったりvar
メソッド側になったりします。想定した渡し方になってない場合があるので注意です。
foo var do 'block' end # => no block, true foo var { 'block' } # => block, false foo(var do 'block' end) # => block, false
GitHubのPull Requestで変更されたファイル一覧を取得する
結論から言うと、あるPull Requestがmaster
にマージコミットされると、 直前のコミット*1と、Pull Requestの最後のコミットの二つが親コミットになっているので、最初の親をHEAD^
で取得しHEAD
とのdiffを見る。
たとえばこのPRがマージされた場合の、master
の履歴がこんな感じ
ここで以下のコマンドを打つ。HEAD^
は18c4d8a
なので、差分である今回のPRで変更されたファイル一覧が取得できる。
% git diff HEAD^..HEAD --name-only
scripts/1.txt
scripts/2.txt
scripts/3.txt
ちなみに、二つ目の親81c4663
はHEAD^2
で取れるが、上記のPRの場合、これとマージコミットは差分が無いので、何も出ない。
% git diff HEAD^2..HEAD --name-only
参考
*1:PRベースでmasterにコミットしている場合は前回マージされたPRのマージコミットのはず
Little Glee Monsterにハマっている件
TL;DR
最近 Little Glee Monster (以下リトグリ)というボーカルグループにハマっておりまして、その良さを共有したいというポストです。
リトグリとは?
このブログにたどり着くであろう想定読者(Web系エンジニア)の方は知らない人が大半だと思うので軽く紹介すると、2014年10月デビューの女子高生6人組のボーカルグループで、ソニー損保のCMの人たちと言われたら分かる人もいるかもしれません *1
https://www.youtube.com/watch?v=wKhPF894kVUwww.youtube.com
(2016.12.1追記) ↑の動画がprivateになったので、代わりにCMじゃないバージョンで https://www.youtube.com/watch?v=TWX1v7BKnUIwww.youtube.com
(2017.2.14追記) ↑の動画もprivateになりました..orz
リトグリの魅力
1にも2にも圧倒的な歌唱力です*2。6人全員が年齢離れした歌唱力を持っていて、その6人が合わさった時のハーモニーに非常に圧倒される毎日です。とりあえず3曲挙げておきますので、興味があったらYouTubeにたくさん動画あるので公式チャンネルとか他の動画とか見てみて下さい。
オリジナル曲「空は見ている」のアカペラver(音量注意)
オリジナル曲「Girls be Free!」
ドリカム「朝がまた来る」のカバー
ライブ
今月9/3に日比谷野外音楽堂に、9/22に山梨県の東京エレクトロン韮崎文化ホールの2回行ってきました。 小並感ですが非常に良かったです、CD音源より生歌の方が迫力あるし、ライブ中にメンバーがステージ降りてファンと交流したり、写真撮影OKな曲があったりでファンサービス満点ですし、ライブに行くのが非常に価値のあるアーティストだと思いました。
9/3 日比谷野外音楽堂
改めて、ガオフェス2016 in 日比谷野外音楽堂ありがとうございました!!
— Little Glee Monster (@LittleGleeMonst) 2016年9月5日
アンケート実施中(^o^)
ご来場いただいた皆さま、感想をぜひお聞かせください♪https://t.co/DbFEAgWwTY pic.twitter.com/2QsQEQi2H2
9/22 東京エレクトロン韮崎文化ホール
山梨の皆さん!ありがとうございました!去年より会場が大っきくなり、これだけのガオラーさんが集まってくださって本当に嬉しい!みんな、楽しんで頂けましたかね?麻珠の故郷、最高!かれん pic.twitter.com/c5W7mtz83A
— Little Glee Monster (@LittleGleeMonst) 2016年9月22日
まとめ
リトグリの良さを語れるエンジニア募集!
GoogleのAPIトークンをS3に保存する
GoogleAPI Clientには Google::Auth::TokenStore
というトークンを保存するためのインターフェースが存在していて、デフォルトでは
Google::Auth::Stores::FileTokenStore
Google::Auth::Stores::RedisTokenStore
のふたつがある。これのS3バージョン。
ひとつ下の記事の FileTokenStore
を置き換えられる。
GCSじゃないの?というツッコミは無しで...w cacheは厳密にはいらないけど何回も呼ぶときがあるかなと思って用意しました。
require 'googleauth/token_store' require 'aws-sdk' class S3TokenStore < Google::Auth::TokenStore def initialize(bucket_name:, path_prefix:) @bucket = Aws::S3::Resource.new.bucket(bucket_name) raise "Bucket(#{bucket_name}) not exists" unless @bucket.exists? @path_prefix = path_prefix @cache = {} end def load(id) @cache[id] ||= begin object = object(id) if object.exists? object.get.body end end end def store(id, token) object(id).put(body: token) @cache[id] = token end def delete(id) object(id).delete @cache.delete(id) end private def object(key) @bucket.object("#{@path_prefix}#{key}") end end
GmailをAPI経由で取得する
GmailのAPI経由で未読のメールを1件検索して既読にするサンプル。OAuthのトークンがない場合はコンソールに出てくるURLをブラウザで開いて認証後に出てくるコードを入力する。
require 'google/apis/gmail_v1' require 'googleauth/stores/file_token_store' Gmail = Google::Apis::GmailV1 OOB_URI = 'urn:ietf:wg:oauth:2.0:oob' def credentials(email) @credentials ||= begin client_id = Google::Auth::ClientId.new( 'xxxxx.apps.googleusercontent.com', 'xxxxx' ) token_store = Google::Auth::Stores::FileTokenStore.new(file: "#{ENV['HOME']}/google_credentials.yaml") authorizer = Google::Auth::UserAuthorizer.new(client_id, Gmail::AUTH_SCOPE, token_store) user_id = email credentials = authorizer.get_credentials(user_id) if credentials.nil? url = authorizer.get_authorization_url(base_url: OOB_URI) puts "Open the following URL in your browser and authorize the application." puts url puts "Enter the authorization code:" code = gets credentials = authorizer.get_and_store_credentials_from_code( user_id: user_id, code: code, base_url: OOB_URI ) end credentials end end email = 'foo@gmail.com' gmail = Gmail::GmailService.new gmail.authorization = credentials(email) result = gmail.list_user_messages(email, max_results: 1, q: 'label:inbox label:unread') result.messages.each do |m| puts m.id puts gmail.get_user_message(email, m.id).snippet r = Gmail::ModifyMessageRequest.new r.remove_label_ids = ["UNREAD"] result = gmail.modify_message(email, m.id, r) end
BashのPS4でデバッグが捗る
Bashでset -x
とするとデバッグモードとして処理内容が逐次出力されますが、PS4
という環境変数で出力内容を調整できます。
test.sh
#!/usr/bin/env bash PS4='+ [${BASH_SOURCE}:${LINENO}] ${FUNCNAME:+$FUNCNAME(): }' set -x hello() { name=$1 echo "Hello $name" } hello 'World'
これを実行すると、以下のようにソース名(BASH_SOURCE
)と行数(LINENO
)、関数の場合は関数名(FUNCNAME
)が出力されます。
% bash test.sh + [test.sh:11] hello World + [test.sh:7] hello(): name=World + [test.sh:8] hello(): echo 'Hello World'
シェルスクリプトで再実行するための関数
retry() { command="$@" local try_count=0 local retry_limit=3 local wait_seconds=300 until sh -c "$command"; do [ $try_count -eq $retry_limit ] && return 1 sleep $wait_seconds try_count=$(expr $try_count \+ 1) done } # example retry ls -ltra hoge