Crystal Signal Pi が 届いた!

Raspberry Pi に 約 7cm ぐらいの 四角柱 を 立て、マルチカラー の LED を で光らせることができるモジュール Crystal Signal Pi が 届き、ようやく組み立てができました. 本来はサーバなどの監視を行い、警告をわかりやすく表示してくれるものですが、いろいろな使い方に挑戦してみたいと思います. まずは、早速組み立てから.

作業環境

  • Raspberry Pi 3 Model B
  • Crystal Signal Pi

Crystal Signal Pi とは?

Crystal Signal Pi は、Raspberry Pi に 約 7cm ぐらいの 四角柱 を 立て、マルチカラー の LED を で光らせることができるモジュールです.
クラウド・ファンディングで購入者を募集されていることを知って、興味を持ち応募しました. クラウド・ファンディングの仕組みを使っていたとはいえ、製造は確定していたので普通に購入する形です.

光で監視するソリューション“ を キーワードに、2016年11月 の オープンソースカンファレンス 2016 Tokyo/Fall で デモをされたようです.
その際の資料はこちら、でしょうか. → “あらゆるイベントを可視化する! RaspberryPiで作るLED警告灯ソリューション

Crystal Signal Pi 到着 & 組立

開発元のインフィニットループさんの封筒で届きました. 写真では宛名部分を折り返していますが、 2つ購入で A4 の 封筒半分ちょっとぐらいです.

中身は緩衝材でしっかり保護されています.

1つ 1つ パッケージングされています. 丸穴をあければお店に そのまま吊るせる感じです. こんな感じで手軽に購入できるようになってほしいですね.

パッケージの中身は以下になります. 丁寧に部品ごとにも袋に入っています.

  • 説明書など書類 3枚
  • 基盤 1枚
  • ケースのアクリル板 2枚 と ネジ、滑り止め
  • LED で 発光する 四角柱 と ゴムバンド

説明書があるので、そう迷わず組立できました. 今回は Raspberry Pi 3 Model B を 使いました. なお組み立ての説明書 は PDF で 公開 されています. PDF は カラーなのでイメージがつかみやすいかもしれません.
まずケースのアクリルにネジとスペーサー入れ、ラズパイを載せ、続いてラズパイとCrystal Signal Pi 基盤の間用のスペーサーで留めます. ネジ穴が切ってあるのでクルクルして簡単に仮留めできます.

続いて Crystal Signal Pi の 基盤を載せます. GPIO に合わせたソケットが取り付けられているので、そのまま差し込みます.

最後にカバーのアクリル板をかぶせますが、四角柱を通してからカバーを載せます. 後は しっかり、ねじ止めして完成!

いざ、点灯!

Crystal Signal Pi の ソフトウェアが用意されていますが、インストールしなくても通電すると、緑とオレンジに交互に点滅した後、緑で光り続けます.
明るいところでは四角柱の側面部分は光がとおっている感じで発光感は強くないです.

天頂部は強く光っており斜めから見てもかなり眩しいです.

明るさ調整するにはソフトウェアが必要ですね. ソフトウェアを入れていないので、こちらも当然ですが、オレンジ色の丸ボタンも反応しません. また、shutdown した後も光続けています.


ラズパイで簡単な状態通知をできる Crystal Signal Pi、面白いプロダクトだと思います. API も 用意されているのでアイデア次第でいろいろな使い方ができそう.

2017年 3月現在、初期ロットのクラウド・ファンディングが終わったところで、次回ロットについては、オフィシャル・サイトでメール登録することで連絡をもらえるとのことです. 思った以上にすごくよかったので、さっそくメール登録しました!

Hexo の フッター に ソーシャル・アイコン を 設置

Hexo の デフォルト・テーマ Landscape に Twitter の 設定を追加した話では、ソーシャル・アイコンが追加されると早とちりをしてしまいました. 改めて思うと、ソーシャル・アイコンは、やはり どこかに配置しておきたいなぁと思うので、設置してみます.

作業環境

  • Hexo 3.2
  • Disqus
  • Twitter

設置場所 の 検討

トップのタイトル・カバーやサイド・バーに配置されているケースが多いように感じます. そういった場所に配置しようかと思ったのですが、現在のレイアウトから手ごろな配置が浮かばなかったので、今回はフッターのコピーライトの横あたりにひっそりと置いておくことにします.

アイコン集 の 検討

アイコン、アイコンはいろいろあるので悩みます. 素敵なデザインのサイトから頂戴しようかと思いましたが、まずは Font Awesome を 使って設定したいと思います.

Font Awesome は 各種アイコンをフォントとして用意してくれています. フォントなので大きさを変えても崩れませんし、色を変更することもできます. 単色の色設定にはなってしまいますがシンプルなテイストでまとめるとも考えられますし、とても使いやすいツールです.

ライセンスは、こちら で 2017年3月現在 の Version 4.7.0 では、フォント は SIL OFL 1.1、CSS などのコードは MIT と、今回のようなブログに設定するにはフリーで使わせていただけます. ただし企業や組織のブランド系のアイコンについては、注意書きがあるので確認およびそれに従った運用が必要です. Font Awesome の ライセンス を ご確認ください.

