iCalendarフォーマットの予定をNode.jsでparseする

icalというnpmパッケージがあるので、これを利用すると素朴にiCal形式のデータを読み取ってオブジェクトとして扱うことができます。

var parser = require('ical');
var url = "http://〜/plan.ics";
parser.fromURL(url, {}, function(err, data) {
for(var plan in data) {
console.log(data[plan]);
}
});

とやると、以下の様な形で予定をparseすることができます。

{ type: 'VEVENT',
params: [],
start: { Mon, 13 Oct 2014 08:30:00 GMT tz: undefined },
dtstamp: '20141013T083000Z',
created: '20141013T083000Z',
'last-modified': '20141013T083000Z',
end: { Mon, 13 Oct 2014 09:00:00 GMT tz: undefined },
summary: '◯☓ミーティング',
organizer: 'hideack',
uid: '*****@****',
description: '定例です',
location: '',
sequence: '1',
status: 'CONFIRMED',
transparency: 'OPAQUE' }

便利そう。素朴にできるシリーズでした。

winstonを使ってみる(node.jsでログを取る)

node.jsでログを取るときにwinstonを使ってみたのでそのメモ。

まずはnpmコマンドでインストール。

$ npm install winston --save

で、詳しくはGithub上のREADMEを参照するとかなり詳しくかかれているので、それを参照しながら実際にログを取ってみます。

やりたいこととしては、

  • ファイルと標準出力にログを出したい
  • ファイルに記録する際はJSONではなくタイムスタンプとログレベルとメッセージが並ぶ様にしたい
  • 標準出力に表示する際は色を付け、タイムスタンプも表示し、全てのログを記録したい
  • 標準出力に出すか否かは任意にしたい

という設定を仮定してみます。以下の様な形。

var winston = require('winston');
var getLoggerSettings = function(consoleLog) {
var settings = {
transports: [
new winston.transports.File({ filename: "winston.log", json: false})
],
exceptionHandlers: [
new winston.transports.File({ filename: "winston.log", json: false})
]
};
if (consoleLog) {
settings.transports.push(new winston.transports.Console({colorize: true, timestamp: true, level: 'silly'}));
settings.exceptionHandlers.push(new winston.transports.Console({colorize: true, timestamp: true, level: 'silly'}));
}
return settings;
};
var logger = new (winston.Logger)(getLoggerSettings(true));
logger.silly('silly');
logger.debug('debug');
logger.verbose('verbose');
logger.info('info');
logger.warn('warn');
logger.error('error');

こうすることによって、ターミナル上には、

といった形でログが表示されます。また、ログファイル上にも、

2014-10-12T07:19:37.276Z - info: info
2014-10-12T07:19:37.276Z - warn: warn
2014-10-12T07:19:37.276Z - error: error

な形で記録されます。ファイル側にinfo以上のログしか記録されていないのは、new winston.transports.File({ filename: "winston.log", json: false}) としていてログレベルを明記していないので、標準のinfo以上のログが記録されています。

ここでは、標準出力とファイルログだけを対象にしましたが、winston-riakや、winston-mongodbという実装もあるので、ログをデータベースに記録することも容易そう*1

node.jsであれこれ書いてログを取りたいときはしばらく使ってみよう。

*1:見た感じですが...

node.jsで素朴にMySQLへ接続する

素朴 = ORMなどを利用せずに素朴なクエリを1行程度発行したい場合にどうしたんだっけ。と少し調べたのでメモエントリ。

npmのmysqlを利用する。

$ npm install mysql --save

あとは、接続→クエリ発行→切断の順で書いていく。

var db = require('mysql');
var settings = {
"host": "localhost",
"database": "sample_database",
"user": "sample_user",
"password": "sample_password"
};
var connection = db.createConnection(settings);
connection.query("select count(*) from users;", function(err, result) {
if (err) {
// 接続失敗
return;
}
console.log(result);  // [ { 'count(*)': 8 } ]
connection.end(function() {
// 接続終了
});
});

結果はJSONで得られる。素朴だ。

植田正治のつくりかた

少し前に買って一度全部眺めていたのだけど、改めて昨日から開きは閉じを繰り返してずっと眺めてる。

「三つ子の魂」といい「雀百まで」という。
いったんはまりこんだら、抜けることは容易ではないらしく、
今もって五十年前と同じような写真を撮っていることを、口にするのも恥ずかしい。
方向はともかく、写真に対する精神的燃焼度だけは、昔とちっとも変わっていないのだ、
といって自らを納得させるより仕方がない。
だって今は、今でも熱心なアマチュアだから。

