読者です 読者をやめる 読者になる 読者になる

かもメモ

自分の落ちた落とし穴に何度も落ちる人のメモ帳

Node.js nvmからnodebrewに乗り換えるぞい!

node.js nvm nodebrew Homebrew

Node.jsのバージョンをv6.9.2に上げるにあたって、npmでグローバルにインストールしたパッケージを移行できるコマンドがあるということだったので、Node.jsのバージョン管理をnvmからnodebrewに乗り換えるました。npmのパッケージ結構容量を取るので...

nvmをアンイントールする

$ npm cache clean
$ rm -rf $NVM_DIR ~/.npm ~/.bower

~/.bashrc~/.bash_profileに書かれているnvm関連のパスを削除

# 下記の記述を削除
source ~/.nvm/nvm.sh
npm_dir=${NVM_PATH}_modules
export NODE_PATH=$npm_dir

homebrewでインストールしたnodeを削除

かなり昔にhomebrewでインストールしたnodeが残っていたので、これもアンインストールしてしまいます。

npmを削除

$ npm cache clean
$ cd /usr/local/lib
$ sudo npm uninstall npm
$ rm -rf /usr/local/bin/npm

homebrewでインストールされているnode.jsを削除

$ sudo brew uninstall node

~/.bashrc~/.bash_profileに書かれているhomebrewのnpmのパスを削除

# 下記の記述を削除
export PATH="/usr/local/share/npm/bin:$PATH"

nodebrewをインストール

1. インストール

$ curl -L git.io/nodebrew | perl - setup

2. nodebrewのパスを追加
~/.bashrc~/.zshrcに下記を記述して保存する

export PATH=$HOME/.nodebrew/current/bin:$PATH

3. 追加したパスを反映

$ source ~/.bashrc

nodebrewでNode.jsをインストール

nodebrewの0.6.0をリリースしました。install-binaryというコマンドを追加しまして、コンパイル済みのバイナリからインストールできるようにしました。
nodebrewでバイナリからインストールできるようにした

install-binaryコマンドでコンパイル済みのnodeをダウンロードします。

$ nodebrew install-binary v6.9.2

※ 通常のinstallコマンドでインストールすると、ダウンロードしてからコンパイルするので少し時間がかかってしまいます。

$ nodebrew install v6.9.2

使用するNode.jsのバージョンとデフォルトのバージョンを指定

# 使用するバージョン
$ nodebrew use v6.9.2
# デフォルトで使用するバージョン
$ nodebrew alias default v6.9.2

インストールの確認

別途ターミナルを起動して、nodeのバージョンを確認

$ node -v
v6.9.2

指定したバージョンが表示されていればOK。
別のバージョンが表示される場合は、nodebrewのパスが通ってなかったり、他のnodeのパスなどが残っている可能性が高いので$ which nodeでnodeのパスを調べたり、~/.bashrc~/.bash_profileの記述を再チェックしてみると良いと思います。

globalにインストールしたnpmのパッケージの移行

nodebrewではmigrate-package <version>コマンドで<version>のglobalにインストールされたパッケージの移行ができる。

# Install global NPM packages contained in <version> to current version
$ nodebrew migrate-package <version>

<version>は移行元を指定する。

ex: v5.9.0 にインストールしたパッケージを現在のバージョンに移行する場合

$ nodebrew migrate-package v5.9.0

[参考]

WordPress ContactForm7 フォーム送信時に送信確認のチェックをリセットしたい

Contact Form 7 WordPress jQuery javascript

ContactForm7は送信前の確認したかのチェックボックスを設置することができます。
ただ、フォームを送信した後、エラーの有無にかかわらず送信確認がチェックされたままで、送信ボタンを押すことができる状態になったままになっています。
そこで、ContactForm7で用意されているtriggerのイベントを利用して、フォーム送信後に送信確認のチェックを外して送信ボタンをdisabledに戻すようにしてみました。

triggerを利用するので、サイトで使ってあるテーマのjsファイルなどに記述すればOKです。
利用するイベントについては、WordPress ContactForm7 フォーム送信時に任意のjsを実行したい。 - かもメモ を参照ください。