Hexo Landscape は /themes/landscape/source/css/fonts に Font Awesome の フォントが入っています. そのため新たに追加しなくても使えるのが嬉しいところです.

Hexo Landscape に 設置、も?

設置場所、アイコン集も決まったので Hexo Landscape に 配置していきます.
フッターに配置することにしたので、編集するファイルは /themes/landscape/layout/_partial/footer.ejs に なります. コピーライトの部分は以下のコードになっており &copy; 行 の <br> の 前に置くことでコピーライト表示に並べて行けそうです.

1
2
3
4
<div id="footer-info" class="inner">
&copy; <%= date(new Date(), 'YYYY') %> <%= config.author || config.title %><br>
<%= __('powered_by') %> <a href="http://hexo.io/" target="_blank">Hexo</a>
</div>

続いて、Font Awesome の アイコン ですが、こちらは Icons ページ から利用したいアイコンをクリックし、表示されたコードをコピペすることで簡単に利用することができます. たとえば Font Awesome の アイコン は <i class="fa fa-font-awesome" aria-hidden="true"></i> です.

とりあえず GitHub と Twitter を 配置するとして、以下のようなコードを置きました.
必要なソーシャルアイコンのタグを調べて配置して終了!

1
2
3
4
5
6
7
<div id="footer-info" class="inner">
&copy; <%= date(new Date(), 'YYYY') %> <%= config.author || config.title %>
<a href="https://github.com/[username]" target="_blank" title="GitHub"><i class="fa fa-github" aria-hidden="true"></i></a>
<a href="https://twitter.com/[username]" target="_blank" title="Twitter"><i class="fa fa-twitter" aria-hidden="true"></i></a>
<br>
<%= __('powered_by') %> <a href="http://hexo.io/" target="_blank">Hexo</a>
</div>

いざ表示!と、行きたかったのですが、残念ながら表示されませんでした…
コードは追加されており、配置されている場所こそ気にはなるもののレンダリングもされているようです. しかし、<i> の スタイルシート が user agent stylesheetfont-style: italic; に なっています.

なんと、Hexo Landscape には Font Awesome の フォント は 入っているものの、CSS が 入っていない… 読み込んでいないではなく、物理的にファイルもない のでした. そのため、Font Awesome の タグ ではアイコンが入ってくれないという事象が発生したものになります.

Unicode 指定 による CSS で 設置

タグ による指定できないので、フォントから直接 Unicode で 指定する方法を取りたいと思います.
Unicode による指定は、CSS で font-family に Font Awesome の フォントを指定し、content に Unicode で 使用する文字を指定します. Unicode は Icons ページ に コードが書かれているので、そちらを指定します. たとえば Font Awesome の アイコン は f2b4 なのでエスケープを入れて content: "\f2b4"; と なります.

CSS の クラス定義は、ちょうどソーシャルへシェアするためのアイコンのクラス定義があるので、それに習って作成したいと思います.
ファイルは /themes/landscape/source/css/_partial/article.styl で、$article-share-link.article-share-twitter などがソーシャル・シェアのアイコンになります. こちらをまねて $article-link.article-link-twitter.article-link-github を 作成しました.
フォント・カラー を 直前のコピーライトと合わせ、文字をやや大きくしています. Unicode は Twitter が f099 で、GitHub が f09b なので、それぞれ content に 指定しています.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
$article-link
color: #999 !important
&:before
font-size: 24px
font-family: font-icon
text-align: center
&:hover
color: #fff !important
text-decoration: none !important
.article-link-twitter
@extend $article-link
&:before
content: "\f099"
.article-link-github
@extend $article-link
&:before
content: "\f09b"

/themes/landscape/layout/_partial/footer.ejs は 先ほどのリンクを作る <a> タグ に クラス定義をあてるだけになります.

1
2
3
4
5
6
7
<div id="footer-info" class="inner">
&copy; <%= date(new Date(), 'YYYY') %> <%= config.author || config.title %>
<a href="https://twitter.com/[username]" class="article-link-twitter" target="_blank" title="Twitter"></a>
<a href="https://github.com/[username]" class="article-link-github" target="_blank" title="GitHub"></a>
<br>
<%= __('powered_by') %> <a href="http://hexo.io/" target="_blank">Hexo</a>
</div>

いざ、表示!


無事表示することができました. Font Awesome は よく利用させていただいています. 絵心やデザイン・センスががない身としてはとても助かっています. ありがとうございます!
普段はタグで指定しているので Font Awesome の CSS が 無いケースでの設定は初めてでしたが、ちょうど ソーシャル・シェア の 定義があり流用できたので助かりました.
テーマへの手入れが増えてきたので、そろそろテーマを切り替えて本格的にやっていきたいのですが、なかなか手が出せず、今しばらくは Hexo Landscape に ちょくちょく手を入れつつお世話になりそうです.

Hexo に コメント欄 の Disqus を 設置

Twitter の アカウントを開設した し、ちょっと寄り道しましたが、いよいよコメント欄 Disqus を 設置したいと思います.

