rukurxの日記

自分の日々の作業や調べたことのメモ

aliasで設定したコマンドをシェルスクリプト内で実行する

シェルスクリプトを実行したらaliasで追加したコマンドが無いよと怒られた...

./hoge.sh: 行 40: hoge: コマンドが見つかりません

普段コマンドラインで使っているコマンドだったので、???状態。 man bash で見たらインタラクティブモードじゃないとaliasで登録したコマンドが使いえないらしい...

Aliases are not expanded when the shell is not interactive, unless the expand_aliases shell option is set using shopt (see the description of shopt under SHELL BUILTIN COMMANDS below).

そこで、 /etc/bashrc にaliasを登録して、環境変数を渡すことでシェルスクリプト内でもコマンドを実行できるようにした。

$ BASH_ENV=~/.bashrc bash -O expand_aliases  hoge.sh

参考

takafumi-s.hatenablog.com

MySQLのSELECT結果をエクスポートする

MySQLからデータをエクスポートするとtsv形式になる。 オプションでCSVとかの形式も選べるのかと思っていたが、どうやらできなそう。

デフォルトのエクスポートだとtsv形式でファイルに出力される

echo "SELECT * FROM user" | mysql -uroot -p > data.tsv

csv形式にするには出力をsedで変換すれば一応できなくもない

echo "SELECT * FROM user" | mysql -uroot -p | sed 's/"/""/g;s/^/"/;s/$/"/;s/\n//g' > data.csv

ついでにzipにする

echo "SELECT * FROM user" | mysql -uroot -p | gzip -c > data.tsv.zip

csvファイルをzipする

echo "SELECT * FROM user" | mysql -uroot -p | sed 's/"/""/g;s/^/"/;s/$/"/;s/\n//g' | gzip -c > data.csv.zip

参考

obel.hatenablog.jp

privateの静的関数をPHPUnitでテストする

PHPUnitでの private static function のテスト方法がわからなかったのでメモ。

公式のドキュメントを見るとReflectionMethod::invokeArgs に最初の引数にnullを渡してあげればよさそうなのでやってみる。

f:id:rukurx:20181001165403p:plain

PHPUnitをインストールする

$ composer require phpunit/phpunit --dev

privateの静的関数を含んだテスト対象のクラスを作成する

<?php

class Hoge {

  private static function fuga() {
    return 'hello';
  }

}

PHPUnitのテストを書く

<?php
use PHPUnit\Framework\TestCase;

require_once 'Hoge.php';

class HogeTest extends TestCase {

  /**
   * privateの静的関数fugaのテスト
   */
  public function test_fuga() {
    $expected = 'hello';
    $class = new \ReflectionClass(new Hoge());
    $method = $class->getMethod('fuga');

    $method->setAccessible(true);
    // 第一引数にnullを渡すとstaticメソッドが呼べる
    $actual = $method->invokeArgs(null, []);

    $this->assertEquals($expected, $actual);
  }

}

テストを実行する

$ phpunit HogeTest.php
PHPUnit 6.5.5 by Sebastian Bergmann and contributors.

.                                                                   1 / 1 (100%)

Time: 65 ms, Memory: 10.00MB

OK (1 test, 1 assertion)

参考

http://php.net/manual/ja/reflectionmethod.invokeargs.php

GitでプッシュしたコミットのAuthorとCommitterを変更する

Gitの設定でglobalにuser.nameとuser.emailを定義していると、 新しくcloneしてきたリポジトリのコミットにglobalのものが使われてしまう。

プライベートでも業務でも同じアカウント使っていれば問題ないが、別々だとPush後に慌てることになる。

自分がいつも慌ててるなんて言ってないですからね...

AuthorとCommitterを置換するGitコマンド

$ git filter-branch -f --env-filter \
  "GIT_AUTHOR_NAME='<name>'; \
   GIT_AUTHOR_EMAIL='<email>'; \
   GIT_COMMITTER_NAME='<name>'; \
   GIT_COMMITTER_EMAIL='<email>';" \
  <変更対象のコミットの範囲>

