JavaScript (数値) 配列から最小値・最大値を取得する

こんな方法もあるなと今日知ったので備忘録的に…

var a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
Math.min.apply(null, a);  // -> 1
Math.max.apply(null, a);  // -> 10

ちなみに, Arrayインスタンスだけでなく, Typed Array (ArrayBufferView) でも可能です.

var a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
var u = new Uint8Array(a);
var f = new Float32Array(a);

Math.min.apply(null, u);  // -> 1
Math.max.apply(null, u);  // -> 10
Math.min.apply(null, f);  // -> 1
Math.max.apply(null, f);  // -> 10

JavaScript Fullscreen API

特定の要素をフルスクリーンにする場合

if (element.webkitRequestFullscreen) {
    element.webkitRequestFullscreen(Element.ALLOW_KEYBOARD_INPUT);
} else if (element.mozRequestFullScreen) {
    element.mozRequestFullScreen();
} else if (element.msRequestFullscreen) {
    element.msRequestFullscreen();  // IE 11 (IE 11未満は未対応)
} else if (element.requestFullscreen) {
    element.requestFullscreen();
} else {
    throw new Error('Cannot change to full screen.');
}

フルスクリーンを解除する場合

if (document.webkitCancelFullScreen) {
    document.webkitCancelFullScreen();
} else if (document.mozCancelFullScreen) {
    document.mozCancelFullScreen();
} else if (document.msExitFullscreen) {
    document.msExitFullscreen();
} else if (document.cancelFullScreen) {
    document.cancelFullScreen();
} else if (document.exitFullscreen) {
    document.exitFullscreen();
} else {
    throw new Error('Cannot exit from full screen.');
}

フルスクーン状態の要素の取得

var fullscreenElement = null;

if (document.webkitFullscreenElement) {
    fullscreenElement = document.webkitFullscreenElement;
} else if (document.mozFullScreenElement) {
    fullscreenElement = document.mozFullScreenElement;
} else if (document.msFullscreenElement) {
    fullscreenElement = document.msFullscreenElement;
} else if (document.fullscreenElement) {
    fullscreenElement = document.fullscreenElement;
}

フルスクリーンイベントの検知

document.addEventListener('webkitfullscreenchange', function(event) {}, false);
document.addEventListener('mozfullscreenchange', function(event) {}, false);
document.addEventListener('MSFullscreenChange', function(event) {}, false);
document.addEventListener('fullscreenchange', function(event) {}, false);

また, フルスクリーン状態におけるスタイルを設定することも可能です.

#element:-webkit-full-screen {
    /* ... */
}

#element:-moz-full-screen {
    /* ... */
}

#element:-ms-fullscreen {
    /* ... */
}

#element:fullscreen {
    /* ... */
}

gulp watch

gulpの場合, ファイルの変更監視はGruntのようにプラグインをインストールする必要はなく標準で利用可能です.

例として, js/sample.jsの変更を監視して, 変更があれば圧縮し, build以下に格納する場合のgulpfileは以下のようになります.

var gulp   = require('gulp');
var uglify = require('gulp-uglify');

gulp.task('build', function() {
    gulp.src('js/sample.js')
        .pipe(uglify())
        .pipe(gulp.dest('build/'));
});

gulp.task('watch', function() {
    gulp.watch('js/sample.js', ['build']);
});

gulp タスク順序

task1 -> task2 -> task3 の順でタスクを実行したい場合, 以下のようにgulpfileを記述しても, 必ずしもその順序性は保証されません.

var gulp = require('gulp');

gulp.task('task1', function() {
    console.log('task1 done');
});

gulp.task('task2', function() {
    console.log('task2 done');
});

gulp.task('task3', function() {
    console.log('task3 done');
});

gulp.task('default', ['task1', 'task2', 'task3']);

その理由は, gulpはタスクを並列処理されるからです. 順序性を保証するには以下のように記述します.
重要なポイントは, taskメソッドの第2引数とreturn文です.

var gulp = require('gulp');

gulp.task('task1', function() {
        return console.log('task1 done');
});

gulp.task('task2', ['task1'], function() {
        return console.log('task2 done');
});

gulp.task('task3', ['task2'], function() {
        console.log('task3 done');
});

gulp.task('default', ['task3']);

gulp

gulpとはNode.jsを利用した, フロントエンドまわり (JavaScriptやCSS) のタスク自動化ツールです.

同様のツールにGruntがありますが, Gruntよりも記述が簡単なことや高速であることから, 最近ではgulpが利用されるケースが増えています.

Gruntもそうですが, gulpもNode.jsとnpmを必要とするツールですので, Node.jsとnpm がインストールされている必要があります.

また, プロジェクトのディレクトリでpackage.jsonも作成しておきます.

まずは, gulpをグローバルにインストールしておきます.

$ sudo npm install -g gulp

以下のようにバージョンが表示されればインストール完了です.

$ gulp -v
[14:37:04] CLI version 3.9.0

gulpがインストールできたら, プロジェクトのディレクトリでgulpfile.jsを作成します.
例えば, src/sample.jsをbuild/以下にコピーするタスクは以下のように記述します.