作業環境

  • Hexo 3.2
  • Disqus
  • Twitter

Disqus の アカウント作成

Disqus の Signup ページ https://disqus.com/profile/signup へ アクセスします.

今回は Twitter の 認証連携でサインアップするので Twitter アイコン を クリックします.

Twitter の サイト へ 遷移するので、Twitter へ サインインして連携を許可します. 各種権限の許可ができない場合は Twitter 連携を諦めて直接サインアップします.

許可すると Disqus の サイトへ戻ります. 名前、メールアドレス、パスワードの入力をします. 名前 は Twitter からひいてくれたようですが、メアド、パスワードは入力が必須でした… この辺を入力したくない(特にパスワード)から Twitter で 認証したのに、意味なかった. orz

Disqus サイト の 開設

サインアップが完了すると、そのまま Disqus サイト の 開設が始まります.
ブログに設置するためにアカウントを作成したので、そのままサイトの開設に進みます.

ここでの「サイト」は Disqus に 開設するサイトのようで、ブログサイトとは関係ないようなので注意が必要です. (ブログサイトから連携する先の Disqus サイト と いったイメージでしょうか)

2つの選択肢が示されます. 今回はブログにコメント欄を設置するので [I want to install Disqus on my site] を クリックします.

基本設定の入力画面が表示されます.
[Website Name] は ユーザ名 に あたるものを入力します. ここで入力した文字列から生成された Your unique disqus URL の 先頭部分 が ブログから連携する Disqus の サイト の Short Name になります. 個々のブログやウェブサイトの名前でないことに注意が必要です.
ここで 表示された “Your unique disqus URL” = Short Name を ひかえておきます.
Category や Language は お好みで選択します.

無事、Disqus サイトの開設ができました.
[Got it. Let’s get started!] を クリックし、続いてブログ・サイトの連携を作成に進みます.

ブログ・サイト の 連携設定

自分のサイトで使っているサービスやプロダクトを選択する画面が表示されます.
Hexo は ラインナップされていないため、汎用 の [I don’t see my platform listed] を クリックします.

コードによるセットアップ方法について解説がありますが、Hexo の デフォルト・テーマ Landscape は 設定 1つで対応できるので、勉強がてら眺めつつ一番下の [Configure] を クリックします.

ブログ・サイトの設定を入力する画面が表示されます. ここは自サイトの情報になります.
[Website Name] は、ブログ の サイト名になります. コメント欄のタイトルに表示されます. [Website URL] は、ブログ の URL を 入力します. [Category]、[Description]、[Language] は お好みで.

無事、セットアップが完了しました!

Hexo に Disqus を 設定

Hexo の デフォルト・テンプレート Landscape の after-footer.ejsarticle.ejsconfig.disqus_shortname の 有無を判定し、コメント欄を出力するかが制御されています.

この config. の Prefix が 曲者で、Hexo の 設定 に disqus_shortname が 必要でした.
テーマに関する設定項目と思っていたので、Landscape の /themes/landscape/_config.yml に 設定をしたところ、どうしても表示されずはまりました. 同じファイル名ではありますが、Hexo の /_config.yml に 以下のように設定します.

1
disqus_shortname: [shortname]

ここで、Disqus の サイトで開設した Web サイト の Short Name の 値 を 設定します.
ローカルで確認する際に、もしかしたら正しく表示されないケースがあるので、その場合は hexo clean してから再生成すると表示されます.


Disqus アカウントのサインアップから、Disqus サイトの開設、ブログ連携 と 一連の作業で流れて行ったので、作業している時に今何をしているかちょっとわからないところがあり、迷ってしまいました… 最近 Disqus の ウェブサイトが変わったのか、自分のやり方が違ったのか、参考情報もなくて悩みつつでしたが、改めて文章で起こしてみると、3つのパートだったことが分かりました. 勉強になりました.

Hexo に Twitter の アカウント を 設定

Twitter の アカウントを開設した ので、いよいよコメント欄 Disqus の 設置!と、行きたいところですが、ちょっと寄り道. Hexo の デフォルト・テーマ Landscape に Twitter の 設定項目があるので設定したいと思います.

作業環境

  • Hexo 3.2
  • Twitter

Landscape の Twitter 設定項目

デフォルト・テーマ Landscape の 設定ファイルは /themes/landscape/_config.yml に なります. 以下に抜粋したとおり twitter: が あります.

1
2
3
4
5
6
7
# Miscellaneous
google_analytics:
favicon: /favicon.png
twitter:
google_plus:
fb_admins:
fb_app_id:

設定値 と 効果 は?

Landscape の ドキュメント Configuration – hexo-theme-landscape によると、”twitter - Twiiter ID” と あっさりしすぎてて、何のことか、また何を入れるかわかりません. 困った…

情報がないか探してみると、Configuration – hexo-theme-bootstrap-blog
に “twitter_id - Twitter ID of the author (ie. @c_g_martin)” が ありました.

異なるテーマなので同じで大丈夫かと思いましたが、”The default Landscape Hexo theme was used as the starting point - Development“ と あるので信じて設定したところ、どうやら動作したようです.

