著者アーカイブ 杉浦

著者:杉浦

Chromeブラウザ上でJSONを楽にわかりやすく見るJSON Viewer

 JSON Viewer – Chrome ウェブストア
tulios/json-viewer: It is a Chrome extension for printing JSON and JSONP.
 JSON ViewerはGoogle Chromeの拡張の一つでChrome上でJSONを整形して色付けして見せてくれます。これを利用することで簡単にJSONで送られてきたデータを視認できます。
 特に威力を発揮するのは次の様な圧縮されたJSONです。何が何だか分からないですし、単に黒一色で整形しただけではまだ読みにくいです。

 上のJSONをJSON Viewerを通してみた結果が次です。ずいぶん縦長ですが読みやすくなりました。

 階層構造のデータを読むときにあるとないとで全然違う、任意のデータの塊を広げる畳むの機能も備えています。この機能は図の赤丸部から動作します。

 これで長大なデータの中腹や末尾付近にある目的の項目も楽に探せます。開発者ツールでいちいち開いたり、どこかのサービスやエディタにコピペ、整形とするよりずいぶん楽になります。

著者:杉浦

pythonの人間のためのHTTPライブラリRequests

 Requests: HTTP for Humans™ — Requests 2.20.1 documentation
 requests · PyPI
 Requestsは人間に優しいHTTP通信用ライブラリです。ちょっとしたリクエストをAPIに送る時などに便利です。次のコード例はbacklogの課題追加APIです。backlogの課題はまとめて追加することが多くいちいちUIで記述をするのは面倒です。APIでまとめて送ることで楽が出来ます。

import requests

BACKLOG_URL = "https://hogehoge.backlog.jp/api/v2/issues"
API_KEY = "hogehogefugafuga"
PROJECT_ID = 104607  # プロジェクトID
ISSUE_TYPE_ID = 485681  # 課題種別ID
CATEGORY_ID = 279257  # カテゴリID
PRIORITY_ID = 3  # 優先度
ASSIGNEE_ID = 251977  # ユーザID

request_data = [
    {
        'summary': '会員登録機能',
        'startDate': '2018-12-07',
        'endDate': '2018-12-08',
    }, {
        'summary': '会員削除機能',
        'startDate': '2018-12-08',
        'endDate': '2018-12-09',
    }
]
for data in request_data:
    BACKLOG_PARAMS = {
        'apiKey': API_KEY,
        'projectId': PROJECT_ID,
        'summary': data['summary'],
        'issueTypeId': ISSUE_TYPE_ID,
        'categoryId[]': CATEGORY_ID,
        'priorityId': PRIORITY_ID,
        'startDate': data['startDate'],
        'endDate': data['endDate'],
        'estimatedHours': 7,
        'assigneeId': ASSIGNEE_ID,
    }

    response = requests.post(BACKLOG_URL, params=BACKLOG_PARAMS)
    print(response)

 requetsでリクエストを送るのは簡単です。送信メソッド毎(get,post,put,patch,delete)のメソッドがrequests内に用意されており、それの引数に文字列のURLと辞書型のボディを渡すだけです。これだけの設定でファイルを実行するとリクエストが送られます。
 細かい設定、細かい結果の取得も簡単にできます。

>>> r = requests.get('https://api.github.com/user', auth=('user', 'pass'))
>>> r.status_code
200
>>> r.headers['content-type']
'application/json; charset=utf8'
>>> r.encoding
'utf-8'
>>> r.text
u'{"type":"User"...'
>>> r.json()
{u'private_gists': 419, u'total_private_repos': 77, ...}
著者:杉浦

trait中の関数を差分プログラミングをする

 traitはクラス中に現れる共通のプロパティ、メソッドをまとめて記述するための仕組みです。コード中におけるその扱いは継承に似ています。継承を行った場合、スコープ定義演算子をもちいることによってコードをコピペせずにちょっとだけ処理を付け足すことが出来ます。