変更対象が直近5コミット分の場合は HEAD~5..HEAD になる。 範囲を HEAD だけにした場合は全てのコミットが対象になるので注意。

直近2コミット分のAuthorとCommitterのnameとemailを変更する

まずは、変更前のGitログの状態を確認する。 AuthorとCommitterが見やすいようにオプションはfullを使う。日付も見たい場合は fuller にする。

$ git log --pretty=full
commit 1a5bt8907d771fe348i5bb72130cd8c106f79f01 (HEAD -> master)
Author: hoge <hoge@users.noreply.github.com>
Commit: hoge <hoge@users.noreply.github.com>

    README.md修正2

commit 1df03d52f42048f50a708e5cdd4c01b1r8c651f3
Author: hoge <hoge@users.noreply.github.com>
Commit: hoge <hoge@users.noreply.github.com>

    README.md修正1

commit b1773g0971805ab21241b6e34e5hb403bfaef24b
Author: hoge <hoge@users.noreply.github.com>
Commit: hoge <hoge@users.noreply.github.com>

    init

AuthorとCommitterを変更する

$ git filter-branch -f --env-filter \
  "GIT_AUTHOR_NAME='tanaka'; \
   GIT_AUTHOR_EMAIL='tanaka@example.com'; \
   GIT_COMMITTER_NAME='tanaka'; \
   GIT_COMMITTER_EMAIL='tanaka@example.com';" \
  HEAD~2..HEAD

Gitログを確認する

$ git log --pretty=full
commit 1a5bt8907d771fe348i5bb72130cd8c106f79f01 (HEAD -> master)
Author: tanaka <tanaka@example.com>
Commit: tanaka <tanaka@example.com>

    README.md修正2

commit 1df03d52f42048f50a708e5cdd4c01b1r8c651f3
Author: tanaka <tanaka@example.com>
Commit: tanaka <tanaka@example.com>

    README.md修正1

commit b1773g0971805ab21241b6e34e5hb403bfaef24b
Author: hoge <hoge@users.noreply.github.com>
Commit: hoge <hoge@users.noreply.github.com>

    init

AuthorとCommitが変更されていますね!

でも、これでは間に関係ないコミットが入ってる場合できないので、間違えてコミットしたAuthor/Committer名に該当したコミットだけを対象に変更するようにしたい。

条件に該当したコミットのAuthorとCommitterだけ置換するGitコマンド

Gitのコマンドの中ではシェルの条件分使えるのでそれを利用する。

$ git filter-branch --commit-filter '
        if [ "$GIT_COMMITTER_NAME" = "<target name>" ];
        then
                GIT_COMMITTER_NAME="<name>";
                GIT_AUTHOR_NAME="<name>";
                GIT_COMMITTER_EMAIL="<name@example.com>";
                GIT_AUTHOR_EMAIL="<name@example.com>";
                git commit-tree "$@";
        else
                git commit-tree "$@";
        fi' <対象コミットの範囲>

直近2コミットの中に "tanaka" というcommitter名でコミットされたコミットログを変更する。

$ git filter-branch --commit-filter '
        if [ "$GIT_COMMITTER_NAME" = "tanaka" ];
        then
                GIT_COMMITTER_NAME="Taro Yamada";
                GIT_AUTHOR_NAME="Taro Yamada";
                GIT_COMMITTER_EMAIL="yamada@example.com";
                GIT_AUTHOR_EMAIL="yamada@example.com";
                git commit-tree "$@";
        else
                git commit-tree "$@";
        fi' HEAD~2..HEAD

Gitログを確認する

$ git log --pretty=full
commit 1a5bt8907d771fe348i5bb72130cd8c106f79f01 (HEAD -> master)
Author: Taro Yamada <yamada@example.com>
Commit: Taro Yamada <yamada@example.com>

    README.md修正2

commit 1df03d52f42048f50a708e5cdd4c01b1r8c651f3
Author: Taro Yamada <yamada@example.com>
Commit: Taro Yamada <yamada@example.com>

    README.md修正1

commit b1773g0971805ab21241b6e34e5hb403bfaef24b
Author: hoge <hoge@users.noreply.github.com>
Commit: hoge <hoge@users.noreply.github.com>

    init