gulpfile.js

// GruntのloadNpmTasksに相当
var gulp = require('gulp');

// GruntのregisterTaskに相当
gulp.task('copy', function() {
    gulp.src('src/sample.js')
        .pipe(gulp.dest('build/'));
});

続いて, JavaScriptのファイルを圧縮するタスクを追加します.
そのためには, gulp-uglifyをインストールしておきます.

$ npm install --save-dev gulp-uglify
// GruntのloadNpmTasksに相当
var gulp   = require('gulp');
var uglify = require('gulp-uglify');

// GruntのregisterTaskに相当
gulp.task('build', function() {
    gulp.src('src/sample.js')
        .pipe(uglify())  // GruntのinitConfigに相当
        .pipe(gulp.dest('build/'));
});

さらに, 圧縮後のファイルとわかるようにファイル名を変更するタスクも追加します.
そのためには, gulp-renameをインストールしておきます.

$ npm install --save-dev gulp-uglify
// GruntのloadNpmTasksに相当
var gulp      = require('gulp');
var uglify    = require('gulp-uglify');
var rename = require('gulp-rename'); 

// GruntのregisterTaskに相当
gulp.task('build', function() {
    gulp.src('src/sample.js')
        .pipe(uglify())  // GruntのinitConfigに相当
        .pipe(rename('sample.min.js'))  // GruntのinitConfigに相当
        .pipe(gulp.dest('build/'));
});

Travis CI + Karma + Chrome でCI

Travis CIでKarma + ChromeでCIするための設定を備忘録的に…

.travis.yml

language: node_js
node_js:
    - 0.12
before_install:
    - export CHROME_BIN=chromium-browser
    - export DISPLAY=:99.0
    - sh -e /etc/init.d/xvfb start
script: karma start --single-run

karma.conf.jsに以下の記述を追加します.

module.exports = function(config) {
  config.set({
    // ...
        customLaunchers: {
          Chrome_travis_ci: {
            base: 'Chrome',
            flags: ['--no-sandbox']
          }
        },
    // ...
  });

  if (process.env.TRAVIS) {
    config.browsers = ['Chrome_travis_ci'];
  }
};

composer.jsonに依存パッケージを記述する

composer.jsonに依存パッケージを記述するには,

$ composer require phpunit/phpunit

これで, composer.jsonに

"require": {
    "phpunit/phpunit": "4.8.6"
}

のように追記されます.

もっとも, PHPUnitのような依存パッケージは開発時のみに必要なので, –devオプションをつけてインストールします.

$ composer require --dev phpunit/phpunit

–devオプションをつけてインストールすると, composer.jsonに

"require-dev": {
    "phpunit/phpunit": "4.8.6"
}

のように追記されます.

PHP Composerインストール

ComposerはJavaScriptのnpmに相当するパッケージマネージャツールです.

今日はそのインストール方法を備忘録として残しておきます.

といっても, curlでダウンロードして, グローバルにインストールするだけです.

$ curl -sS https://getcomposer.org/installer | php
$ sudo mv composer.phar /usr/local/bin/composer

インストールが完了したことを確認.

$ composer --version
Composer version 1.0-dev (9e67bc761be98b45875855003eb8b2f23f4bf5a5) 2015-09-19 14:32:06

PHPUnit

PHPUnitを利用したPHPのユニットテストについて簡単にまとめておきます.

1. PHPUnitのインストール

$ wget https://phar.phpunit.de/phpunit.phar
$ chmod 755 phpunit.phar

これで ./phpunit.pharとして実行可能になりますが, PATHがとおっている場所に置いておいたほうがグローバルに利用可能なので, 以下のように移動します.

$ (sudo) mv phpunit.phar /usr/local/bin/phpunit
$ phpunit --version
PHPUnit 4.8.6 by Sebastian Bergmann and contributors.

以上のようにバージョンが表示されればインストールは完了です.

2. ユニットテストコード

以下のPHPのクラスのメソッドをテストするとします.

<?php 

final class Calculator {

    private function __construct() {
    }

    public static function add($a, $b) {
        return $a + $b;
    }

    public static function sub($a, $b) {
        return $a - $b;
    }
}

テスト用のクラスはPHPUnit_Framework_TestCaseを継承させ, 慣例として「テスト対象のクラス名 + Test」の命名にします.

また, テストスイート (テストメソッド) には, testXXXのように先頭にtestを付加する必要があります (そうでない場合は, @testアノテーションを記述する必要があります).

<?php

require_once('Calculator.php');

class CalculatorTest extends PHPUnit_Framework_TestCase {
     public function testAdd() {
         $expected = 3;
         $actual   = Calculator::add(1, 2);
         $this->assertSame($expected, $actual);
    }

    public function testSub() {
        $expected = 1;
        $actual   = Calculator::sub(2, 1);

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

以下のようにしてテストを実行します.

$ phpunit CalculatorTest.php
PHPUnit 4.8.6 by Sebastian Bergmann and contributors.

..

Time: 137 ms, Memory: 13.25Mb

OK (2 tests, 2 assertions)

アサーションメソッドやアノテーションに関してはこちらが参考になるかと思います.