$(function() {
  var $form = $('.wpcf7-form');

  var onRresetAcceptance = function(evt) {
    var $form = evt.data.form,
        $submit = $form.find('input:submit');

    if( !$submit.length ) {
      return;
    }

    $form.find('input:checkbox.wpcf7-acceptance').each(function(i, elm) {
      var $acceptance = $(elm),
          is_invert = $acceptance.hasClass('wpcf7-invert'),
          is_checked = $acceptance.prop('checked');
      if( (is_invert && !is_checked)
       || (!is_invert && is_checked) ) {
          $acceptance.prop('checked', !is_checked).trigger('change');
          $submit.prop('disabled', true);
       }
    });
  };

  if( $form.length ) {
    $(document).on('submit.wpcf7', {form: $form}, onRresetAcceptance);
  }
});

フォーム送信時になぜか、submit.wpcf7が二回呼ばれてしまっているのですが、この様な感じでフォーム送信時に送信確認をリセットして送信ボタンをdisabledにする事ができました。


[参考]

WordPress ContactForm7 フォーム送信時に任意のjsを実行したい。

WordPress javascript jQuery Contact Form 7

管理画面から

WordPressの管理画面 > コンタクトフォームの編集画面 > その他の設定
を選択して、記入エリアにon_sent_ok:(送信完了時)、on_submit:(送信された時常に) のキーワードに続けて実行したいjavascriptのコードをテキスト形式で記述する。

on_sent_ok: "alert('sent ok');"
on_submit: "alert('submit');"

恐らく最も簡単な方法です。google Analyticsのコードを追加したりはこれで十分だと思います。
しかし、複雑なコードを書いたり、自前のスクリプトで即時関数の中にあるオブジェクトなどを触ろうとすると少し大変です。

設定されているdispatcherを利用する

ContactForm7がサイト上で実行しているjsファイルを見ていると次のようなdispatcherが設定されていました。

// contact-form-7/includes/js/scripts.js
$(data.into).trigger('invalid.wpcf7'); // deprecated
$(data.into).trigger('spam.wpcf7'); // deprecated
$(data.into).trigger('mailsent.wpcf7'); // deprecated
$(data.into).trigger('mailfailed.wpcf7'); // deprecated
$(data.into).trigger('submit.wpcf7'); // deprecated

管理画面から設定できる on_sent_okon_submit はそれぞれ mailsent.wpcf7submit.wpcf7 でイベントの発火を受け取ることができそうです。
それ以外にもエラーになった時やメール送信失敗時のevent dispacherも用意されています。

on_submit (送信された時常に) 実行したい場合は次のようにdocumentにイベントを付けておけばOKです。

$(document).on('submit.wpcf7', function(evt) {
  alert('submit');
});

このdeprecatedさえれるイベントを利用すれば、独自に書いているjsの中でも比較的自由にContactForm7のイベント実行時に合わせて独自の処理を加える事ができそうです。


[参考]

小さなお店&会社の WordPress超入門 ―初めてでも安心! 思いどおりのホームページを作ろう!

小さなお店&会社の WordPress超入門 ―初めてでも安心! 思いどおりのホームページを作ろう!

Stylus Objectでらくちんカラー管理したい

stylus CSS

f:id:kikiki-kiki:20161130110134p:plain
StylusやSassなどでwebサイトのCSSを作成する時は、variableというようなファイルを作成して使用する色などを変数で書いておき適時使用しています。

しかし、色のバリエーションがある時に

$primary = #158cba
$primary-dark = #127ba3
$success = #28b62c
$success-dark = #28b62c

の様に全て変数で書いていくのは、なかなか面倒です。
そこで、値をオブジェクトにして簡単に色を取得できる方法を考えてみました。

stylus カラーパレットでの管理方法

// variable.styl
// カラーパレットをオブジェクトで作成
$color-palette = {
  default: {
    color:      #555,
    base:       #eee,
    border:     #e2e2e2,
    dark:       #d5d5d5,
    border_dk:  #c3c3c3,
    darker:     #C8C8C8,
    border_dkr: #c3c3c3 
  },
  primary: {
    color:      #fff,
    base:       #158cba,
    border:     #127ba3,
    dark:       #127ba3,
    border_dk:  #0c516c,
    darker:     #106a8c,
    border_dkr: #0c516c
  },
  // 略
}