条件に一致するコミットのみ変更がされてますね! 個人的にはAuthorやCommiter名で引っ掛けて対象のコミットだけ変更するやり方の方が安心感あっていいなと思います。

参考

idesaku.hatenablog.com

Git - 歴史の書き換え

sohtaro.com

PHPのFakerを使ってテストデータを自動生成する

PHPユニットテストを書いていると、適当なテストデータが必要になる。 毎回テストとかHoge的なテストデータを使っていたので、ちゃんとしたテストデータを使いたかった。 PHPにはFakerというランダムにテストデータを生成してくれるライブラリがあるので早速使ってみた。

github.com

PHPのFaker自体はPerlData::FakerRuby Faker にインスパイアされたものらしい。 PHPでも使えるようにしてもらえて感謝。

$ mkdir faker-sample
$ cd faker-sample
  • FakerをComposer経由でインストールする
$ composer require fzaninotto/faker
$ php -a
Interactive shell

php > // Fakerのオートーロードをrequireする
php > require_once 'vendor/fzaninotto/faker/src/autoload.php';
php > // Faker\Generatorインスタンスを生成する
php > $faker = Faker\Factory::create();
php > echo $faker->name;
Dr. Zachery Ledner V
php > echo $faker->address;
860 Jaskolski Gateway Apt. 806
Rutherfordville, ID 44854-0067
php > echo $faker->text;
Nemo ipsa placeat aut et nostrum perferendis et. Neque dolor accusantium sint sit.
php >

デフォルトではロケールen_USになっているため、英語になる。 ただし、textは何故かラテン語...

php > require_once 'vendor/fzaninotto/faker/src/autoload.php';
php > $faker = Faker\Factory::create('ja_JP');
php > echo $faker->name;
伊藤 春香
php > echo $faker->address;
9584833  佐賀県西之園市東区吉本町佐藤2-4-6
php > echo $faker->text;
Nemo maxime suscipit ut. Enim veritatis enim libero quas necessitatibus id. Et ad aspernatur iusto. Accusamus ut dolores consequuntur.
php >

日本語にするとより自動生成されたテストデータがリアルなものに感じます。 それでもtextはまだラテン語...

ソースを読んでみると都道府県や名前情報を配列でもっている。

Fakerの都道府県定義
Fakerの都道府県定義

Fakerで自動生成できるデータは日本語では現在以下の6種類ある。 日本語形式でなくてもよければ他にも使える。

  • 住所
  • 企業
  • インターネット
  • 電話番号
  • テキスト

どんなものを自動生成してくれるかと、呼び出し方はここのソース読むとわかる。 直下の 各ロケール内のクラスが継承している親クラスと、使いたいロケール内にあるクラスのメソッドをプロパティとして呼び出すことで使うことができる。

  • 人(Person)の場合
php > // 共通メソッド(Person.php)
php > echo $faker->name;
藤本 晃
php > echo $faker->firstName;
学
php > echo $faker->firstNameMale;
修平
php > echo $faker->firstNameFemale;
幹
php > echo $faker->lastName;
近藤
php > echo $faker->title;
Dr.
php > echo $faker->titleMale;
Mr.
php > echo $faker->titleFemale;
Prof.
php > // ja_JPロケールで定義されているメソッド (ja_JP/Person.php)
php > echo $faker->kanaName;
ワタナベ マアヤ
php > echo $faker->firstKanaName;
リョウヘイ
php > echo $faker->firstKanaNameMale;
トモヤ
php > echo $faker->firstKanaNameFemale;
リカ
php > echo $faker->lastKanaName;

使えるテストデータの種類が多いのでPHPUnitでテストする際には必須級のライブラリです。インストールと使い方もとても簡単なのでガンガン使っていきたいと思います。既にかなりお世話になってるけど。

コマンドラインから使えるチートシートを試してみた

コマンドラインを使うことが多いけど、あまり頻繁に使わないコマンドやオプションはすぐに忘れてしまうので、気軽にコマンドラインから呼び出せるチートシートないかと思っていたら、忘れた頃に発見!

github.com

そのまんま cheat って名前だった…

