scramble cadenza

技術ネタのガラクタ置き場

React.js で親子関係にある component の更新順序

イントロ

話題の React.js を去年末ぐらいから、ちょこちょこと触っています。
殆ど Javascript 触ったこと無い状態から、いきなり React 始めて大分修羅の道だったのですが、最近ようやく慣れてきました。

何となくわかってきた React の性質っぽいものを残しておくメモ

これは何か

React.js で作った component の更新順序を見てみた、というもの。
結論を言ってしまうと、親子関係にあると、必ず 「親 → 子」の順序で更新が行われる

現象

React.js の基本原則として、this.setState を呼ぶと、それがトリガーになって render が呼ばれる、というものがある
(state とは Ruby でいうインスタンス変数のようなもの。setStatesetter だと思えばいい)
以下のように、子も親も同時に setState を呼ぶとどうなるのだろう?という話。

超簡単なサンプルを作ってみた。

var Parent = React.createClass({
  getInitialState: function() {
    return (
      { age: 0 }
    );
  },
  setAge: function() {
    var value = this.refs.age.getDOMNode().value;
    this.setState({ age: Number(value) });
  },
  increment: function() {
    this.setState({ age: this.state.age + 1});
  },
  render: function() {
    console.log('in parent');

    return (
      <div id="parent">
        <h2>parent</h2>
        <p>input parent age: {this.state.age}</p>
        <input type="text" ref="age"/>
        <button onClick={this.setAge}>submit</button>

        <h2>child</h2>
        <Child increment={this.increment} />
      </div>
    );
  }
});

var Child = React.createClass({
  getInitialState: function() {
    return (
      { age: 0 }
    );
  },
  increment: function() {
    this.setState({ age: this.state.age + 1});
    this.props.increment();
  },
  render: function() {
    console.log('in child');
    return (
      <div id="child">
        <p>parent age: {this.state.age}</p>
        <button onClick={this.increment}>a year ago</button>
      </div>
    );
  }
});

React.render(
  <Parent />,
  document.getElementById('parent')
);

最初に親の年齢を入力して、a year ago ボタンを押すと、子供の年齢も親の年齢も 1 インクリメントするやつ。

ところでこのアプリ、親の年齢を入力しないと、親も子も 0 歳からスタートする。0 歳の親ってどういうこっちゃ。
けど細かいところは気にしない。

サンプルの重要なところは React の render で parent から child を作ってるところ。 つまり

- parent
   - child

のような構造を作っている。

一番下の a year ago ボタンをクリックすると、console には

 in parent
 in child

と出力される。
これは先に親の render が呼ばれて、その後に子の render が呼ばれることを意味している。

で、何がいいたい?

どうしてこういう順序になるのか、わからないです。
直感的には setState が先に呼ばれた方、でも良い気もするので。

こういうもの、という理解でいいのだろうか?
「親→子」という流れは理解しやすんだけど、それで無理やり理解した気になるのもなんだかなー。

「理性の限界」を読んだ

イントロ

理性の限界――不可能性・不確定性・不完全性 (講談社現代新書)

理性の限界――不可能性・不確定性・不完全性 (講談社現代新書)

人間の「理性の限界」について、色々な角度からディスカッション形式で話が進んでいく。
途中「ハイゼンベルク不確定性原理」や「ラプラスの悪魔」といった物理学の面白い話がでてきて、大学が物理学科の私は思わずニンマリ。

本を知ったきっかけ

最近ニコニコ動画 3つのボタンでカービィボウル という動画を見てしまった。
動画は勿論面白いんだけど、作者がすごい人だなと思っていて、彼がオススメするならって記憶に残っていた。

個人的な動機

読んでみようと思った理由はそれだけじゃない。

より合理的で、理性的に判断できるようになりたかったから、というのもある。
合理的な判断とはナンゾヤ、という話もあるけど、「今、自分は落ち着いていて、冷静に考えているか」ってこと。

常に意識したいことの一つです。
そういう基準や客観性をどうやって評価するか、維持するか、ということに興味があった。

背景

自分が「こっちのほうが良いんじゃないかなぁ」と考えることが、相手は「あっちのほうが良い」と思うことが、往々にしてある。
日常生活レベルの話なら「個性」と言い換えることができて、結構面白い。

けど合理的な判断を求められる仕事でも起こりえて、こちらは途端に厄介になる。