使い方

ex: 色を返すだけのミックスイン

// Mixin: Return color
// @param: $type: color type
// @param: $tone: color's tone
get-color($type = "default", $tone = "base")
  return $color-palette[$type][$tone]

// How to use
.c-bg-primary
  background-color: get-color("primary")
.c-bg-primary-darker
  background-color: get-color("primary", "darker")

stylusはオブジェクトから値を取得するのに、javascriptと同じようにObject[val]の形式でも取得することが可能なので、darkやlightといったカラーバリエーションがあっても1つのミックスインに$type$toneを渡せば、トーンに合った色を簡単に取得することができました。

応用

ボタンなど色の出力のパターンが決まっているものは、ミックスインで出力するCSSのテンプレートを作ってしまえば簡単にバリエーションのCSSを作成することができます。

ex: ボタン

// Mixin: Button Variation
button-variant($type)
  color: $type.color
  background-color: $type.base
  border-color: $type.border
  &:hover
    color: $type.color
    background-color: $type.dark
    border-color: $type.border_dk
  &:active,
  &.is-active
    color: $type.color
    background-color: $type.darker
    border-color: $type.border_dkr
  &:disabled,
  &.is-disabled
    color: $type.color
    background-color: $type.base
    border-color: $type.border

// ボタンのカラーバリエーションのCSSを出力
for $key, $colors in $color-palette
  .c-btn-{$key}
    button-variant($colors)

ex: ラベル

// Mixin: Label Variation
label-variant($type, $tone = "base")
  color: $type.color
  background-color: $type[$tone]

// ラベルのバリエーションのCSSを出力
// Label Variation
for $key, $colors in $color-palette
  .c-label-{$key}
    label-variant($colors)

  // Darker Labels Style
  .c-label-{$key}-darker
    label-variant($colors, "darker")

Demo

See the Pen Stylus Color Manage by KIKIKI (@chaika-design) on CodePen.


[参考]

TVアニメ『アイカツスターズ!』新OP/EDテーマ「1, 2, Sing for You!/So Beautiful Story/スタージェット!」

TVアニメ『アイカツスターズ!』新OP/EDテーマ「1, 2, Sing for You!/So Beautiful Story/スタージェット!」

Gulp min化したJS・CSSに自動でコメントを入れたい

Gulp node.js javascript

f:id:kikiki-kiki:20161129005159p:plain コーディングをする時、Gulpでコンパイル&min化をしています。
min化したコードにコメントでバージョン情報とか、元のライセンス情報を入れたいケースとかがあります。

javascript

ライブラリなどのライセンス情報で/*!で始まるコメントの場合はgulp-uglifyのオプションでmin化する際に残すことができるみたいです。

var gulp = require('gulp'),
    rename = require('gulp-rename'),
    // console.logを削除するパッケージ
    stripDebug = require("gulp-strip-debug"),
    // jsをmin化するパッケージ
    uglify = require("gulp-uglify");

gulp.task('js. minify', function(cb) {
  return gulp.src( FILE_PATH )
    .pipe( stripDebug() )
    .pipe( uglify({
      // このオプションを使うと/*! */のコメントは残る
      preserveComments: 'some'
    }) )
    .pipe( rename({
      extname: '.min.js'
    }) )
    .pipe( gulp.dest( DEST_DIR ) );
});
/*! License */

↑ この/*!で始まる形式でないコメントは消えてしまうので、違う形式でライセンスが書かれているファイルはライセンスのコメントを残すことができないので注意が必要。

CSS

いつもCSSのmin化につかっているgulp-clean-cssでは特定の形式のコメントを残す方法が無さそうでした…
ライセンス情報を残すオプションのある良い感じのライブラリがあれば教えてください。

ファイルの先頭にテキストを追加できるパッケージを使う


gulp-header を利用すればJS, CSSに関わらず好きなコメントをファイルの先頭に追加できるようです。
min化したファイルに最後にバージョン情報や最終更新日時を追加するのに良さそうです。

ex: min化したCSSにpackage.jsonに書かれている情報を元にコメントを追加する

var gulp = require("gulp"),
    rename = require('gulp-rename'),
    header = require('gulp-header'),
    cssminify = require('gulp-clean-css'),
    // 日付を簡単にフォーマットできるパッケージ
    moment = require('moment');

// package.jsonを読み込む
var pkg = require('./package.json');
// CSSに追加するテキスト
var banner = ['/**',
    ' * <%= pkg.name %>',
    ' * @version <%= pkg.version %>',
    ' * @author <%= pkg.author %>',
    ' * @lastmodified <%= today %>',
    ' */',
    ''].join('\n');