Macにインストールするので、brew search で検索する。

$ brew search cheat # 検索 
==> Formulae
cheat

Homebrewでも管理されているので、brewコマンドでインストールする。 sqlite使ってる様で一緒にインストールされた。

$ brew install cheat # インストール

cheatコマンドを実行するとUsageが表示される。

$ cheat
Usage:
  cheat <cheatsheet>
  cheat -e <cheatsheet>
  cheat -s <keyword>
  cheat -l
  cheat -d
  cheat -v

基本的には cheat <cheatsheet> で確認したいチートシートを指定する。

$ cheat git

どんなコマンドのチートシートがあるか確認したい場合は -l オプションを使うと一覧が表示される。

$ cheat -l

Gitのrebaseなどの特定のオプションについて確認したい時は -s オプションを使うことで該当箇所だけみることができる。多分searchのsと思われる。

$ cheat -s rebase
git:
  # Interactive rebase for the last 7 commits
  git rebase -i @~7

hg:
  hg pull --rebase

自分専用の内容にしたい場合は -e オプションで編集できる。

$ cheat -e git

オプション -v はcheatコマンドのバージョンを出力する。

$ cheat -v
cheat 2.2.3

オプション -dチートシートの格納先を出力する。

$ cheat -d
/Users/hoge/.cheat
/usr/local/Cellar/cheat/2.2.3/libexec/lib/python2.7/site-packages/cheat/cheatsheets

環境変数を使うことで色々と変更できる。

github.com

これで毎回ブラウザに切り替えたりして、ググったりしなくていいので捗りそうです。一応ネットに繋がってなくても使えるのでその辺も便利かもしれないです。

Composer使ったのでメモ

Composerとは

Composerはライブラリの依存関係を管理してくれるツールです。 ライブラリAを使おうとしたら、内部的にライブラリBやCを使っていることがあります。ライブラリAを使うために自分でBやCをインストールしたりするのは手間がかかります。

getcomposer.org

Composerを使ってライブラリAをインストールすると、いい感じに依存しているライブラリBとCもインストールしてくれます。

# パッケージAをインストールすると、依存するパッケージB, Cもインストールしてくれる
$ composer require パッケージA

ただし、依存するライブラリBとCがcomposerに対応している必要があります。

Composerをインストールする

公式サイトのダウンロードページからダウンロードする。 getcomposer.org

Composerでプロジェクトを作成する

$ composer init

設定を色々と聞かれた後に composer.json ファイルが作成される。 composer.jsonにはライブラリの依存関係が記載されている。 Composer.jsonがあるディレクトリで以下コマンドを実行すると、依存しているライブラリをインストールしてくれます。

$ composer install

プロジェクトの作成はテンプレートを使うこともできる。

# laravelの場合
$ composer create-project --prefer-dist laravel/laravel PROJECT_NAME

パッケージをインストールする

$ composer require パッケージ名:タグ
例)
$ composer require package:dev-master

パッケージの情報はcomposer.jsonに記載され、インストールしたバージョン等の情報はcomposer.lockに記載される。 composer.lockファイルはComposerでライブラリをインストールする際に作成される。 composer.jsonに記載されている、インストールしたパッケージのバージョンなどの情報が保存されている。 composer.lockを共有することで、他の人があとでcomposerを使ってインストールすると同じバージョンのライブラリをインストールしてくれる。

パッケージを削除する

$ composer remove パッケージ名

composer.jsonとcomposer.lockからもパッケージ名が削除される。

パッケージを全て最新化する

$ composer update

パッケージを新しくしたい時に実行する。composer.lockの内容を無視して、composer.jsonにあるパッケージを最新の状態でインストールして、composer.lockも更新される。 composer.jsonに記載されているパッケージが全て最新になる。

特定のパッケージだけ最新化する

$ composer require パッケージ名

気軽にupdateするとcomposer.jsonに記載されている全てのパッケージが更新されてしまうので、パッケージ名を指定して更新する。 パッケージをインストールするときと同じ。

オートローダを作成・更新する

$ composer dump-autoload

autoload.phpが作成・更新される。

参考

qiita.com