class ChildHoge extends ParentHoge
{
  public function __construct()
  {
    //親のコードの処理前に付け足す処理の部分
    parent::__construct();
    //親のコードの処理後に付け足す処理の部分
  }
}

 このように便利なスコープ定義演算子ですが、traitを指すことはできません。traitでこれに似たことをしたい時、名前の変換を行うことによって実現ができます。元のコードを別名として扱い、traitを読み込んだクラスで元々の名前のメソッドを実装することによってクラス外のふるまいを変えることなくちょっと付け足しただけの差分プログラミングができます。

class ChildHoge
{
  use FugaTrait {__construct as traitConstruct;}
  
  public function __construct()
  {
    //トレイトのコードの処理前に付け足す処理の部分
    $this->traitConstruct();
    //トレイトのコードの処理後に付け足す処理の部分
  }
}
著者:杉浦

foreachとPHPDocとIDE

 IDEの補完機能は便利です。複雑なオブジェクトのプロパティ、メソッドを網羅し、入力をサポートしてくれます。
 
 これは変数の型を推論することと型の内容を把握することによって実現されています。ここでforeachを使った場合、次の様になる時があります。

 静止画のためわかりにくいですが、予測が出来なくなっています。これは推論が不能になったため起こっています。型推論の主な道筋はそれを導くために用いられた関数、演算子などによる型の連想です。ここで起こっていることはarrayの中に入っている値の型が推論できない、ということです。これを解決するためにPHPDocによる型の説明を用いることが出来ます。

/** @var Members $member */

 このPHPDocコメントを書くことによって$memberはMembers型であるとIDEに示すことができ、IDEは型による補完機能を動かしてくれました。

著者:杉浦

phpの三項演算子の一種エルビス演算子

PHP: 比較演算子 – Manual

PHP 5.3 以降では、三項演算子のまんなかの部分をなくすこともできるようになりました。 式 expr1 ?: expr3 の結果は、expr1 が TRUE と同等の場合は expr1、 それ以外の場合は expr3 となります。

 phpの三項演算子は真ん中の部分を省略して記述することが出来ます。この記述?:はエルビス・プレスリーの顔文字にならってエルビス演算子と通称されています。google画像検索などではエルビス・プレスリーの写真に?:を当てはめた画像が大量にヒットします。エルビス演算子による記述を用いたコードは次の様になります。

$c = $a ? $a : $b;
$c = $a ?: $b;

 {}もelseも必要にならないが条件分岐が欲しいときはよくあります。特定の条件――次の例では投稿された記事の編集権限の有無――によって早期returnを促すガード節はエルビス演算子を用いることによって簡単に記述できます。

auth()->user()->hasAccess($edit_post) ?: abort('403');

 null合体演算子??は$hoge ?? $fugaでisset($hoge) ? $hoge : $fugaという式を表していたのに対し、エルビス演算子は緩やかな比較を用いたTRUEであるか否かの式を表します。$hoge ?: $fugaならば $hoge == true ? $hoge : $fugaといった具合です。これにより次の画像の様な違いが現れます。

著者:杉浦