gulp.task('css.minify', function(cb) {
  var versionDate = moment().format('YYYY-MM-DD');

  return gulp.src( FILE_PATH )
    .pipe( cssminify() )
    .pipe( rename({
      extname: '.min.css'
    }) )
    .pipe( header(banner, {
      pkg: pkg,
       today: versionDate
     }) )
    .pipe( gulp.dest( DEST_DIR ) );
});

gulp css.minifyでタスクを実行すると、min化されたCSSファイルの先頭に下記のようなコメントが追加されます。

/**
 * PROJECT-NAME
 * @version 1.0.0
 * @author KiKiKi_KiKi
 * @lastmodified 2016-11-29
 */

 

完璧にライブラリなどに書かれたライセンス情報のコメントを自動的に残す方法は達成できませんでしたが、JSではuglifyのオプションを利用すればそれなりに上手く行きそうな気がします。
また、gulp-headerを使えばプロジェクトの情報などを動的に追加することができるので、CSSでも追加するコメントのテンプレートを予め作成しておけば、ある程度カバーできそうだなぁと思いました。


[参考]

速習ECMAScript6: 次世代の標準JavaScriptを今すぐマスター!

速習ECMAScript6: 次世代の標準JavaScriptを今すぐマスター!

高校生みたいなバックパックが思ったより便利だった

Blog

超ド田舎に住んでいるので終電時間がめちゃめちゃ早く、ちょっとした勉強会とかに参加しても一泊しなければならない事が多くラップトップ(ノートPC)と一泊分の着替え+本や筆記用具の入るいい感じのカバンを探していました。(ちょっとした勉強会に参加するにも片道90分くらいの都市部に行くしか無いのだ!終電は21時だぞ☆)
PCバックで検索してレビューとかを見ていても結構お高い商品ばかりだったのですが、amazonで見つけた高校生みたいなカバンがお値段以上に良い感じでたので情報共有します。
f:id:kikiki-kiki:20161120210410p:plain
凄く高校生みたいです... ミソボーイの私が背負うのは見た目がアレかもしれませんが、私は気にしません!!!!

良かった点

  • 13インチのラップトップが余裕で入る
    A4サイズの本やノートも余裕で入ります。
  • ラップトップ+周辺機器と着替えを入れてもまだ本やペットボトルが入るくらい余裕がある
  • 安い!amazonの値引きも合って3000円未満で買えた

f:id:kikiki-kiki:20161120210921p:plain
とにかく、見た目以上に大容量でした。
ラップトップと着替えと本やノートを入れてますが、まだメインの部分には物が入る余裕があります。

少し残念だった点

  • 底のクッションが薄い
    PCを直で入れた状態で雑に扱うと衝撃が大きそうなので、気にする人はPCもケースに入れた方が良いかも。
  • 背負う面の通気が無い
    お高いバックパックには大抵ある背面の通気構造がないので、夏場や長時間背負ってると蒸れると思う。
  • 前面収納がシングルジップ
    メインの所と同様にダブルジップだと尚良かったと思う。
  • たくさん入るので、テキトーに入れると鞄の中がグチャグチャになる
    テキトーに詰めると取り出しにくくなります。

もう少し使ってみないと解らない所

  • けっこう丈夫っぽい。
    安い商品は縫製が結構アレですぐ壊れたりってありがちですが、力がかかる部分には補強がされてたりして思ったよりしっかり縫製されてるように思いました。
    ただ沢山物を入れると重くなるので、上部の引っ掛ける部分は大丈夫かな〜ってなる部分はあります。(トイレに入ったときとかね!)
  • 防水性
    カバーがあるのである程度防げると思いますが、どれくらい防水性があるのかは雨に打たれてないので今の所謎です。まぁ容量あるので折りたたみ傘でも入れておけよって感じかもですが。

 