植田正治のつくりかた

植田正治のつくりかた

gulpを利用してmochaで書かれたテストを実行する

定例の2周り遅れエントリ。Castoや、STORYBOARDSではtask runnerにGruntを利用していたのですが、glupも触ってみようということで使ってみました。

最近はnode.jsでちょっとしたツールを書いていたりすることが多く、そのテストにmochaを使って書いていたりするので試しにその実行のタスクをglupで書いてみることにしました。

まずは、glupのインストール。globalで入れてコマンドラインから叩ける様にします。

$ npm install -g gulp
$ gulp -v
[19:28:32] CLI version 3.8.8
[19:28:32] Local version undefined

実際にgulpを使いたいプロジェクトに入って、プロジェクト直下にもインストールします。

$ cd project
$ npm install gulp --save-dev
$ gulp -v
[19:30:00] CLI version 3.8.8
[19:30:00] Local version 3.8.8

更にmochaのテストをgulpで実行させるために、gulp-mocha等々入れます。

$ npm install gulp-mocha --save-dev
$ npm install gulp-util --save-dev

これで準備ができたので、プロジェクト直下に gulpfile.js を作成します。今回は、

  • mochaのテストを実行するタスク
  • libディレクトリまたはtestディレクトリ以下を監視して、ファイルに変更があればそのmochaのテストを実行するタスクを呼び出すというタスク

の2つを書いてみます。ほぼサンプルそのままですが...。

var gulp = require('gulp');
var mocha = require('gulp-mocha');
var gutil = require('gulp-util');
gulp.task('mocha', function() {
return gulp.src(['test/*.js'], { read: false })
.pipe(mocha({ reporter: 'list'}))
.on('error', gutil.log);
});
gulp.task('watch-mocha', function() {
gulp.watch(['lib/**', 'test/**'], ['mocha']);
});

こうすることで、mochawatch-mocha というタスクが作成されました。まずシンプルにテストを実行するには、プロジェクトルートで

$ gulp mocha
[19:35:25] Using gulpfile ~/project/gulpfile.js
[19:35:25] Starting 'mocha'...
․ test A : 16ms
(snip)
5 passing (29ms)
[19:35:25] Finished 'mocha' after 397 ms

とgulpを利用してmochaのテストを実行できます。もうひとつ作成している watch-mocha というタスクを実行すると

[19:37:58] Using gulpfile ~/project/gulpfile.js
[19:37:58] Starting 'watch-mocha'...
[19:37:58] Finished 'watch-mocha' after 9.99 ms

と表示され待機状態になるので、gulpfile.js 上で指定したlib及びtestディレクトリ以下のファイルを編集して保存すると自動的に変更が検出されたタイミングでmochaのテストが実行されます。

[19:37:58] Using gulpfile ~/project/gulpfile.js
[19:37:58] Starting 'watch-mocha'...
[19:37:58] Finished 'watch-mocha' after 9.99 ms
[19:39:32] Starting 'mocha'...
․ test A : 16ms
(snip)

もっとも、この程度のタスクの大きさだとあんまりメリット感じられないのですが、gulpfile.js

gulp.src(['test/*.js'], { read: false }).pipe(mocha({ reporter: 'list'})).on('error', gutil.log);

のくだりの手続き的に書いていくやり方はわかりやすい気もしたり。もう少しあれこれ触っていこうかと思います。

node.jsでヒアドキュメント

Node.jsでプログラムを書いている時、JavaScriptでヒアドキュメント書きたいとき*1が稀にあって、そんなときはnpmパッケージのhereを使うと実現できたりします。

$ npm install here --save

した後に、

var here = require('here').here;
var testDoc = here(/*
def foo
  bar
end
*/).unindent();
console.log(testDoc)

とすれば、

def foo
bar
end

と表示されます。

NPM

*1:mochaでテスト書くときとかに...

sails+MongoDBでJSONベースのAPIを作成してみる

先日からAPIサーバをsailsとMongoDBを使って作ってみようとあれこれしてみたのでその際のメモです。

sailsの特徴に

  • 最初からsocket.io(websocket)が利用できる
  • JSONベースのAPIが簡単に作れる