laravelのEloquentクラスのbootメソッド

 laravelはモデルの基盤をEloquentというクラスで定義しています。boot()はこのEloquentが呼び出されたときに走ることになる関数です。laravel5.6のソースコード(vendor\laravel\framework\src\Illuminate\Database\Eloquent\Model.php)には次の様にあります。

    /**
     * The "booting" method of the model.
     * モデルの「初期起動」メソッド
     *
     * @return void
     */
    protected static function boot()
    {
        static::bootTraits();
    }

    /**
     * Boot all of the bootable traits on the model.
     * モデル上の起動可能なすべてのtraitを起動します
     *
     * @return void
     */
    protected static function bootTraits()
    {
        $class = static::class;

        $booted = [];

        foreach (class_uses_recursive($class) as $trait) {
            $method = 'boot'.class_basename($trait);

            if (method_exists($class, $method) && ! in_array($method, $booted)) {
                forward_static_call([$class, $method]);

                $booted[] = $method;
            }
        }
    }

 これにある様にbootはbootTraitsを呼びだしbootTraitsは頭にbootクラス名とあるtraitのメソッドを呼び出します。bootメソッドに追記する事、bootトレイトを作ることでモデル呼び出し時に様々なことが出来ます。特に便利な使い方はグローバルスコープです。グローバルスコープは次の様に記述する事でクエリビルダを呼び出す際に必ず記述したクエリがつくというものです。

    protected static function boot()
    {
        parent::boot();
        static::addGlobalScope('auth_post', function (Builder $builder) {
            $post_key = Users::findOrFail(auth()->id())->post_key;

            $builder->where('post.primary_key', $post_key);
        });
    }

 上記のコードでは今ログインしているuserに関連するpostでwhereをかけています。ログインしているユーザに関してのみのデータを扱う、という処理は頻繁に現れます。このようなほぼ必ずするべき記述をモデルクラス内の各メソッドで何度も記述することは無駄であり、bootメソッドの利用はこれを解決します。

著者:杉浦

PHPのNull合体演算子

 PHPはユーザの投げてきた値、DBから取得した値といった、存在するかも怪しい値を扱うことが多いです。この問題への対策の定番は条件文とissetです。issetは変数がセットされていること、そして NULL でないことを検査する関数です。
PHP: isset – Manual
PHP: PHP 型の比較表 – Manual
条件文とissetを用いて真面目に素朴な書き方をするならば次の様になります。

if(isset($_GET['user'])){
    $user = $_GET['user'];
} else {
    $user = 'nobody';
}

 5行になりました。この処理と同じ処理を何度も記述する場合、ソースコードは巻物の様に長くなります。条件文がシンプル、行う処理もシンプル、であるならば三項演算子がきれいに記述をしてくれます。三項演算子を用いた例は次になります。

$user = isset($_GET['user']) ? $_GET['user'] : 'nobody';

 1行に収まりずいぶんましになりました。しかしながら、ある値が存在するならばその値を扱うという処理は定番であり、三項演算子を用いた場合、二重にある値――例ならば$_GET[‘user’]の繰り返し――が冗長です。Null合体演算子はこれを解決します。Null合体演算子による記述は次です。

$user = $_GET['user'] ?? 'nobody';

PHP: 比較演算子 – Manual
 もうこれ以上ないくらいシンプルな記述になりました。最初のif文と同じ働きをしますが行数は1行、横の長さも大して変わりません。長大な参照名がついてしまっていても変数を増やさず二行で書けます。

$user_point_total = User::findOrFail($_POST['primary_key'])->userPointTotal->point_total
   ?? UserPointTotal::$default_points;
著者:杉浦

ESLintのJSDoc用プラグインeslint-plugin-jsdoc