時に感情的な判断をしがちで、環境によっては到底理性的とは思えない判断をすることがある。不思議なことに。

でも仕事とは限らずに、自分もそういうことはあるし、他人を観察してそう思えることもある。

振り返ると「なんであんなことを」と思うけど、実際そういう時は客観性を失っていて「感情的になっていること」自体に気づかなかったり、あるいは気づかない振りをするものだと思う。

動機の動機

自分は冷静だと考えているけど、相手が感情的になっている場合。人によっては説得しようとすることが逆効果なこともある。

自分の説明が下手なのかな?と思ったけど、なんだか納得してくれているようには見える。でも相手の主張は変わらない。
そんな不思議な体験をした。

きっと自分が感情的になっている事に気づいていないからだろう、と思われる。

そんな時に「相手が自発的に自身の客観性を認識するためには、どうすればよいか」「自分は冷静になっているつもりで、実は論理的な説明ができていないのか?」という悩みを抱える事になった。
難しい。

本を読んで

「理性的とはナンゾヤ」という話にあまり触れず、相対的な議論が展開される。
「◯◯という方法は××という方法より、こういう理由で理性的だ」という感じ。
だから客観性をどうやって評価するか、という疑問の答えにはならなかったけど、ヒントにはなったし、単純に読み物として面白かった。

「神の非存在論」はなるほどなーという感じ。「神は理性では認識不可能」って結論は興味深い。
認識不可能だけど、神様という概念をほとんどの人間が理解していたり、或いは創りだしたりする。

神様 SUGOI
そんな神様を創れる人間はもっと SUGOI

「運と実力の間」を読んだ

イントロ

年末に読んだ本のうちの一つ。暇だったからブログに書いてみる
私の最近のマイブームが poker で、poker といえば木原直哉氏。
というわけで氏が書いた本を読んでみるか、と極めて安直な理由。

感想

面白い。今の自分が持ってない知見もあった。
内容は木原氏の生い立ちと WSOP 出場に至るまでの経緯、出場経験について語られていた。

元々興味を持って購入したので、その分楽しめた。

エンジニアリングとギャンブルについて

ここからは本の感想ではなく、極めて個人的な意見。

(観察対象があまりに少なすぎると思うけど) プログラムが書くことが得意なプログラマは(私を含む)、こういうギャンブル系が苦手な人が多いと思っている、という話。

言い換えると「確率で考え、実際に行動すること」が不得意な人が多い、ということ。
わかっていても行動できなかったり、そもそもそういう方面に興味が沸かない方が多い。

どうしてそう思うんだろうなーと今まで疑問だったけど、「運と実力の間」を読んでその理由っぽいものを思いついたので書き残します。

勝つまでのプロセスが違う

「勝つまでのプロセスが違う」というのがその有力候補。

当然「勝つ」とは何か、という定義は難しい。人によって違うから。

poker 側の「勝ち」は簡単に言うと「お金が増えること」
プログラム側は仮に、プログラムがどこかでエラーを吐いていて、それをデバッグし、直す作業を考えてみる。
直せたら「勝ち」としよう。直せなくて諦めたら「負け」

poker の話

本の中では以下のように述べられている。

  • 負けている時にやり方を変えるな

曰く、負けている時にやり方を変えたら、何が原因で負けているか、わからなくなるからだ。と。
私の拙い経験としても賛成意見。

これは運が絡むゲームにはよくある考え方だと思う。

プログラミングの話

じゃあプログラミングではどうだろうか。

状況にもよるだろうけど

  • デバッガを起動し、原因を突き止める
  • 設定ファイルを見直す
  • ログを追う

等が思い浮かぶ。

共通しているのは、プログラム(またはそれに関連する物)を少しだけ書き換えて、何度も実行する、ということ。 行った修正でエラーが出なくなるか、ちゃんと確かめないといけない。
どんなときも根気強く前に進み、心が折れるのが一番マズい。(経験上)

逆に言えば、プログラムを書き換えないで再実行する意味は無い。(時間に関連するバグなど例外はあるが)
何となく rspec をもう一回叩いてみるか... は時間の無駄だと思う。失敗する時は原因を潰さない限り、何度も失敗する。
だからどこに原因があるか色々考えたり、調べたりして、あらゆる方法を試すのだ。