があるのですが、ここでは後者のJSONベースのAPIを作ってみることにして、データストアにMongoDBを使ってみました。*1


準備

sailsのGet Startedページを参考にしつつ、npm及びsailsコマンドが使える状況であれば...

$ sails new testapp
info: Created a new Sails app `testapp`!

testapp というディレクトリが掘られてアプリケーションの雛形が作成されます。

今回はMongoDBへ接続してみるのでそのディレクトリ内でsails-mongoを入れておきます。

$ npm install sails-mongo --save

接続設定

config/connections.js に接続設定を書きます。

既にサンプルの記述はsailsコマンドで出力されているので必要あらばホスト名, ポート番号, 接続用ユーザ名, パスワード, データベース名を書き換えます。

  someMongodbServer: {
adapter: 'sails-mongo',
host: 'localhost',
port: 27017,
// user: 'username',
// password: 'password',
// database: 'your_mongo_db_name_here'
},

続けて、config/env/development.js に開発環境の場合にモデルから接続するデータベース接続を設定することができるので設定します。
connectionの箇所に上の config/connections.js で定義した接続名を記載。

module.exports = {
models: {
connection: 'someMongodbServer'
}
};

API生成(CRUDできるコントローラ + Modelの生成)

実際にMongoDBに作成されるコレクションに対応するModelとそれをCRUD操作できるコントローラを作成します。

サンプルとしてUserというモデルを作成してみます。sailsコマンドを入力。

$ sails generate api user
info: Created a new model ("User") at api/models/User.js!
info: Created a new controller ("user") at api/controllers/UserController.js!
info: REST API generated @ http://localhost:1337/user
info: and will be available the next time you run `sails lift`.

これで接続設定は完了したのでおもむろにsailsサーバを立ちあげます。新しくMongoDB上にデータベースを作成することになるのでalterを選択してsailsからMongoDB上にデータベースとコレクションを作成してもらいます。