なお、設定値は以下のように、アットマークを付けシングルクォートで囲む必要があります.

1
2
3
4
5
6
7
# Miscellaneous
google_analytics:
favicon: /favicon.png
twitter: '@username'
google_plus:
fb_admins:
fb_app_id:

さっそくローカルで確認したのですが、特に変化はなかったようです… あれ?
Twitter の アイコンが増えて、リンクしてくれたりするのかなぁぐらいに思っていたのですが、どうやら違うようです. では、何が設定されたのか…

Twitter Cards !

とりあえず生成されたサイトのソースを確認します. すると head に Twitter 関連のメタ情報が出力されていました.

この出力内容は Twitter Cards に 関するもので、Twitter に サイトのリンクをツイートされた際に、以下のようにサイトの画像サムネイルやタイトル、先頭分のサマリが表示されます.


Twitter Cards の 説明によると、”リッチメディアをツイートに添付してウェブサイトへのトラフィックを促進できます – Twitterカード — Twitter Developers” とのこと.
ただの文字列リンクより、サマリが表示されるので設定しておくに越したことはないので、このまま設定しておきたいと思います.

Twitter や GitHub の アカウントへのリンクを貼る機能と勝手に思っていましたが早とちりでした. しまった…
とはいえ、リンクは貼りたいので、どっかでテーマを変えるなり、カスタマイズしないとだなぁ~

Slack で プレミアムフライデー・ボット してみる

2017年2月24日 金曜日、それは “プレミアムフライデー” なる施策の開始日である. うん、ウチは関係ないらしいのだけど! とうことで、関係ないボット を Slack に 乗せてみた.

作業環境

  • Slack
  • Node.js 6.9.1 LTS
  • Botkit 0.4.9 0.5.1
  • node-cron 1.2.1
  • moment-timezone 0.5.10

プレミアムフライデーって、なにそれ?おいしいの?

まずもって関係ないので、よく知りません. 人によっては美味しいものであったり、おもしろい物であるようです.

経済産業省によりますと以下の施策だそうです.

個人が幸せや楽しさを感じられる体験(買物や家族との外食、観光等)や、そのための時間の創出を促すことで、
(1) 充実感・満足感を実感できる生活スタイルの変革への機会になる
(2) 地域等のコミュニティ機能強化や一体感の醸成につながる
(3)(単なる安売りではなく)デフレ的傾向を変えていくきっかけとなる
といった効果につなげていく取組です。

なんか漠然として、よくわかりませんが、こちらのサイト を サマると以下でしょうか.

  • 月末の金曜日は早く仕事を終え退社する
  • 早く退社した時間は、余暇として楽しむ
  • ちょっと豊かな月末金曜日を過ごしてハッピーになる

いいなぁ、ハッピ~. こちらもアバウトな感じでよくわからない.
とりあえず聞いたことある話からすると、以下のようです.

  • 月末の金曜日は 15時までに退社する
  • 退社後は食事や娯楽などを楽しむ
  • 消費が活性化され、楽しんだ人 も 景気 も ハッピー になる

なるほど. いいなぁ、ハッピ~.

ボットの仕様を考える

月末の金曜日は 15時に変えることを促す通知をするのが通常仕様とすることになりそうです. 一方で関係ない身としては 15時に帰れと言われても困りますので、何かしらの工夫が必要です.

いただきます! こちらのネタ!!
ということで、まずは usernameicon を プレミアムフライデーなアカウントにして 15時退社をアナウンス. 続いて通常ボット・アカウントに戻って上記ネタでリプライする、自作自演ボットにしたいと思います. これなら関係無い感が出てるボットになって、きっと朝から はっぴー な 気分になれ…

ボット実装

自動切断のワークアラウンド・コードを削除する更新をしました (2017年3月10日)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
'use strict';
const Botkit = require('botkit');
const cron = require('cron');
const http = require('http');
const moment = require('moment-timezone');
const controller = Botkit.slackbot();
moment.locale('ja');
moment.tz.setDefault('Asia/Tokyo');
controller.spawn({
token: process.env.bot_access_token
}).startRTM((err, bot, payload) => {
new cron.CronJob({ cronTime: '00 00 11 * * 5', timeZone: 'Asia/Tokyo', start: true, onTick: () => {
let now = moment();
if (now.month() != now.clone().add(7, 'days').month()) {
bot.say({
channel: 'random',
text: '今日、月末の金曜日は午後3時に退社して余暇を楽しもうという ' +
'<https://premium-friday.go.jp/#section_about|プレミアムフライデー> だよ! ' +
'退社時間が早まることで消費が活性化するし、働き方改革にもつながる施策なんだ. ' +
'さぁ~ みんな3時には帰って、買い物、食事や旅行などして普段よりも豊かな生活を送ろう!!',
username: 'プレミアムフライデー ボット',
icon_url: 'http://www.meti.go.jp/press/2016/12/20161212001/20161212001-a.jpg'
}, (err, response) => {
bot.say({
channel: 'random',
text: `<http://[YOUR_IMG_URL]/image.jpg?${moment().unix()}| >`
});
});
}
}});
});