何が言いたいかというと、負けている時には色々試すのが、プログラミングをする上で良いやり方だと思うってこと。

前提の話

プログラミングと poker では勝てるようになるまでのプロセスが違う、という意見なんだけど、もう一つ重要な考え方がある。

それは人は自身の向き不向きを自覚していて、自然に向いているものに興味を持つ、という考え方。方位磁石が自然と北を向くような感じ。

特に子供の頃はそのような傾向が強く見られるように思える。 これはもう一つ示唆するところがあって、それは「そう簡単に自分の向き不向きが変わらない」という事。

まとめの話

  • プログラミングと poker は勝つ方法が違う
  • 人は自分に合った興味を持つ
  • しかもそれは中々変わらない

という意見から、プログラミングが好きな人はギャンブルに興味を持ちにくく、しかも不得意である可能性が高い。と思うようになった。まる。
言語化すると長い...

で、何が言いたい?

グダグダ書きましたが、全部極論です。
視野が狭いとこうなるので、気をつけねば。

株や投資などには、個人の自己責任でお楽しみください。

binding.pry 使ってる時に、一気にループを抜ける方法

イントロ

みんな大好き pry の話
何回も binding.pry が呼ばれる環境下で、毎回 exit を入力するのめんどいよね、という話。

サンプル

class Test
  def aaa
    binding.pry
    'aaa' 
  end
end
describe '#aaa' do
   it '1' do
     expect(test.new.aaa).to eq('1')
   end

   it '2' do
     expect(test.new.aaa).to eq('2')
   end 
end

この場合 binding.pry は 2 回、処理を停止する。

    4: def aaa
 => 5:   binding.pry
    6:   'aaa'
    7: end

exit 叩く。

    4: def aaa
 => 5:   binding.pry
    6:   'aaa'
    7: end

もう一回 exit 叩く。

あるあるですね。
こういう時、一回でプロンプトまで戻りたいわけです。

解決法

!!! or exit! or exit-program を入力する

    4: def aaa
 => 5:   binding.pry
    6:   'aaa'
    7: end

>> !!!

% # 即座に終了した!

知らなかった...

rails でカスタム generator 作る話

これは何か

好きな generator を作る話。ここで述べる generator とは

rails generator hoge

のような rails generate コマンドのこと。 知識整理のために書いてみる

雛形作成

rails には generator を生成する generator があって、以下の様なコマンドを叩けば良い。

rails generate generator <generator名>

試しに test という generator を作ってみる。

% rails generate generator test                                                                                               
      create  lib/generators/test
      create  lib/generators/test/test_generator.rb
      create  lib/generators/test/USAGE
      create  lib/generators/test/templates
      invoke  test_unit
      create    test/lib/generators/test_generator_test.rb

ファイルが作られた。 作られた generator は以下のように実行できる

rails generate <generator名> (<引数1>, <引数2>, ...)

引数は generator 側の定義で制御する

generator 作成

生成されたファイル

先ほどの rails generate generator test コマンドで生成されたファイルを順番に見ていく

lib/generators/test/test_generator.rb

class TestGenerator < Rails::Generators::NamedBase
  source_root File.expand_path('../templates', __FILE__)
end

メインの generator ファイル。 Rails::Generators::NamedBase を継承した {generator名}Generator というクラスが生成されている。

ここにメソッドを定義していく。

具体例

TestGenerator に何も生産しないメソッドを作る。

class TestGenerator < Rails::Generators::NamedBase
  source_root File.expand_path('../templates', __FILE__)

  def ore
    puts "俺が"
  end

  def dhh
    puts "DHH、こと"
  end

  def da
    puts "David Heinemeier Hanssonだ!"
  end
end

rails generate コマンドを叩くと TestGenerator クラスのインスタンスメソッド上から全部実行される

% rails generate test test # test という引数を仮に与えている
俺が
DHH、こと
David Heinemeier Hanssonだ!

ご覧のとおり上から実行されていることがわかる。
なのでファイルを作りたかったら、そういうメソッドを書けばよい。
ディレクトリを掘りたかったら、そういうメソッドを書けば良い。簡単

lib/generators/test/USAGE

中身は以下の通り。

Description:
    Explain the generator

Example:
    rails generate test Thing

    This will create:
        what/will/it/create

ヘルプコマンドの下の方にそのまま使われる

