どこでも見れるメモ帳

とあるSEの備忘録。何かあれば気軽にコメントください〜

はてブの共起タグをネットワーク表示するには(個人版)

はじめに

はてブのタグについて,共起タグを取得し,ネットワーク表示する方法を簡単に記します.
環境はMacOSXFirefox, はてブ拡張アドオンインストール済とします. f:id:ni66ling:20151108220709p:plain

共起頻度が3回以上のタグ組み合わせをネットワーク表示

共起タグの取得

$ echo "tagA,tagB,freq" > cooccur.csv
$ sqlite3 -cmd \
    "select 
      T.name, 
      CT.name, 
      count(CT.name) 
    from tags T 
      left join tags CT 
        on T.bookmark_id = CT.bookmark_id 
          and T.id != CT.id 
    where T.name > CT.name 
    group by T.name, CT.name 
    having count(CT.name) >= 3
    order by T.name, CT.name;" \
    /Users/[username]/Library/Application\ Support/Firefox/Profiles/[hash].default/hatenabookmark/[hatenabookmark_id]/bookmark.sqlite </dev/null \
    | tr '|' ',' \
    >> cooccur.csv

共起ネットワークの作成

$ R
library(igraph)
csvdata <- read.csv("./cooccur.csv", head = T)
graphdata <- graph.data.frame(csvdata, directed = F)
tkplot(
  graphdata, 
  vertex.label=V(graphdata)$name, 
  canvas.width = 1200, 
  canvas.height = 700, 
  vertex.size = 0, 
  edge.width=E(graphdata)$freq/4)

結果のグラフは,上図の通り.

おまけ:タグ"Javascript"の共起タグを上位10件取得

$ sqlite3 -cmd \
    "select
      CT.name,
      count(CT.name)
    from tags T
      left join tags CT 
        on T.bookmark_id = CT.bookmark_id 
          and T.id != CT.id 
    where T.name = \"Javascript\" 
    group by CT.name 
    order by count(CT.name) desc
    limit 10;" \
    /Users/[username]/Library/Application\ Support/Firefox/Profiles/[hash].default/hatenabookmark/[hatenabookmark_id]/bookmark.sqlite </dev/null
# 例)
# node.js|28
# html5|17
# firefox|15
# jQuery|15
# tips|14
# 開発|13
# programming|12
# まとめ|12
# ajax|11
# dom|11

参考

マージコミットを含む大きめのgitブランチをcherry-pickで別ブランチに持っていくには

はじめに

f:id:ni66ling:20150726174614p:plain:w500
マージコミットを含む大きめのgitブランチを,別のブランチに持って行きたい状況が発生したのでメモ*1
取り込みたいブランチを1コミットにまとめ,これを取り込み先ブランチにcherry-pickマージする方法を記す*2
なお,複数コミットを1コミットにまとめる方法について,一般にはgit rebaseでsquashやfixupを用いることが多い*3が,マージコミットに対してはうまくいかなかった*4
そこで,ここでは取り込みたいブランチについて差分パッチを作成し適用するという方法をとった.

やりかた

# Xを1コミットにまとめるための一時的なブランチ(B_dummy)を作成
git checkout A1
git checkout -b B_dummy

# B1〜B3をパッチ化(参考[3])
git diff --binary A1..B3 > X.patch

# パッチをB_dummyにあて(参考[4]),B1〜B3を1コミット(=X)にまとめる
git apply X.patch
git add [target files]
git rm [target files]
git commit -m 'this is X: patch A1..B3'

# 別ブランチA'1に移動し,トピックブランチB'を作成し,Xをcherry-pickで持ってくる
git checkout A'1
git checkout -b B'
git cherry-pick X

参考

*1:ある機能セットを別プロジェクトのリポジトリに適用したいとか,エンタープライズ系で個別カスタマイズを一式持って行きたいとか,そういう状況

*2:以前は純粋にcherry-pickマージのみで行っていた.でもこれだとcherry-pick対象のリビジョン数が数百,数千になると,同じ箇所で生じるコンフリクト解消が地味にシンドかった

*3:参考[1]

*4:git rebaseのオプションで--interactiveと--preserve-mergesを併用し,その中でsquash/fixupを行うとエラーが生じてしまう.参考[2]

Poderosaでコマンド実行結果をクリップボードにコピーするには

はじめに

f:id:ni66ling:20150725191724p:plain:w400
Poderosaには,コマンド実行結果をPoderosa実行元(ローカル)のクリップボードにコピーする機能があります.
これでファイルをcatしてクリップボードにコピーとか,ディレクトリ構成をtreeしてコピーとかできます.便利!

やりかた

  1. コマンド実行時,Enterキーを入力する代わりにCtrl+,キーを入力
  2. するとポップアップメニューがでますので「コマンド結果をコピー(C)」を選択