Botkit や Moment.js の セットアップ系はいつも通りで、定時処理は毎度の new cron.CronJob() で ジョブを作成します.
今回は「月末の金曜日 11時」に 処理をしたいのですが、cronTime だけでの表現が浮かびませんでしたので、まずは「金曜日 11時」に 処理を起動するようにしました.
続いて現在日時を取得して、7日後が同じ月か now.month() != now.clone().add(7, 'days').month() で 判定することで月末の金曜日なのかを確認しています.

月末の金曜日だったら、まずは「プレミアムフライデー ボット」が 広報の通知をするために usernameicon_url を 変更してポストします.

「プレミアムフライデー ボット」が 発言した後に返事を返したいので、以下のように bot.say() の 中で再発言させています. bot.say() を 並べてしまうと、タイミングによっては通常ボットの返事が先に来てしまうことがありえるので、bot.say() の コールバックから発言する処理になります.

1
2
3
bot.say({ /* プレミアムフライデーの発言 */ }, (err, response) => {
bot.say( /* 通常ボットからの返事 */ );
});

通常ボットからの返事では、<http://[YOUR_IMG_URL]/image.jpg?${moment().unix()}| ><url| > の 書式で URL を 半角スペースに置き換えてポストする記法を使っています. これによって URL 無しで画像だけポストできます. ?${moment().unix()} は、Slack が 同じ URL だと 2回目以降は折りたたんでしまって、最初から画像が見えないので、実行時の Unix timestamp を つけることで URL を 変えて展開できるようにしています.
※ 画像は自前で用意して適当なところへ置いておきます.

実験!

cronTime を 調整して、いざ実験. ちゃんと表示されました.
とりあえず実験用にはネタ元のたツイートから画像を拝借させて頂きましたが、後は画像を自前のネタに変えて適当なとこにアップしてボットを設置するだけですね. 関係ない人々の月末の週末が楽しみです♪


今週末に迫ってきたプレミアムフライデー. 急に騒がしくなってくる中で関係ない身としては流れに乗れない寂しさから勢いボットを作って乗ってみました. 帰るころにはハッピーな人で溢れかえっているか、後の祭りか…
みなさま、よい週末を.

『知識ゼロから学ぶソフトウェアテスト』 あるいは 無残なるノーテスト

Java で プログラミングをしている場合に、テストケースの作成に JUnit を ベースにテストしているケースがあるかと思います. “Assert that X is Y.” の 考え方 を 基本に isnotnullValue などしてテストケースを書いていくよいライブラリと思うのですが…

テスト も カバレッジ も ちゃんと やってます!

それは昔々の事、とあるアプリケーションに携わった人のお話しで機能追加することから物語は始まりました. (いや物語らん話しのがよかた)

このアプリケーション、しっかりテストケースが作ることになっており、なんと C0 カバレッジ 90% 以上、C1 も 努力目標ながら高レベルでされているとのことでした. ちゃんとテストするフレンズなんだね!すごーい!(2017年2月現在 流行りのフレーズ)

と、聞いていたのも束の間、コードを触り始めると気になる謎の実装、不思議なテストケース…
「テストなってないじゃん?」いや、まぁ、「テストするとは」の定義は何かと自問自答するわけですが、テストケースがあるとか、カバレッジが取れてるとかでなくて、「何を検証したいのか」じゃないのかなぁと、考えたとのことです.
僭越ながら同感です. いたずらにカバレッジだけとっても、通過させるためだけの意味のないテストケースの実行コードなんてものがあふれることもあり得ます.

え? その “verify(x, never()).y()”…

さて、そんな中、聞かれたのが “verify(x, never()).y()” というコード. これだけ聞かれてもよくわからないのですが、たぶんモックでメソッドの呼び出し有無を判定したいと思われます.

そして出てきたのが以下のようなテストケース. (※ ポスト用に命名等を汎化させています)

1
2
3
4
5
6
public class DaoTest {
@Test public void testAdd() {
verify(dao, never()).findAll();
}
// ...(省略)
}

いゃ~! 見たくなかった、聞きたくなかった…
たぶん、Deta Access Object = DAO の テストケースと思われます.
きっと、新しいレコード を 追加 = add するのをテストしたかったのでしょう. 知らんけど.
verify()never() は モックを簡単にするためのライブラリから、メソッドの実行確認をしているのでしょう.
だけど、dao.add() 実行してないじゃん? あと findAll() しなくね?、どう考えても. (そもそも Dao の 処理を何も実行してないからアレだけど) White Box テストだから知ってるはずだし?