% rails generate test -h
Usage:
  rails generate test NAME [options]

Options:
  [--skip-namespace], [--no-skip-namespace]  # Skip namespace (affects only isolated applications)

Runtime options:
  -f, [--force]                    # Overwrite files that already exist
  -p, [--pretend], [--no-pretend]  # Run but do not make any changes
  -q, [--quiet], [--no-quiet]      # Suppress status output
  -s, [--skip], [--no-skip]        # Skip files that already exist

Description:
    Explain the generator

Example:
    rails generate test Thing

    This will create:
        what/will/it/create

lib/generators/test/templates/

ディレクトリ。現在は空。 erb テンプレートファイルを置いておく用のディレクトリ

test/lib/generators/test_generator_test.rb

require 'test_helper'
require 'generators/test/test_generator'

class TestGeneratorTest < Rails::Generators::TestCase
  tests TestGenerator
  destination Rails.root.join('tmp/generators')
  setup :prepare_destination

  # test "generator runs without errors" do
  #   assert_nothing_raised do
  #     run_generator ["arguments"]
  #   end
  # end
end

テストの雛形。rspec 使ってれば rspec で出してくれる。 ...と思いきや、rspec の場合はスケルトン作成に失敗する。
(失敗の原因を詳しく追ってない。本当は作られるはず... なのかな)

継承クラス

親クラスは若干注意が必要なので、ここでやりたいことに合わせて分岐する

Rails::Generators::NamedBase

default だとこっち。 rails generate コマンドの引数として、一つ何かを受け取ることが必須のクラス

cf. Rails::Generators::NamedBase

% rails generate controller Users xxxx のような馴染みのある generator を作りたい場合はこちらで良い。

Rails::Generators::Base

NamedBase とは異なり rails generate コマンドの引数を自由に定義できるクラス。 Rails::Generators::NamedBaseRails::Generators::Base を継承している。

こちらのほうが柔軟性があるが、特別な用途がない限りは使わなくても良いかと思います。

便利メソッド

generator なので、テンプレートからファイル生成したり、ディレクトリを掘ったりする用途が主である。
rails はすごいから、そういう簡単なものは既にメソッドが用意してある。

これらのメソッドは全て Thor::Actions に定義されているので、そっちを見たほうがいい。 というのも Rails::Generators::BaseThor::Actions を include しているから。

もっと言うと Rails::Generators::BaseThor::Group を継承して作られているので、rails の generator は大体 thor でできてると言って良い。

したがって困ったときは thor で検索すると良い

以下は便利メソッドの内、いくつかを紹介

create_file

https://github.com/erikhuda/thor/blob/067f6638f95bd000b0a92cfb45b668bca5b0efe3/lib/thor/actions/create_file.rb#L22
file を生成する

directory

https://github.com/erikhuda/thor/blob/067f6638f95bd000b0a92cfb45b668bca5b0efe3/lib/thor/actions/directory.rb#L49

directory を copy する

template

https://github.com/erikhuda/thor/blob/067f6638f95bd000b0a92cfb45b668bca5b0efe3/lib/thor/actions/file_manipulation.rb#L108

ERB テンプレートを使って、ファイルを生成

具体例

class TestGenerator < Rails::Generators::NamedBase
  source_root File.expand_path('../templates', __FILE__)

  def create_empty_file
    create_file "aaaa.txt"
  end
end
% rails g test arg1
      create  aaaa.txt

見たことある出力やー

% rails g test arg1
   identical  Test.txt

もう一回やると、またまた見たことある出力に。
大体こんな感じでノリで generator 作れてしまいます。すごい簡単です。

まとめ

  • 継承するクラスによって、generator に渡せる引数が変わる
    • Rails::Generators::NamedBase は 1 つの引数を受け取る
    • Rails::Generators::Base は自在に定義可能
  • rails generator の内部は殆ど thor
    • 詰まったら thor で調べると良い
    • thor を一度触ったことがある人は知見を十分に活かせる
      • thor はとても素直な実装になっているから
      • thor の spec はとてもわかり易いので、読むだけで理解できる
  • hook_for は謎が多いので、使う時は若干注意
  • thor は「トール」と読むらしい

参考

CircleCI から deploy させる話

イントロ