End-of-Life for Built-in JSDoc Support in ESLint – ESLint – Pluggable JavaScript linter
 ESLintはJavaScriptの詳細で厳密なチェックをし、簡単なものによっては修正も行ってくれる検証ツールです。JSDocは次の様なJavaScript中のコメントのテンプレートです。

    /**
     * 現在のソートの状態からアイコンを表示するべきかを判断する
     * @param {String} column カラム名
     * @param {String} ascOrDesc 昇順か降順か
     * @return {Boolean} アイコンを表示するべきならtrue
     */
    shouldDisplayIcon: function(column, ascOrDesc) {

 JSDocは読みやすいことの他にもIDE等ソースコードを対象としたアプリ―ケーションで利用でき便利です。ESLintもJSDocを素でサポートしていたのですが、ESLintとJSDocの発展とメンテナ(スタッフみたいなもの)の規模の関係からJSDocのサポートが打ち切られました。これに従って、既存のJSDoc用ルールが非推奨ルールになりました。ESLintが勧めるJSDoc関連ルールを設定できる移行先プラグインがeslint-plugin-jsdocです。
eslint-plugin-jsdoc – npm
 eslint-plugin-jsdocはESLint本体よりもJSDocに詳細なルールが用意されており、より厳密なルールによってJSDocを検証できます。readmeに載っていませんがrecommendedによるルールのプリセットも用意されています。次の様に.eslintrc.jsonに記述してサクッと使えます。

  "plugins": [
    "jsdoc"
  ],
  "extends": [
    "plugin:jsdoc/recommended",
  ],
著者:杉浦

laravelのモデルであるEloquent ORMのCRUDに使うための便利な機能

Eloquent:利用の開始 5.6 Laravel
 Eloquent ORM(Object Relational Mapping)はPHPのフレームワークlaravelで実装されているSQLによるデータ操作をするモデル部分のことです。laravelでモデルを記述する際、多くの場合で以下の様に継承をします。

use Illuminate\Database\Eloquent\Model;

class Flight extends Model
{
    //
}

 このIlluminate\Database\Eloquent\Model;の中にあるCRUDに使える特に便利な機能を少し紹介します。少し詳しくは冒頭のリンクの説明書、とても詳しくはソースコード参照です。laravelのソースコードはとても丁寧で読みやすいためソースコードだけでも理解が進みます。
 全件取得をする時は次の様に記述できます。

$flights = Flight::all();

 これでSELECT * FROM Flights;の結果をCollection(配列の拡張形式)に変換した相当です。カラムを絞ることも簡単です。

$flights = Flight::all('primary_key', 'created_at');

 これでSELECT primary_key,created_at FROM Flights;の結果をCollection(配列の拡張形式)に変換した相当です。この様によく使われるパターンにはシンプルな回答が大体用意されています。
 ある1件を主キーを頼りに取得する時は次の様に記述できます。

$flight = Flight::find(1);

 これでSELECT * FROM Flights WHERE id = 1;の結果をモデルクラスFlightに変換した相当です。findした場合、対象が存在しないことも考えられます。そのためfindOr***の形で処理が用意されています。

$flight = Flight::findOrFail(2);
$flight = Flight::findOrNew(2);

 前者は見つからなかった場合、404エラーがユーザに返されます。後者は見つからなかった場合、新たにレコードを作成します。
 レコードを作成する時は次の様に記述できます。

$new_flight = [
    'name' => 'hoge',
    'mail' => 'fuga@example.com'
];
Flight::create($new_flight);

 create([‘カラム名’=>値の連想配列])これだけで新たにレコードがFlightsテーブルに追加されます。
 更新する時は次の様に記述できます。

$update_data = [
    'name' => 'fuga',
];
$flight = Flight::findOrFail(1);
$flight->fill($update_data)->save();

 これもcreateに似ています。fillでは渡されたカラム名のデータのみを更新します。createと違ってこちらはより複雑な操作を繰り替えすことも考えられており、save()と命令する必要があります。
 論理削除をする時はモデルにtraitを増やす必要があります。増やさない場合は物理削除です。

class Flight extends Model
{
    use SoftDeletes;
}

 実際に削除する時は次です。

$flight = Flight::findOrFail(1);
$flight->delete();

 これで作成、読み取り、更新、削除でCRUD制覇です。いずれも非常にシンプルに記述でき、大変便利です。

著者:杉浦

googleスプレッドシートのメール通知機能

 googleスプレッドシートは無料で多人数の共同作業を容易に行うことのできるExcelの様な表を扱うwebサービスです。長期に渡って多人数で共同作業を行う際、編集が行われたことを知る機能の有無は重要です。定期的に見る、ということもできますが手間であり漏れも出がちです。googleスプレッドシートにはgmailに対して通知を行う機能が備わっています。
スプレッドシートの通知をオンにする – パソコン – ドキュメント エディタ ヘルプ
 やり方は簡単。画像の様にツール > 通知ルールと開いて、通知のタイミングを設定、保存、完了するだけです。これでgoogleスプレッドシートを開いているgoogleアカウントに向かって通知メールがルールに従ってその都度送信されます。