色々書きましたがamazonの割引で3000円未満で買えたので、値段の割には良い買い物だったかなと思ってます。
大容量故に入れすぎると重くなってしまうので、欲張って入れすぎないようにする必要がありそうですw
(僕はすぐ本を入れすぎてしまうので...)
ブルジョアになれば、もっとお高いカバンに買い換えるかもしれませんが、それまではこの子を使い倒そうかなって思ってます。

Mac OS Sierraにアップグレードしたらターミナルで.bashrcが読み込まれなくなった。

Mac Tips

開発をしているとターミナル(黒い画面)を使うことが多いかと思います。
Macだとllコマンドが無かったりするので、.bashrcによく使うコマンドとかのエイリアスを書いたりしていました。

alias ll='ls -n'

こんな感じで。
 

アプリ開発をするのに必要なXcodeのアップグレードの為にOSのアップグレードも必要になってきたので、流石ににそろそろアップデートするか...と思いアップグレードしました。
往々にしてアップグレード後は今まで使っていた何かが使えなくなっていたり、設定をし直さなければならないものです。
取り急ぎ、ターミナル(黒い画面)起動時に.bashrcが読み込まれなくなっていたので、設定しなおしたメモ。

Mac OS Xはデフォルトでは.bashrcを読み込まないらしい

えっ!? アップデート前からOS Xだったんだけど...
いつからそうなってたの???
まぁいいや。読み込むように設定をすればOKなだけです。

.bash_profile に設定を書く

.bash_profileが無ければ作成します。

$ touch ~/.bash_profile

.bash_profileをエディタなどで開いて下記を記入して保存

if [ -f ~/.bashrc ]; then
  . ~/.bashrc
fi