CircleCI からテストが通ったら capistrano 使って deploy させたい。
けど、対象サーバーは IP 制限がかかっている。CircleCI の IP なんてコロコロ変わるし、どうしたらいいんや... って話。

これができると、PR を github ボタンでマージしたら、自動(当然テストも通した後)で deploy されるので、非常に嬉しい。

方針

before deploy

  • awscli を使い security group の inbound に自分自身の ip を付与
    • CircleCI の内部から IP address を割り出して、コマンドラインで一時的にinboud に追加させる

deploy

  • コマンド(bundle exec cap deploy)を実行

after deploy

  • awscli を使い security group から ip を取り外す
    • before deploy の逆をやればいい

前準備

IAM user や security group の名前は適当に決めてます。
やること多いです。

  1. IAM user circle_ci を作成
    • ec2 に関する権限を全て付与(今回に限って言えば、全て付与しなくても動くはず)
    • 詳細は後述
  2. CircleCI 用の security group を作成する
    • 名前は circle_ci
    • 普段は inbound の欄は空
    • 一時的に CircleCI の IP が許可される用の security group
  3. deploy したいサーバーに security group circle_ci を attach する
  4. AWS環境変数を CircleCI の設定画面上で予め登録する
    • IAM user circle_ci の credential を登録
  5. deploy 対象のサーバーにログインするための秘密鍵を CircleCI の設定画面上で登録する

実装

CircleCIからCapistranoを利用してAWS(EC2)にデプロイする - Qiita に大体書いてある。

deploy するコマンドとして、deploy.sh みたいなシェルスクリプトを作って、それを deployment で実行させればいい。

参考記事とは少し違っているけど、自分が作成した deploy.sh は以下のようになった。

#!/bin/sh
set -ex

SECURITY_GROUP_NAME="circle_ci"
IP=`curl -f -s ifconfig.me`

trap "aws ec2 revoke-security-group-ingress --group-name ${SECURITY_GROUP_NAME} --protocol tcp --port 22 --cidr ${IP}/32" 0 1 2 3 15
aws ec2 authorize-security-group-ingress --group-name ${SECURITY_GROUP_NAME} --protocol tcp --port 22 --cidr ${IP}/32
bundle exec cap prod deploy

追記

コメントを受け、修正しました

Before

IP=`curl-s ifconfig.me`

After

IP=`curl -f -s ifconfig.me`

-f は man で見てみると、以下のような意味だそうです。
確かエラーになった時の事を考えると、入れておいたほうが良いかもですね。

       -f, --fail
              (HTTP) Fail silently (no output at all) on server errors. This is mostly done to better  enable  scripts  etc  to  better  deal  with  failed
              attempts. In normal cases when an HTTP server fails to deliver a document, it returns an HTML document stating so (which often also describes
              why and more). This flag will prevent curl from outputting that and return error 22.

              This method is not fail-safe and there are occasions where non-successful response codes will slip through, especially when authentication is
              involved (response codes 401 and 407).

ポイント

set -ex

-x は毎度おなじみ debug 用途。実行したコマンドを標準出力するオプション。
-e はコマンドに失敗したら、即時にスクリプトを終了する。一行づつ && で挟んでいるイメージ。
コマンドが 3 つ書かれているけど、どれか一つでも失敗したら、deploy せず即時失敗扱いで良いので、このようにしている。

trap コマンド

何かしら異常があった場合、変更を加えた Security Group を元に戻さないといけない。
でないと、ある IP から接続可能な状態になってしまい、セキュリティ上良くないから。

つまり、deploy に失敗しようが成功しようが、revoke-security-group-ingress は実行させたい、ということ。
そのために trap コマンドでシグナルを補足しています。

0 1 2 3 15 を書いておけば、大抵のシグナルには反応してコマンドが発動する。

肝は最終的な exit コードは trap コマンドの実行結果ではなく、trap 以前に実行した最後のコマンドであること。
つまり bundle exec cap prod deploy で exit コード 1 が返ってきた場合、trap が発動して、revoke され、exit コード 1 でシェルスクリプトが終了する。
(CircleCI では exit コード 1 ならば、build 失敗扱いになる)

circle.yml

circle.yml は以下のようになる。
pip install しないと awscli のバージョンが古く、コマンド実行に失敗する。

machine:
  timezone: Asia/Tokyo
  ruby:
    version: 2.1.3