$ sails lift
info: Starting app...
-----------------------------------------------------------------
Excuse my interruption, but it looks like this app
does not have a project-wide "migrate" setting configured yet.
(perhaps this is the first time you're lifting it with models?)
In short, this setting controls whether/how Sails will attempt to automatically
rebuild the tables/collections/sets/etc. in your database schema.
You can read more about the "migrate" setting here:
http://sailsjs.org/#/documentation/concepts/ORM/model-settings.html?q=migrate
In a production environment (NODE_ENV==="production") Sails always uses
migrate:"safe" to protect inadvertent deletion of your data.
However during development, you have a few other options for convenience:
1. safe  - never auto-migrate my database(s). I will do it myself (by hand)
2. alter - auto-migrate, but attempt to keep my existing data (experimental)
3. drop  - wipe/drop ALL my data and rebuild models every time I lift Sails
What would you like Sails to do?
info: To skip this prompt in the future, set `sails.config.models.migrate`.
info: (conventionally, this is done in `config/models.js`)
warn: ** DO NOT CHOOSE "2" or "3" IF YOU ARE WORKING WITH PRODUCTION DATA **
prompt: ?:  2
Temporarily using `sails.config.models.migrate="alter"...
(press CTRL+C to cancel-- continuing lift automatically in 0.5 seconds...)
info:
info:
info:    Sails              <|
info:    v0.10.4             |\
info:                       /|.\
info:                      / || \
info:                    ,'  |'  \
info:                 .-'.-==|/_--'
info:                 `--'-------'
info:    __---___--___---___--___---___--___
info:  ____---___--___---___--___---___--___-__
info:
info: Server lifted in `/Users/usr0600170/pj/testapp`
info: To see your app, visit http://localhost:1337
info: To shut down Sails, press <CTRL> + C at any time.
debug: --------------------------------------------------------
debug: :: Sat Aug 30 2014 15:12:56 GMT+0900 (JST)
debug: Environment : development
debug: Port        : 1337
debug: --------------------------------------------------------

sailsだけにヨットです。

実際にAPIを呼び出してみる。

この時点で先に作成したUserモデルをCRUDすることができるAPIが動作しています。*2

簡単に確認してみるときは、curlでも良いのですがHTTPieが便利なのでこれを使って試してみます。

POSTをすればCreate

$ http -f POST localhost:1337/user name=hideack
HTTP/1.1 200 OK
Connection: keep-alive
Content-Length: 145
Content-Type: application/json; charset=utf-8
Date: Sat, 30 Aug 2014 06:15:36 GMT
X-Powered-By: Sails <sailsjs.org>
{
"createdAt": "2014-08-30T06:15:36.825Z",
"id": "54016c080a473e0000da6837",
"name": "hideack",
"updatedAt": "2014-08-30T06:15:36.825Z"
}

POSTした際に得られたidでGETすればRead

$ http GET localhost:1337/user/54016c080a473e0000da6837
HTTP/1.1 200 OK
Connection: keep-alive
Content-Length: 145
Content-Type: application/json; charset=utf-8
Date: Sat, 30 Aug 2014 06:15:54 GMT
X-Powered-By: Sails <sailsjs.org>
{
"createdAt": "2014-08-30T06:15:36.825Z",
"id": "54016c080a473e0000da6837",
"name": "hideack",
"updatedAt": "2014-08-30T06:15:36.825Z"
}

同様にそのidでDELETEすればDelete

$ http DELETE localhost:1337/user/54016c080a473e0000da6837
HTTP/1.1 200 OK
Connection: keep-alive
Content-Length: 145
Content-Type: application/json; charset=utf-8
Date: Sat, 30 Aug 2014 06:19:12 GMT
X-Powered-By: Sails <sailsjs.org>
{
"createdAt": "2014-08-30T06:15:36.825Z",
"id": "54016c080a473e0000da6837",
"name": "hideack",
"updatedAt": "2014-08-30T06:15:36.825Z"
}
$ http GET localhost:1337/user/54016c080a473e0000da6837
HTTP/1.1 404 Not Found
Connection: keep-alive
Content-Length: 40
Content-Type: text/html; charset=utf-8
Date: Sat, 30 Aug 2014 06:19:20 GMT
X-Powered-By: Sails <sailsjs.org>
No record found with the specified `id`.

sails + MongoDBの構成でシンプルなCRUDするAPIであれば上記の様な手順でサクッとできるので便利ですね。

ただ、これは序章でここからいろいろ試みていくと多々踏み抜いたので追々書いていこうかと思います。

*1:特に指定をしないとJSONベースで格納されるファイルベースのデータストアが利用されます

*2:MongoDBなので...

sailsでsocket.ioを無効にする方法

最近sailsを使ってAPIサーバを書いて見る試みをしていたりするのですが、sailsでは sails new コマンドでプロジェクトを作成するとデフォルトでsocket.ioが有効になるので、これを無効にする方法を調べたのでメモ。

結論としては .sailsrc というファイルをプロジェクトルートに置いてあげることで制御することが出来ます。

{
"hooks": {
"sockets": false,
"pubsub": false
}
}

カラメルお取り寄せ会に参加してきましたよ

会社で開催されたカラメルお取り寄せ会に参加しましたよ。のエントリー。

今回は秘密のケンミンショーでも紹介されたことのある金沢郷土料理の老舗 ふくら屋の惣菜缶詰のお取り寄せということで、各自白ご飯やおにぎりを持参して参加してきました。缶詰の図柄から美味しさの期待が膨らみます。

いくつか缶詰に種類があったのですが、いもだこを写真の撮影用に器にあけてみました。「いもだこ」ってその名の通り蛸と旬の里芋を煮込んだ能登は輪島の郷土料理とのことで里芋に蛸の味が染みてそれはとてもとても美味しかったです。

今回取り寄せた缶詰には他にもお多福豆やニシンの甘露煮、たらの子も入っていて一缶一缶じっくり味わえます。この缶詰は以下からご購入いただけますよ。ぷち贅沢に是非。

 
 

TOKYOAMEDAYO – 東京が雨予報ならYo

YoのAPIキーを取ってみたので試しに何か作ってみようということで、
東京地方に雨の予報が出ていたらYoしてくれるアカウントを作ってみました。

TOKYOAMEDAYO というアカウントに利用中の端末からYoしてもらえれば以降、毎朝7時30分に東京地方に雨の予報が出ていれば、このアカウントからYoされます。

スクリプトが行っているのは、livedoor天気の東京地方の本日の予報から「雨」が含まれていたらYoするだけです。今回試してみた様な「雨が降る/降らない」といった2値情報であれば、Yoで気軽にpush出来て良いなと思いました。

とりあえずnpm化したので、Yo API Keyと先のlivedoor天気の予報地域先のIDを渡せば、日本国内の他の地域の雨予報もYoできる。と思います。

NPM