u16suzuの blog

日々学んだことのメモブログです。

ローカルにある不要になった remote-tracking branch を削除する

remote-tracking branch を削除する方法

remote-tracking branch とはローカルにあるリモートレポジトリの追跡ブランチのことです。

私たちが手元で使うローカルブランチは、 git fetch して、このremote-tracking branch をローカルに作成した後に、

ここからさらに git checkout -b して生成されます。

開発が終わり、無事マージした後にこの remote-tracking branch は不要になります。

remote (ex. GitHub上) で削除済みのブランチであれば git remote prune origin で消せるのですが、

そうでないブランチは消せません。しかし、以下の方法で消すことができます。

%w(
  origin/test
  origin/fix
  origin/fix_typo
).each do |bra|
  system("git branch -d -r #{ bra }")
end

削除前は、 git status, git diff などのコマンドが重かったのですが、実行後は幾分か軽くなりました。

参考にさせていただきました

追記

gitコマンド部分も含めて、Rubyスクリプト化しました。

`git branch --all`.split("\n").map(&:strip).select{|s| s.match(/^remotes\//)}.each do |bra|
  system("git branch -d -r #{ bra.gsub(/^remotes\//, "") }")
end

Rubyの細かい記法のメモ

begin, end で複数行をインスタンス変数にキャッシュできる

def calc_camage(base)
  # 最終値={基本値×(1-1/8)×武器補正×攻撃回数}
  base * (1-1/8) * 8 * 1
end

def damage
  @damage ||= begin
    atk = 12
    dfn = 9
    base = atk/2 - dfn/4
    calc_camage(base)
  end
end

p damage # => 32

文字列の展開をまとめて行う

ar = (1..10).to_a
puts ("%03d " * 10) % ar
# => 001 002 003 004 005 006 007 008 009 010

Array#assoc, rassoc

2次元配列をHashっぽく操作できる。多分名前の由来は英語の association 。

a2 = [
    [:a, 1],
    [:b, 2],
    [:c, 3],
]

p a2.assoc(:a) # => 1
p a2.rassoc(3) # => :c

Hashにもある。

h = {a: 1, b: 2, c: 3}

p h.assoc(:a) # => [:a, 1]
p h.select{|k,v| k==:a} # => {:a=>1}

ヒアドキュメント

インデントを気にしなくて良い<<~ は2.3 から入った。 なので、それ以前のバージョンでは <<- を使う必要がある。 #{} による変数展開も使える。

age = 33
sql = <<~SQL
  select *
  from users
  where age == #{ age }
  ;
SQL

puts sql

引数部分にヒアドキュメントを直接指定もできる。

def foo(arg)
  puts arg
end

foo(<<-SQL
  select * from users
  where id = 1
  ;
SQL
)

# =>  select * from users
#  where id = 1
#  ;

at_exit でプログラムの最後に実行できる処理を指定できる

END でも可。後から順に実行される。

at_exit { p 1 }
at_exit { p 2 }
at_exit { p 3 }
END { p 4 }
END { p 5 }
END { p 6 }
# =>
# 6
# 5
# 4
# 3
# 2
# 1

変数名などにUTF8の文字を使える

ただ、クラス名は頭文字が大文字の半角英字である必要がある。

日本語のメソッド名が書けたりする。

class Nucoぬこ
  def self.新規作成
    new
  end

  def 鳴く( 回数 = 1 )
    puts "にゃーん" * 回数
  end
end

Nucoぬこ.新規作成.鳴く( 3 )
# => にゃーんにゃーんにゃーん

こちらを参考にしました

Rubyで別ファイルにログを出力する

Railsで開発をしていると、たくさんSQLを実行しているサーバだと development.log の出力が多すぎて追うのが大変になります。

こういう時、別ファイルに出力させたいのですが、以下のように行えばOKです。

また、log/ 以下は gitignore されていることがほとんどだと思うので、log以下にファイルを置くと良いです。

Logger.new('log/out.log').info( "ログ出力したい文言" )

出力例は以下のようになります。 

I, [2019-01-15T18:59:25.132692 #6825]  INFO -- : ログ出力したい文言

Rails外の場合だと、require が必要です。

require "logger"

Logger.new('out.log').info( "ログ出力したい文言" )

size,count,empty? のパフォーマンスを確認する

size,count,empty? のパフォーマンスを確認をしてみる。

require "benchmark"

count = 1000_000

ar = [1, 2, 3, 4, 5]

Benchmark.bm(10) do |x| # 10はラベルの為に確保する長さ
  x.report("size") do
    count.times do
      ar.empty?
    end
  end

  x.report("count") do
    count.times do
      ar.count == 0
    end
  end

  x.report("length") do
    count.times do
      ar.length == 0
    end
  end
end
  • 実行結果
                 user     system      total        real
size         0.040000   0.000000   0.040000 (  0.048787)
count        0.060000   0.000000   0.060000 (  0.058087)
length       0.040000   0.000000   0.040000 (  0.045684)
  • 1回あたりの実行時間を nano sec に直してみる。
size 48.787[nano sec]
count 58.087[nano sec]
length 45.684[nano sec]

参考資料のNumbers Everyone Should Know - High Scalability -によると、Send 2K bytes over 1 Gbps network 20,000 ns

すなわち、2K bytes のデータを 1Gbpsのネットワークで送信した場合 20[micro sec] かかるということなので、

普通の web application を作っているのならば、これらのメソッドの速度の違いはあまり気にする必要はなさそうだ。

また、Railsのアプリケーションログを見てみると、ざっくりこんな感じで1リクエスト毎にms単位の時間がかかっている。

I, [2019-01-10T12:30:21.152318 #21603]  INFO -- : [2236aa74-e13c-475e-a42c-5a87dc7fba51] Completed 200 OK in 143ms (Views: 0.4ms | ActiveRecord: 12.7ms)

これと比較したらメソッド毎の nano sec 単位の実行速度の違いなど誤差の範囲である。

参考資料

gem のコードを git clone して RubyMine で開くスクリプト

以下を /usr/local/bin に置いて、 chmod a+x clone_and_open.rb しておく。

clone_and_open.rb https://github.com/u16suzu/foo すると ~/src にダウンロードされる。

clone_and_open.rb

#!/usr/bin/env ruby

class CodeReader
  # clone and open
  #
  # git repository を ~/src に clone して RubyMine で開くコマンド
  def clone_and_open(uri=ARGV[0])
    dir_name = uri.split("/")[-2]
    repo_name= uri.split("/")[-1]

    system "mkdir -p ~/src/#{dir_name}"

    # password入力を避けるために ssh 形式で clone する
    system "git clone git@github.com:#{dir_name}/#{repo_name}.git ~/src/#{dir_name}/#{repo_name}"

    system "mine ~/src/#{dir_name}/#{repo_name}"
  end
end

CodeReader.new.clone_and_open

2018年12月にリリースされたRubyGems, BundlerのRubyの対応バージョンのメモ

2018年12月にリリースされた RubyGems v3系, Bundler v2系にてRubyの対応バージョンが2.3以上必須となった。

早速この影響でTravisCIが落ちるなどしたのでシュッと対応しておいた。

RubyGems v3系 (3.0.0)

Bundler v2系 (2.0.0)

gemのソースを pry-byebug を使ってブレークポイントで止めて読む準備

いつも仕事でもプライベートでも使っている bundler だけど、中身のコードを把握していないのでどうも雰囲気で使っている感が否めない。

そこで、ソースを読み腹落ち感を得るためにコードを読む準備を進めてみた。

pry-byebug を使ってブレークポイントで止められるようにする

(1). システムに pry-byebugを入れる

毎回 Gemfile 書くのは面倒なのでシステムに入れちゃう

gem install pry-byebug
gem install pry-stack_explorer # 超便利なのでこれも

(2). require "pry" して、止めたいところで binding.pryすれば止まる

require "pry"

ar = [1,2,3]

ar.each do |i|
  binding.pry # ここで止まる
  p i
end

便利。

bundlerのコードで試してみる

(1). ソースを git cloneする

$ git clone git@github.com:bundler/bundler.git ~/src

/vendor/bundle に入ったコードだと git blame できなくて普通に読みづらいので、git clone したり gem-src を使うなりして git repository を取得した方が良い。

(2). CUI ツールのエントリポイントであるbundler/exe/bundle でまずは require "pry"する

#!/usr/bin/env ruby
# frozen_string_literal: true

require 'pry'
(略

(3). 実行して止まるか確認

./bundler で実行すればシステムに入っている方ではなく git clone した方の bundler が実行できる。

$ cd /Users/suzuki_y/src/bundler/exe/
suzuki_y@MBP:~/s/b/exe$ ./bundle install                             

From: /Users/suzuki_y/src/bundler/exe/bundle @ line 30 :

    25:   require "bundler/cli"
    26:
    27:   binding.pry
    28:
    29:   # Allow any command to use --help flag to show help for that command
 => 30:   help_flags = %w[--help -h]
    31:   help_flag_used = ARGV.any? {|a| help_flags.include? a }
    32:   args = help_flag_used ? Bundler::CLI.reformatted_help_args(ARGV) : ARGV
    33:
    34:   Bundler::CLI.start(args, :debug => true)
    35: end

[1] pry(main)>

無事止まりました。

show-stackでコールスタックもみれます。

[1] pry(main)> show-stack

Showing all accessible frames in stack (9 in total):
--
=> #0  <main>
   #1 [block]   block in run <Byebug::PryProcessor#run(&_block)>
   #2 [method]  run <Byebug::PryProcessor#run(&_block)>
   #3 [method]  resume_pry <Byebug::PryProcessor#resume_pry()>
   #4 [method]  at_line <Byebug::PryProcessor#at_line()>
   #5 [method]  at_line <Byebug::Context#at_line()>
   #6 [block]   block in <main>
   #7 [method]  with_friendly_errors <Bundler.with_friendly_errors()>
   #8 [main]    <main>

あとは、コードを好きにいじりながら自由にコード読み放題です。

メソッド系のgemの場合

また、 bundlerのようなコマンド系の gem ではなく、tapp gem のようにコード内で使用するメソッド系の gem は、

gemのルートディレクトリに main.rb みたいな適当なファイルを作って、そこから対象のgemを require して呼び出しを行ってとっかかりを作ります。

# src/tapp/main.rb
require "./lib/tapp"
require "pry"

binding.pry

"123".tapp
"123".taputs
From: /Users/suzuki_y/src/tapp/main.rb @ line 6 :

    1: require "./lib/tapp"
    2: require "pry"
    3:
    4: binding.pry
    5:
 => 6: "123".tapp
    7: "123".taputs

[1] pry(main)> step

From: /Users/suzuki_y/src/tapp/lib/tapp.rb @ line 13 Tapp.config:

    12: def config
 => 13:   @config ||= Tapp::Configuration.new
    14: end

[1] pry(Tapp):1>

いい感じですね。

RubyMineを使ったやり方もあとで追記したいと思います。