dependencies:
  pre:
    - sudo pip install awscli
deployment:
  master:
    branch: master
    commands:
      - ./deploy.sh

まとめ

ここまで準備して、ようやく master へのマージ + テスト通ったら deploy が自動化されます。

とはいえ、これでも revoke-security-group-ingress に失敗する可能性があり、CircleCI の IP address が許可されたままになる可能性があります。が、そのリスクには目を瞑っています。
revoke-security-group-ingress に失敗したら build にも失敗するはずなので、すぐに調査すればいい話だから。
circle_ci の inbound を削除すれば元通りなので、復旧作業も楽勝。と思ってる。

なお、Circles EC2 IP addresses and AWS security group - CircleCI なんてのがあって、この情報をうまく使えば deploy できるんや... って思いがちだけど、これは孔明の罠なので要注意。

できてないこと

  • pip install awscli をキャッシュさせること
    • 頑張れば出来そうだけど、まだやってない

参照

dangerous_open_uri という gem を作った

イントロ

gem にした。名前は結構気に入ってる。
仕事でこういうことをしたかった、というのが背景としてある。
さらに会社の先輩に冗談で「作っちゃえよ、需要あるっしょ」と言われて、それもそうかと一晩で作った。

mgi166/dangerous_open_uri · GitHub

詳細

mgi166/dangerous_open_uri の README.md に大体書いてある。

これを使うと basic 認証がかかっているページを open-uri で開くことができる。

open-uri の場合

require 'open-uri'

open("http://user:pass@www.example.com/secret/page.html").read
#=> ArgumentError: userinfo not supported.  [RFC3986]
#=> from /Users/user/.rbenv/versions/2.1.2/lib/ruby/2.1.0/open-uri.rb:261:in `open_http'

ArgumentError となる。しかも RFC3986 という文字も付いてきて、不穏な雰囲気。

じゃあどうやるのかというと Baisc 認証の場合は以下のようにするのが普通。
第二引数の option として http_basic_authentication に配列で user名、password を渡す。

require 'open-uri'

open("http://www.example.com/secret/page.html", http_basic_authentication: ["user", "pass"]).read
#=> "hello, world!"

dangerous_open_uri の場合

option 指定しなくてよくなる。たったこれだけ。

require 'dangerous_open_uri'

open("http://user:pass@www.example.com/secret/page.html").read
#=> "hello, world!"

dangerous の理由

https://www.ruby-forum.com/topic/95983

open-uri('http://user:pass@www.host.de/') does not work as expected.

According to RFC3986, supporting userinfo in URI is dangerous, so that
open-uri will not support it.

              matz.
Report post Edit Delete Reply with quote

RFC3986 で dangerous とされているため、open-uri ではサポートしないよ、と仰ってます。

本当に dangerous?

内部的には

  • userinfo がある場合は http_basic_authentication に user と password 入れる
  • userinfo を空にする
  • OpenURI.open_http を呼ぶ

ということやってるだけなので、ほとんど open-uri です。
したがって open-uri の安全精度とほぼ変わらないはず。(と筆者は考えている)

まとめ

一晩で作れるような代物だったので、フットワーク軽く作れたと思う。重かったらこうはならない。
重くてもサラッと作れるようになっていきたい。

名前は dangerous だけど、dangerous じゃなく作ったつもりです。
マジで危ない作りになっていたら PR ください。

tmux のコピーモードでのコピーがうまくいかない件

イントロ

告白すると tmux + reattach-to-user-namespace でコピーできます! って記事を見てその通りにやってみるものの、うまくいかない人でした。
ようやくこの病気を克服したので残す。

tmux 1.8 のお話。

現象

どううまくいかないかというと、長い文字列をコピーしようとすると失敗する。
確かにコピーしたはずの文字列が、何故か truncate されてしまう現象といったらいいのだろうか。
ちなみに文字列が短かったりすると、ちゃんとコピーできる。

今までは文字が切れそうなら option 押しながらドラッグしていたが、相当苦しかった。

今まで

set-option -g default-command "reattach-to-user-namespace -l zsh"

曰く、tmux 上で pbcopy/pbpaste がうまく動かないらしく、そのバグを直した wrapper が reattach-to-user-namespace である、とのこと。
そこで上記の設定を追加することで、tmux 上で pbcopy/pbpaste 使える、という話をよく聞く。