これでターミナルを新しく開き直せば、.bashrcの設定が使えるようになっています。
なんで、Macllコマンド無いのかなぁ〜 (めんどくさがり


[参考]

入門bash 第3版

入門bash 第3版

Ruby Stylusでnibを使いたい。

Ruby stylus node.js

前回 Ruby(sinatra)でStylusを使えるようにしました。
しかし、このままではSassで言うところのCompassにあたるnibを使うことができていませんでした。nibを使えるようにした際のメモです。

nibはnode(npm)でインストールしておく必要がある

$ npm install nib

Rubyでnibを使う

RubyファイルにStylus・nibを使用する記述をする

# main.rb
require 'stylus'
require 'stylus/tilt'

# nibを使用する
Stylus.use :nib

# オプション
# min化する
Stylus.compress = true
# デバックコメントを出力する
Stylus.debug = true

RubyファイルにStylus.use :nibを記述した上で、Stylus内でnibをimportしなければnibを使用することができませんでした。
Stylusファイルの先頭に@import 'nib'を記述します。

// main.styl
@import 'nib'

.clearfix
  clearfix()

npmでインストールする必要があり、かつstylusのファイルでもimportの記述をしなければならないので、nodeのプロジェクトで使うよりは少し面倒ですが、これでnibも使えるようになったので、nodeのプロジェクトと同様にstylusでCSSを作成することができるようになりました。


[参考]

Ruby (2.2.0) 自分で作成したファイルを読み込む(require)にハマる

Ruby

Ruby(2.2.0)を使っていて自作したファイルを読み込み(require)する際にハマったのでメモ。
結論から言えば自作ファイルを読み込ませる際は相対パスで読み込むrequire_relativeを使うのが良さそう。

ファイル構成と読み込み

ファイル構成

/app
  |- main.rb # <- 実行ファイル
  |- controller.rb
  |- /modules
  |   |- a.rb
  |   |- b.rb
  |   |- /dir
  |        |- e.rb
  |- /lib
       |- c.rb
       |- d.rb

読み込み順

main.rb # <- 実行ファイル
  |- controller.rb ... (1)
       |- /modules/a.rb ... (2)
            |- /modules/b.rb ... (3)
            |    |- /modules/dir/e.rb ... (4)
            |    |- /lib/d.rb ... (5)
            |- /lib/c.rb ... (5)

1. 実行ファイルから同一階層のファイルの読み込み (main.rb -> controller.rb)

main.rbからcontroller.rbを読み込みます。

require は ./ が無いとエラーになる

require 'controller.rb'
# => Loaderror

Ruby1.9.2から./が無いとエラーになる仕様になったらしい。

require './controller.rb'
# => SUCCESS

※ただし、実行ファイルが別階層のものになると./有りでもエラーになる

require_relative で指定する場合 ./ 無しでもOKっぽい

require_relative 'controller.rb'
# => SUCCESS
require_relative './controller.rb'
# => SUCCESS

requireでもrequire_relativeでも/からファイルを指定するとエラーになる場合がある

/からファイルやディレクトリを指定すると、完全なルートからファイルを探すっぽいのでルートからのパスと一致してない場合はエラーになるっぽい。

require '/controller.rb'
# => Loaderror cannot load such file -- /controller.rb

/app/controller.rbなので、/controller.rbは見つからないっぽい?
それとも仕様的にNGなのかちょっと不明。

require_relativeでも/からファイル指定するとルートからファイル検索するっぽい。

require_relative '/controller.rb'
# => Loaderror cannot load such file -- /controller.rb

 


2. 同一階層のフォルダ内のファイルの読み込み (controller.rb -> /modules/a.rb)

main.rbで読み込むcontroller.rbで、同一階層にある/modulesフォルダ内のa.rbを読み込ませます

同一階層のファイルの読み込みと同じ

require 'modules/a.rb'
# => Loaderror
require './modules/a.rb'
# => SUCCESS

※ただし、実行ファイルが別階層のものになると./有りでもエラーになる

require_relative 'modules/a.rb'
# => SUCCESS
require_relative './modules/a.rb'
# => SUCCESS

 


3. 実行ファイルと同じ階層にあるフォルダ内でもファイル読み込み (/modules/a.rb -> /modules/b.rb)

先のcontroller.rbで読み込む/modules/a.rbから同じ/modulesディレクトリ内のファイルを読み込ませる

main.rb # 実行ファイル
/modules
  |- a.rb # -> b.rb を読み込ませたい
  |- b.rb

require は 実行ファイルからの絶対パスでないとエラーになる

require 'b.rb'
# => LoadError

./を付けてもa.rbからの相対パスなので読み込めない

require './b.rb'
# => LoadError

main.rbからのパスを指定すればOK

require './modules/b.rb'
# => SUCCESS

※ただし、実行ファイルが別階層のものになると、当然パスが変わるのでエラーになる

相対パス読み込み require_relative

require_relative 'b.rb'
# => SUCCESS
require_relative './b.rb'
# => SUCCESS

 


4. フォルダ内のファイルから同一フォルダに有るディレクトリ内のファイルの読み込み (/modules/b.rb -> /modules/dir/e.rb)

/modules/b.rbから/modules/dir/e.rbを読み込む

main.rb # 実行ファイル
/modules
  |- b.rb # -> ./dir/e.rb を読み込ませたい
  |- /dir
       |- e.rb

requireなら実行ファイルからの絶対パスで指定する

require './modules/dir/e.rb'
# => SUCCESS

※ただし、実行ファイルが別階層のものになると、当然パスが変わるのでエラーになる

require_relativeの場合は相対パスで指定する

require_relative 'dir/e.rb'
# => SUCCESS
require_relative './dir/e.rb'
# => SUCCESS

 


5. 別階層のディレクトリにあるファイルの読み込み (/modules/a.rb -> /lib/c.rb, /modules/b.rb -> /lib/d.rb)

/modules/a.rbから/lib/c.rbを読み込む

main.rb # 実行ファイル
/modules
  |- a.rb # -> /lib/b.rb を読み込ませたい
/lib
  |- c.rb

requireなら実行ファイルからの絶対パスrequire_relativeなら読み込ませるファイル(a.rb)からの相対パスで指定すればOK。
/modules/b.rbから/lib/d.rbを読み込ませるのも同様。

require './lib/c.rb'
# => SUCCESS

※ただし、実行ファイルが別階層のものになると、当然パスが変わるのでエラーになる

require_relative '../lib/c.rb'
# => SUCCESS

まとめ

  • require ... 実行ファイルからの絶対パスで指定。必ず./から始める必要があるっぽい。
  • require_relative ... そのファイルからの相対パスで指定。

自作したファイルを読み込ませる場合は、
require_relativeで相対パスでファイル指定をする 方法が間違い無さそうだなと思いました。


[参考]

Effective Ruby

Effective Ruby

Ruby Bool値かどうか型チェックしたい。ついでにis_bool?メソッドを作ってみた。

Ruby

Rubyで変数がBoolean型かどうかチェックしたい。
かなりレアケースな気がするけれど、この前参加した勉強会で要望があったのでトライしてみた。

RubyのTrueとFalse

  • false ... false, nil の時
  • true ... false, nil 以外全てtrue

Rubyには is_bool? という関数はない

true.is_bool?
# => undefined method `is_bool?' for true:TrueClass (NoMethodError)

エラーになります。

is_a?(クラス名)というメソッドを使うとオブジェクトが引数のクラスのインスタンスかどうか判定できるので、これを利用する。
trueTrueClassfalseFalseClassインスタンス
BooleanBoolClassってクラスは無いっぽい。

val = true
p val.is_a?(FalseClass) || val.is_a?(TrueClass) # => true

val = false
p val.is_a?(FalseClass) || val.is_a?(TrueClass) # => true

val = nil
p val.is_a?(FalseClass) || val.is_a?(TrueClass) # => false

チェックできるけど記述が長いので何回もチェックが必要だとめんどくさそう...

is_a? を使わない方法を考えてみる

値を!!でtrue/falseに変換して比較したらいけそうな気がしました。

def is_bool(v)
  !!v === v
end

p is_bool true  # => true
p is_bool false # => true
p is_bool nil   # => false
p is_bool 1     # => false
p is_bool 0     # => false
p is_bool ""    # => false
p is_bool true.to_s  # => false
p is_bool false.to_s # => false

なんとなく上手くいっている気もしますが、Ruby===演算子は型チェックをしているのではなく、左辺のオブジェクトによって判定の挙動が異なるらしいので本当にこれでOKなのか少し自信がありません。
ついでに関数化してみたのですが、is_boolって関数名で引数取る感じが何となくイケてない気がします...

他の言語を使っていると、ついつい「===演算子は==演算子よりも更に厳密な同値判定演算子でしょ?」なんて思ってしまいますが、ところがどっこい、Rubyの場合はむしろ===演算子のほうが柔軟な場合もあり得るのです。
Object#===の説明を見てみるとわかりますが、基本的にこの===演算子は、サブクラスで再定義されていない限り、単にObject#==を呼び出すだけなんですね。

出展: Rubyのcase式と===演算子について - しばそんノート

TrueClass, FalseClassでは#===が定義されていないようだったので、Object#===と同じなのではないかと思います。
ってコトは !!v==vでも同じことっぽい!?

Object
obj === other → true or false
Case Equality – For class Object, effectively the same as calling #==, but typically overridden by descendants to provide meaningful semantics in case statements.

出展: https://ruby-doc.org/core-2.2.2/Object.html#method-i-3D-3D-3D

Rubyは定義済みのクラスにメソッドとかを追加できるっぽい

手持ちの初めてのRubyという本を見ていると、オブジェクトとクラスの章にRubyは「定義済みのクラスに対して、いつでも定義を追加することができます。」とありました。
Objectクラスにis_bool?というメソッドを追加することも可能っぽかったので試してみました。

class Object
  def is_bool?
    !!self === self
  end
end

p true.is_bool?  # => true
p false.is_bool? # => true
p nil.is_bool?   # => false
p 1.is_bool?     # => false
p 0.is_bool?     # => false
p "".is_bool?    # => false
p true.to_s.is_bool?  # => false
p false.to_s.is_bool? # => false

一応 Object.is_bool? でBool値かどうか判定できるっぽものが出来ました。
メソッド内の判定をself.is_a?(FalseClass) || self.is_a?(TrueClass)にした方が判定としては確実かもしれません。

ただ、個人的に大元になるObjectクラスにメソッドを追加するのは正直どーなの?という感覚があるので良し悪しが判断できません。
こうするとCoolだよとかRubyっぽいよ。ってのがあれば教えてください。


[参考]

初めてのRuby

初めてのRuby