Ctrl+,でポップアップが出ない?

Ctrl+,キーバインドされているみたいなのですが,私の環境では適切に動作できませんでした.
キーバインドを変更することで,適切にポップアップメニューが表示できるようになりました.

f:id:ni66ling:20150725191740p:plain:w600

  1. ツール > 詳細プリファレンスエディタ を選択
  2. フィルタに「org.poderosa.terminalemulator.commandPopupKey」を入力
  3. 項目をダブルクリックし,値を「Ctrl+Oemcomma」から変更(例えば「Ctrl+Shift+C」など)

参考

RSpecで複数の指定行を実行する方法

はじめに

f:id:ni66ling:20160611144301p:plain

RSpecで特定のケースのみを「複数」実行したい状況が生じたためメモ.

やり方

行指定オプションを複数回指定する.

$ rspec [file_name] --line_number [line_number_1] --line_number [line_number_2]

略記式で以下のようにも記述できる.

$ rspec [file_name]:[line_number_1]:[line_number_2]

例えば,デグレhoge_spec.rbにおけるx行目とy行目のit文がredになってしまい,実装修正後にgreenになっていることを確認するとき,以下のように記述すればOK.

$ rspec hoge_spec.rb:x:y

また,複数ファイルにわたる場合でも記述できる.

$ rspec hoge_spec.rb:x:y fuga_spec.rb:z

実際の開発時には,他オプションも付けて以下のように実行すると良さそう.*1 *2 *3 *4

$ rspec -fd -c --seed 1234 --fail-fast hoge_spec.rb:x:y fuga_spec.rb:z

参考

*1:-fdは結果を詳細に出力

*2:-cは色付き出力

*3:--seed 1234は実行順序のランダムシードを1234に指定し,rspec実行のたびに実行順序が変わらないように出力

*4:--fail-fastはredが生じたらすぐに終了

SRP(単一責任原則)とCC(循環的複雑度)によるコンポーネント内の技術的負債の定量化

はじめに

ソースコードを静的解析することでRailsコンポーネント(単一ファイル)の技術的負債を定量化します.
方針はこちらの記事*1に従って行います.
なお,SRPの算出はgit blameを用いて*2行い,CCの算出はrubocopのMetrics/CyclomaticComplexityを用いて行います.

# ref: 第8回 Perlによる大規模システム開発・設計のツボ(3):Perl Hackers Hub|gihyo.jp … 技術評論社
#      http://gihyo.jp/dev/serial/01/perl-hackers-hub/000803

# コンポーネントの単一責務性の違反指数(SRP)
#   SRP=R+U+((L/100)-5)
#     R:修正リビジョンのユニーク数
#     U:修正ユーザのユニーク数
#     L:モジュールのライン数
function get_SRP() {
  local target_filepath=$1
  echo $(( \
    $(git --no-pager blame --line-porcelain $target_filepath | sed -n 's/^summary //p' | sort | uniq -c | sort -rn | wc -l) + \
    $(git --no-pager blame --line-porcelain $target_filepath | sed -n 's/^author //p' | sort | uniq -c | sort -rn | wc -l) + \
    ( $(cat $target_filepath | wc -l) / 100 - 5) \
  ))
}

# コンポーネントの循環的複雑度(CC)
#   CC=循環的複雑度が20を超えるメソッド数
function get_CC() {
  local target_filepath=$1
  echo $( \
    rubocop --format simple --only Metrics/CyclomaticComplexity --config <(echo -e "CyclomaticComplexity:\n  Max: 20") $target_filepath | grep 'Cyclomatic complexity' | wc -l \
  )
}

# コンポーネントの負債指数(P)
#   P=SRP×CC+(SRP+CC)
function get_P() {
  local srp=$1
  local cc=$2
  echo $(( $srp * $cc + ( $srp + $cc ) ))
}

# コンポーネントの負債指数(P)が大きい順に "P SRP CC ファイル名" を標準出力
for file in `git ls-files app lib | grep -E '\.rb$'`; do
  _srp=$(get_SRP $file)
  _cc=$(get_CC $file)
  echo $( get_P $_srp $_cc ) $_srp $_cc $file
done | tee technical_dept_result.log | sort -k1,1 -nr 

※gistはこちら*3

関連する過去記事

ni66ling.hatenadiary.jp ni66ling.hatenadiary.jp

*1:第8回 Perlによる大規模システム開発・設計のツボ(3):Perl Hackers Hub|gihyo.jp … 技術評論社 - http://gihyo.jp/dev/serial/01/perl-hackers-hub/000803

*2:git blameによるSRP(単一責任原則)の定量化 - どこでも見れるメモ帳 - http://ni66ling.hatenadiary.jp/entry/2015/06/25/000444

*3:技術的負債の定量化 - https://gist.github.com/KenshoFujisaki/9cefd372c9cec0814a08