だがこれだけだとダメだった。

解決法

以下の二行を .tmux.conf に追加する。

bind -t emacs-copy M-w copy-pipe "reattach-to-user-namespace pbcopy"
bind -t emacs-copy C-w copy-pipe "reattach-to-user-namespace pbcopy"

デフォルトでは M-w の方には copy-pipe が設定されておらず、文字が切れてしまうようだ。
C-w は copy-pipe されていたが、M-w は copy-pipe されておらず、いつも M-w を使っていたので気付かなかった。

M-w でも C-w でも両方 copy-pipe するためには、両者設定を書く必要がある。
ちゃんと設定されたかどうかは、以下のコマンドで確認できる。-t は key-map のデーブルを指定するオプション。(テーブルだから t )

tmux list-keys -t emacs-copy
...
     C-w copy-pipe "reattach-to-user-namespace pbcopy"
     M-w copy-pipe "reattach-to-user-namespace pbcopy"
...

copy-pipe されていたら、設定されている証拠。

No bundle exec

イントロ

bundle exec したくない、という話。随分前に調べたやつ。

  • bundle exec メンドイ
    • しかも使用頻度高い
  • コマンド自体が長くなって、初めて見るコマンドを覚えづらい
    • bundle exec 以降を覚えればいいけど、ついつい全部覚えてしまう。
    • コマンドが長いとそれだけで疲れる
    • しかも bundle exec 自体は本質的ではない
  • alias be='bundle exec' とかあるけど、be 打つのもだるい

という問題意識があります。

候補

実は探せば結構ある。自分が触ったのは以下の 3 つ

結論

direnvrbenv-bundler > rbenv-binstubs

今は何も考えず direnv で良いと思う

direnv

安定の direnv さん。 新しい rails なら PATH_add bin もやっておくと良い。

方法

bundle install --path vendor/bundle --binstubs=vendor/bundle/bin
direnv edit

PATH_add vendor/bundle/bin # この一行を追加して save

長所

  • 拡張性の高さ
  • go 製なので独立したアプリケーション
  • no bundle exec 以外にも使える

短所

  • ちょっと手順が多い
  • --binstubs を忘れると OUT

rbenv-bundler

以前使用していた
最近 update したら、使えなくなってた。
その後 direnv に乗り換えた。

方法

bundle install --path vendor/bundle
rbenv rehash

長所

  • 移行コストが非常に低い
    • いつもと変わらぬ感じで利用できる

短所

  • 重い
  • 今は使えない

rbenv-binstubs

binstubs を指定するのがダルくて、rbenv-bundler に移行した。 これをつかうなら direnv で良いと思う

方法

bundle install --path vendor/bundle --binstubs=vendor/bundle/bin
rbenv rehash

長所

  • ないかも...

短所

  • binstubs 忘れたら OUT
  • direnv と比較すると、下位互換的な感じ
    • 実質 bundler でしか機能しないので

hipchat_searcher という gem を作った

イントロ

随分前に作りました。動機はまだ無い。

強いていうならば「お手軽で作りやすかったから」という自分勝手な理由です。
使いやすそうであれば使ってみてください。

mgi166/hipchat_searcher · GitHub

何ができるか

コマンドラインから hipcaht のログを検索できます。
たったそれだけ。

hipchat の検索って結構ダルくて

  1. アプリで 「⌘ + f
  2. 何故かブラウザが開く(白目)
  3. ここで検索クエリを入力

    f:id:mgi:20140924094114p:plain

  4. 沢山結果が返ってくる

    f:id:mgi:20140924093530p:plain

  5. 疲れる

というパターンがある。
古い発言を探したい時などは、結構苦しい。
ログあるけど後から探せないんじゃ、何のためのログなのか。

この鬱憤が少しづつたまり、そして gem を作ったわけです。

インストール

gem install hipchat_searcher

いつも通り。

使い方

mgi166/hipchat_searcher · GitHub に書いてある。

hps {検索ワード}

  • -r で room 名の指定
  • -u で user 名の指定
  • -e で全部検索(hipchat api の仕様上、間近 100 件以上のメッセージを検索対象とする場合は、このオプションを指定する)
  • -d で日付指定
  • 他多数

まとめ

気が向いたので紹介してみました。
怪しい挙動をしていたら、すぐにこちらまで。