どうして、そうなったのか. 少し話を聞いたたらしいのですが、「テストって、何をテストをするんですか?」「どうやるんですか?」「できすか?やって見せてください!」…
えーっと、逆ギレ? DAO とかテストめんどくさいの分かるけど、単純 な Getter/Setter だけのテストだってできてないんですが (T_T

1
2
3
4
5
6
7
8
public class ModelTest {
@Test public void setParam() {
Model model = new Model();
model.set("あああ..."); // ※ すごい長い「あ」が続く
assertEquals("あああ...", model.get());
// ※ この後、同様のパターンで半角英数、記号、全半角の組み合わせ? などが続く
}
}

なお、C0 90% は、どっか別のテストケースで実行していたのが、たまたま通過していたものだったとか. 対となるテストケースの実行では無残なカバレッジ率とのこと… はあぁ 全部作り直しかよ~と、ご愁傷様です ( ̄人 ̄)
ひゃ~ こわい、こわい.

“assertTrue(true)” ?

そんな今となっては香ばしい昔話を黄泉がえらせたのが、Titter に 流れてきた衝撃のツイート.

“assertTrue(true)”… 何を言っているのかわかりませんでいた. いや TDD とかで、Fake it、ですよね~ やるやる~~www と…

いや、ヤバいです. どういう話しですか?
先の昔話も 今も テストの闇は深い… (“JUnit 目視” という、別系統のヤバいのも見た気が)

『知識ゼロから学ぶソフトウェアテスト』

テストで悩んだら『知識ゼロから学ぶソフトウェアテスト』を 読んでみるのがよいかと思った次第で、ちょうどアプリケーションのテストの不備に、”assertTrue(true)” という闇の呪文、半額セールが重なったので、勢い投稿を書いてしまいました!

こちらの書籍は JUnit とかの実装技術ではないのですが、「テストとは」という視点で書かれています. テストに対する考え方を学ぶことができるのではないでしょうか. いきなりテストケースを実装する前に、何を、どうやってテストするのかを知ってから、作るとよいかと思います.

私は改訂版の前の書籍を読んだことがありますが、テストケースはどう作るべきかの基礎をしっかり学ばせていただきました. 改訂版とのことで、どう変わったのかは改めて読みたいと思いますが、基本的な考え方を知るにはよいと思います.

ちょうど、翔泳社祭2017「ぼうけんキッズ」刊行記念eBOOK半額セール(2/22まで) | 翔泳社 で 電子ブックは半額で買えるので今はチャンスですね!

Amazon Kindle 版 は こちら https://amazon.jp/ebook/dp/B00HQ7S5CA です.


「テストって何をするんだろ」には『知識ゼロから学ぶソフトウェアテスト』も よいと思いますので、よかったら ご参考までに.

Twitter の アカウント作成

以前 WordPress を 使っていたことがあり、それに比べて Hexo と GitHub は 簡単にブログを設置 できるなぁと、WordPress 界隈が騒がしい今日この頃、ふと WordPress 時代を思い出しました.

改めて思い出すことなく、前々から気にはなっていたのですが Hexo にはコメント欄がありません. 静的ジェネレータで生成されたサイトなのでサーバ側の処理がないので当然と言えば当然なのですが、やはり寂しい.

作業環境

  • Hexo 3.2
  • Twitter

Hexo の コメント欄

いろいろと調べてみると Hexo 2.x のころにはコメント欄があったようで、3.x になってからテーマとの兼ね合いからなくなったのだとかなんとか.
現在は Disqus というサービスを使うと設置できるようなので、さっそく設置に取り掛かろうと思ったところ、SNS の 認証連携は Facebook, Twitter, Google+ で、GitHub は 対応していませんでした.

メールで直接サインアップするよりも、SNS に まとめておきたいので、今回は Twitter の アカウントを作成し、そのアカウントから Disqus へ サインアップしたいと思います.

Twitter の アカウント作成

Twitter の Signup ページ https://twitter.com/signup へ アクセスします.

呼び名、メールアドレス、パスワード を 入力し、[アカウント作成] ボタンをクリックします.
ここの “呼び名” は、Twitter での表示名で、既に使われている名前とも重複可能です. また後程変更することもできます. ネット上でのハンドルや、いつものニックネームで大丈夫です.

電話番号の入力を求められますが、特に必要なければ [スキップ] を クリックします. 今回はスキップしました.

ユーザー名、アカウント名を入力します. こちらは Twitter 内 で 一意となる文字列が求められます. “2006年7月にオブビアウス社(現Twitter社)が開始したウェブサービス – Wikipedia“ と 約10年の歴史に、Twitter, Inc.について | About の 2017年2月現在 で 約 3億 月間アクティブユーザー とのことで、なかなか思うアカウント名は取れません… (画面はブログ用に加工してます)

無事、アカウントが取れると Welcome 画面が表示されます. [さぁ、はじめよう] を クリックし進めます.

興味あることからフォローするアカウントなどが勧められたりするようですが、今回は何もせずに [続ける] しました. 明確に取りたい情報があれば設定しておいてもよいかもしれません.

アドレス帳のアップロードを求められますが、今回は [利用しない] で 先へ進めました. いろいろなサービスがある中で、何と、どこまでを、リアルとくっつけるのかは悩ましいところです.

フォローするアカウントの選択として、いくつかのアカウントをサジェストしてくれます. 日本語で日本からサインアップしているのですが 2017年の話題の人としてプレジデントを勧めてくれたのでしょうか… 画面に表示された “場所に基づくおすすめ “ 感 が あまりないのですが.

ブラウザのポップアップ通知について聞かれます. 必要な方を選択します. 使ったことは無いのですが、専用クライアントなしでブラウザだけで通知できるとは技術の進歩は素晴らしいですね.

ようやく、Twitter を 利用できるようになりました. “さぁ、はじめよう” って、言ってたのに長かった.


ブログのコメント欄 Disqus に向けて、一歩を踏み出すことができました. Twitter 自体も用意したいなぁと思っていたので、ちょうど設置できてよかったです.
しばらくは ツイート できないとは思いますが、せっかく設置できましたので @azriton も よろしくお願いいたします.

Hexo の 新規投稿パス を カスタマイズ

Hexo では 新しい投稿は hexo new "記事タイトル" コマンドで作成します. その際に新しいファイルは /source/_posts/記事タイトル.md として作成されます. 初めのうちはひとつのフォルダ内でよいのですが、ファイルが増えてくると管理に困ってしまいます.
このファイルが作成される場所を管理しやすいように Hexo を 設定したいと思います.

作業環境

  • Windows 7
  • Hexo 3.2

新規投稿ファイルの配置場所

この設定は _config.ymlnew_post_name に なります. 以下に初期設定を抜粋したように :title.md と なっているため、/source/_posts に コマンドの引数で与えた 記事のタイトル.md というファイルが作られます.

1
2
# Writing
new_post_name: :title.md # File name of new posts

ここの設定を変えることで、作成されるファイルをコントロールすることができます. パーマリンクの設定を例にみると permalink: :year/:month/:day/:title/ のように :year などの変数を使っています.
この例に倣って、以下のように年月フォルダにファイルを置くように設定してみます.

1
2
# Writing
new_post_name: :year/:month/:title.md # File name of new posts

hexo new "記事のタイトル" を 実行したところ、ねらったとおりに年月フォルダに作られるようになりました.
ここで使える変数についてのドキュメントは見当たらなかったのですが、Permalinks | Hexo を 参考に試してみました. :i_month:i_day などは動作しました. :id:categoryundefined というフォルダになります. カテゴリは、この時点では設定がないので当然ですね.

新しいフォルダへの引っ越し

これまでのファイルは自分でフォルダを作成する必要があります. フォルダを作成してファイルを移動することで完了です.
ここは自動でできないので致し方ありません.

ところで、

実は new_post_name の フォルダ部分 は ファイルを作成する際に参照される設定で、サイトの生成には関係していません.
そのため、これまでのファイル は そのままに、新しく作るものだけを新しい設定のフォルダで管理することもできますし、全く関係ないフォルダ名で管理することもできます. もちろん、日本語のフォルダ名も利用できます… (あとから気づいた orz)
そうなると内部的なカテゴリで分けても良かったのかもと思ったりもします.

ただ、ファイル名については URL で 使われるので、こちらに細工するこは URL として見えてしまうことを前提にする費用があります.
フォルダを内部的な カテゴリ や シリーズ で 整理して、ファイル名に連番を付けてもよいかと思ったのですが URL に 連番が出るのは悩みどころです.


最初にファイルを生成するときに、一定のルールに従って生成してくれるという機能の紹介でした.
ある程度ポストが増えてくるとファイル管理に意外と悩むものなんだなぁと感じます. 規模や特性によるので一概には言えないことなのでしょうが、何か良い方法があったら知りたいところです.

Slack の ボット で 定期的に降水予報を通知する

朝の天気と、その後の降水予報が Slack に 通知できるようになりました.
これで傘を持っていくかを判断できるようになりましたが、朝は晴れていて日中晴れの予報でも夕方に天気が崩れることもあります. 何てことだ orz

既に傘は持ってきていないわけですが、あらかじめ天気が崩れることが分かれば、予定を変更して早く帰るなりの作戦が取れます. (まぁ、作戦を立てたとして実行できるかは別なのですが…)

今回は、降水予報の実装 を 定期的に実行して、雨もしくは雪が降る予報があった場合に Slack に 通知するようにしたいと思います.

作業環境

  • Slack
  • Node.js 6.9.1 LTS
  • Botkit 0.4.9
  • node-cron 1.2.1
  • moment-timezone 0.5.10

通知方法の検討

OpenWeatherMap で 取得できる予報は、「3時間ごと 5日間」と「日次で 16日間」の 2つがあります. 無料で使えるのは「3時間ごと 5日間」なので、こちらを使って降水予報を実装したいと思います.

取得できるデータには降水確率などの情報は無いですが、天気状況に加えダイレクトに降水量があります. この降水量を使うことにして 9時間以内に降水量がある場合に、降水予報として通知するようにします.

Slack ボット の 実装

定期実行のスケジュールが異なるため、毎朝の天気情報とは異なる cron ジョブを作成します.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
new cron.CronJob({
cronTime: '00 00 9-21 * * 1-5',
onTick: () => {
http.get(`http://api.openweathermap.org/data/2.5/forecast?id=${city}&appid=${apikey}&units=metric&cnt=3`, (response) => {
let body = '';
response.setEncoding('utf8').on('data', (chunk) => { body += chunk; });
response.on('end', () => {
let json = JSON.parse(body);
for (let i in json.list) {
let forecast = json.list[i];
if ((forecast.rain && forecast.rain['3h']) || (forecast.snow && forecast.snow['3h'])) {
let text = '→ ' + labels.next(forecast.dt_txt) + labels.desc(forecast) + labels.prec(forecast);
http.get(`http://api.openweathermap.org/data/2.5/weather?id=${city}&units=metric&appid=${apikey}`, (response) => {
let body = '';
response.setEncoding('utf8').on('data', (chunk) => { body += chunk; });
response.on('end', () => {
let current = JSON.parse(body);
bot.say({
channel: channel,
text: text,
username: `${current.weather[0].main}(${current.weather[0].description})`,
icon_url: `http://openweathermap.org/img/w/${current.weather[0].icon.replace('n', 'd')}.png`
});
});
});
break;
}
}
});
});
},
start: true,
timeZone: 'Asia/Tokyo'
});

基本的な構造は、朝の天気予報 の OpenWeatherMap API 呼び出し順が逆になるだけで、ほぼ同じです.
cronTime は 平日の 9時~21時に、1時間ごとに実行するようにしました.
API 呼び出しは、最初に /forecastcnt=3 で 3時間毎 の データ を 3回分で 約 9時間を取得しています. その中に降水情報があったら アイコン と ユーザ名 に 使う、現在の天気 /weather を 取得します.


予報も出せるようになったので、朝から傘が必要か、そして日中の天気の変化について知ることができ、降水確率 ○○% というよりも、何時に、どのくらいの雨(雪) が 降るのかが分かるので、意外とよさそう.
これまで実装してきたものを組み替えるだけで簡単に作れました. API さまさま、ですね. ありがたい.

Slack の ボット で 今日の天気を通知する - 表示最適化編

朝の天気と、その後の降水予報が Slack に 通知できるようになりました!
これで毎朝の天気を確認できるわけですが、その情報を見るツールとしてスマホを使った時に少し気になる点がありました.

作業環境

  • Slack
  • Android 6.0
  • Slack 2.27.0 (Android App)
  • Node.js 6.9.1 LTS
  • Botkit 0.4.9

スマホ表示の確認


ちゃんと表示されています! が 天気アイコン、デカい!
分かりやすいと言えば分りやすいですが、ちょっと大きすぎですね. 1日分で、ほぼ画面が埋め尽くされてしまっています. もう少しコンパクトに表示するようにしたいと思います.

表示方法の検討

Slack の ボット は 発言する際に、アイコン と 名前 を 変えることができます. (chat.postMessage method | Slack)
これを使うことで、現在ロボットのアイコンが表示されている部分 を 天気アイコン にし、名前の部分に天気情報を入れることにすれば、すっきりしそうです.

Botkit での 実装方法ですが、その辺についての説明はありませんでした. 残念.
近いところとしては Slack-specific fields and attachments に リプライにアタッチする話があります. アタッチの中に usernameicon_url が 登場しますが、アタッチしたいわけではないのでちょっと異なりそうです.

仕方がないのでソースに当たることにします.
ボットを話させているのは Slackbot_worker.js#send() – Botkit v0.4.9 です. こちらを参照すると slack_message 変数を作っているところに見事に usernameicon_url が あります. つまり、この関数の引数 message に 渡してあげることで設定できそうです. 以下に Slackbot_worker.js#send() を 抜粋.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
bot.send = function(message, cb) {
botkit.debug('SAY', message);
/**
* Construct a valid slack message.
*/
var slack_message = {
type: message.type || 'message',
channel: message.channel,
text: message.text || null,
username: message.username || null,
parse: message.parse || null,
link_names: message.link_names || null,
attachments: message.attachments ?
JSON.stringify(message.attachments) : null,
unfurl_links: typeof message.unfurl_links !== 'undefined' ? message.unfurl_links : null,
unfurl_media: typeof message.unfurl_media !== 'undefined' ? message.unfurl_media : null,
icon_url: message.icon_url || null,
icon_emoji: message.icon_emoji || null,
};
// (省略)...
};

usernameicon_url の 渡し方ですが、こちらは、もうあまり考えることは無いですね. 既に channeltext を 渡しているわけですから、それらと一緒に渡すだけになります.

Slack ボット の 実装

以下にボットの発言部分 bot.say() の 実装を抜粋します.

1
2
3
4
5
6
bot.say({
channel: channel,
text: text,
username: `${current.weather[0].main}(${current.weather[0].description})`,
icon_url: `http://openweathermap.org/img/w/${current.weather[0].icon.replace('n', 'd')}.png`
});

channeltext に 合わせて、usernameicon_url を 設定するだけです.
前回は text に アイコン の URL を 使っていたので、Unix timestamp を パラメータでつけていましたが、今回は常に展開されるので Unix timestamp は 不要です.

通知!


アイコンと天気情報がコンパクトにまとまりました.
実際には “Today” の 線が引かれたりするので、さらに見やすくなると思われます.


今回はプログラムのテストで朝の情報を夜に出していますが、Slack への ポスト・タイミング と 天気予報の計算時刻は、そう大きくはずれないので “6:52 現在” などを削ってもよいかもしれませんね.