gist

2012年5月29日火曜日

[Node.js] sprintfが意外と使える件



sprintfは、その名の通り書式を指定して文字列を生成するパッケージです。

sprintfは、JavaScriptのsprintfライブラリと同じ動作をします。オブジェクトや配列を出力できます。

$ npm install sprintf

CoffeeScript

sprintf = require('sprintf').sprintf
vsprintf = require('sprintf').vsprintf

# %2$s で2番目の文字を出力します。
console.log sprintf '%2$sは%3$sが%1$sです!', '大好き', 'ニャル子', '真尋さん'

# vsprintfでは配列を出力します
console.log vsprintf '登場人物: %s, %s, %s, %s', ['真尋', 'ニャル子', 'フー子', 'ハス太']

# オブジェクトを出力します。%(プロパティ名)s で指定します。
user = {name:'ニャルラトホテプ', nickname:'ニャル子'}
console.log sprintf '%(name)sのニックネームは、%(nickname)sです', user 

# オブジェクトの配列も出力可能
users = [
    {name: '真尋'}
    {name: 'ニャル子'}
    {name: 'フー子'}
]
console.log sprintf '%(users[0].name)s, %(users[1].name)s %(users[2].name)s', {users: users}

結果

$ coffee sample.coffee 
ニャル子は真尋さんが大好きです!
登場人物: 真尋, ニャル子, フー子, ハス太
ニャルラトホテプのニックネームは、ニャル子です
真尋, ニャル子 フー子

地味ですが強力なパッケージです。もちろん%d, %f, %xなども使えます。

2012年5月28日月曜日

hook.ioで「 (」・ω・)」うー!(/・ω・)/にゃー!」してみた




hook.ioは、ソケット通信を利用してデータ通信を可能にするパッケージです。イベント名をドメインで管理することができます。
$ npm install -g hook.io
 

uh.coffeeとnya.coffeeを用意します。

uh.coffee
hookio = require 'hook.io'

hookA = hookio.createHook {name: "a"}
hookA.on "*::uh", (data)->
 console.log data
 setTimeout ()->
  hookA.emit 'nya', '(/・ω・)/にゃー!'
 , 1000

hookA.start()

createHookメソッドでフックの名前を指定しています。hookA.on の第1引数にイベント名を指定します。これは::で区切ったドメイン風に指定できます。*::uh であれば、最後のイベント名が uh であれば補足して、第2引数に指定した関数を実行します。第2引数のメソッドの引数dataには、飛んできたdataが入ってきます。console.logでdataの内容を出力して、1秒したら nyaイベントを発火(emit)します。

続いてnya.coffee。

nya.coffee
hookio = require 'hook.io'

hookB = hookio.createHook {name: "b"}
hookB.on 'hook::ready', ()->
  hookB.emit 'uh', '(」・ω・)」うー!'

hookB.on '*::nya', (data)->
 console.log data
 setTimeout ()->
  hookB.emit 'uh', '(」・ω・)」うー!'
 , 1000

hookB.start();

hook::redayで1回 uhイベントを発火します。hook::readyは hookが用意できた時にhook.ioから発火されるイベントです。もし nyaイベントが飛んできたら データを出力して1秒後に uhイベントを発火します。

イベントをドメインでフィルタできるのがいいところ、かと。

実行結果

video


レッツ\(・ω・)/にゃー!

2012年5月27日日曜日

mimeを使ってみた

mimeは、MIME-TYPEをマッピングしているパッケージです。

$ npm install mime

CoffeeScript

mime = require 'mime'

console.log '--- lookup ---'
console.log mime.lookup '.txt'
console.log mime.lookup '.mp3'
console.log mime.lookup 'a.htm'
console.log mime.lookup '.flv'

console.log '--- extension ---'
console.log mime.extension 'text/html'
console.log mime.extension 'application/vnd.ms-excel'
console.log mime.extension 'video/x-m4v'
console.log mime.extension 'application/json'

mimeには、ファイルの拡張子からMIME-TYPEを取得する lookup メソッドと、その逆でMIME-TYPEから拡張子を取得する extensionメソッドがあります。

実行してみます。

$ coffee sample.coffee 
--- lookup ---
text/plain
audio/mpeg
text/html
video/x-flv
--- extension ---
html
xls
m4v
json

また、mimeでは、独自のMIME-TYPEを追加することができます。

mime = require 'mime'

console.log '--- custom ---'

mime.define {
 'text/coffee': ['coffee', 'cf']
 'text/ruby': ['rb', 'ruby']
}

console.log mime.lookup 'sample.coffee'
console.log mime.lookup 'sample.cf'
console.log mime.extension 'text/coffee'
console.log mime.lookup 'sample.rb'
console.log mime.extension 'text/ruby'

console.log '--- load sample.types ---'
mime.load 'sample.types'
console.log mime.lookup 'a.mid'
console.log mime.extension 'audio/x-midi'

defineメソッドでコードからMIME-TYPEを追加できます。loadメソッドでは、ファイルを指定して追加することもできます。このときのファイルフォーマットは、Apacheのtypes形式となります。

sample.types

audio/x-midi mid

実行

$ coffee sample.coffee 
--- custom ---
text/coffee
text/coffee
coffee
text/ruby
rb
--- load sample.types ---
audio/x-midi
mid

mimeは、地味ですが、expressなどのWebフレームワークで使われている重要なパッケージの一つです。

2012年5月24日木曜日

ディレクトリ丸ごと操作できるwrenchを使ってみた

wrenchは、ディレクトリに対して、mkdir、chmod、chown、rmdir などができるパッケージです。

$ npm install wrench

CoffeeScript


wrench = require 'wrench'


files = [];
wrench.readdirRecursive '.', (error, curFiles)->
    console.log curFiles

wrench.chmodSyncRecursive '.', '0755'

結果

他にも、mkdirSyncRecursive、rmdirSyncRecursive、readdirSyncRecursive、chownSyncRecursive、copyDirSyncRecursive などのメソッドが用意されています。

ディレクトリに対して操作できるパッケージとして使われており、npmでも上位に位置しています。

2012年5月22日火曜日

フォームデータを解析する formidable を使ってみた

formidable は、受信したフォームデータを解析し、オブジェクトに変換するパッケージです。connectパッケージで使われています。

$ npm install formidable

CoffeeScript

formidable = require 'formidable'
http = require 'http'
util = require 'util'

http.createServer (req, res)->
 if req.url is '/upload' and req.method.toLowerCase() is 'post'
  form = new formidable.IncomingForm()
  form.parse req, (err, fields, files)->
   res.writeHead 200, {'content-type':'text/plain; charset=UTF-8'}
   res.write 'received uploaded\n\n'
   res.end util.inspect {fields: fields, files: files}
  return

 res.writeHead 200, {'content-type': 'text/html'}
 res.end """
 <html><head><meta charset="utf-8"></head>
 <body>
 <form action="/upload" enctype="multipart/form-data" method="post">
 <input type="text" name="title"><br>
 <input type="file" name="upload" multiple="multiple"><br>
 <input type="submit" name="Upload">
 </form>
 </body>
 """
.listen 3000

new formidable.IncomingForm() でインスタンス化し、parse 関数で解析を開始します。コールバックの第2引数 fieldsには、フォームデータのキー(inputタグのname属性)と値(value値)のオブジェクトが配列で入ってきます。第3引数 files には、アップロードされたデータの情報が入ってきます。

実行します。

$ coffee sample.coffee

ブラウザで http://localhost:3000 にアクセスします。

テキストフィールドに適当な文字列を入力し、適当なファイルを選択して、送信します。

特にファイル情報を簡単に、しかも高速に取得できる点で、とても便利なパッケージです。1万以上のパッケージの中で57のパッケージに使われています。

2012年5月21日月曜日

ディレクトリを簡単に作成できる mkdirp を試してみた

mkdirpは、ディレクトリを作成するだけのパッケージです。ちょうど mkdir -p を実行したのと同じ動作になります。


$ npm install mkdirp

CoffeeScript

mkdirp = require 'mkdirp'

mkdirp 'sample/sample2/sample3', (err)->
 if err 
  console.log err
 else 
  console.log 'created!'


実行結果

$ coffee sample.coffee 
created!
$ tree
.
├── sample
│   └── sample2
│       └── sample3
└── sample.coffee

3 directories, 1 file

ちょっとしたパッケージですが、148ものパッケージに使われています。こういうアイデアも大事ですね。

2012年5月20日日曜日

クエリ文字列をオブジェクトに変換する qs を使ってみた

qsは、クエリ文字列をオブジェクトへ、オブジェクトからクエリ文字列に変換できるパッケージです。expressやconnectで使われています。

$ npm install qs

qsには、parseとstringifyの2つのメソッドがあります。

qs = require 'qs'

obj = qs.parse 'user[name][first]=Miku&user[name][last]=Hatsune&user[email]=miku@vocaloid.com'

console.log obj

obj = 
 user: 'Hatsune Miku'
 mail: 'miku@vocaloid.com'

str = qs.stringify obj

console.log str

実行結果

$ coffee sample.coffee 
{ user: 
   { name: { first: 'Miku', last: 'Hatsune' },
     email: 'miku@vocaloid.com' } }
user=Hatsune%20Miku&mail=miku%40vocaloid.com

2012年5月19日土曜日

node-progressで進捗をコンソール出力してみた

node-progressは、ファイルダウンロードなどの進捗状況をコンソールに出力するためのパッケージです。

$ npm install progress

ProgressBar = require 'progress'

progress = new ProgressBar 'downloading [:bar] :percent :etas', {
 total: 20
 width:20
}

timer = setInterval ()->
 progress.tick()
 if progress.complete
  console.log 'Complete!\n'
  clearInterval timer
, 1000

new ProgressBar の第1引数にコンソール出力の書式を指定します。書式には以下を指定できます。

  • :bar・・・プログレスバー
  • :current・・・進捗の値
  • :total・・・進捗の合計
  • :percent・・・進捗の割合
  • :elapsed・・・経過した時間
  • :eta・・・残り時間

第2引数には、オプションを指定できます。

  • :total・・・進捗の合計
  • :width・・・プログレスバーの長さ
  • :complete・・・プログレスバーの完了時の文字列
  • :imcomplete・・・プログレスバーの未完了の文字列

2012年5月17日木曜日

コンソール出力を整形するcliffを使ってみた

cliffは、コンソール出力を整形して色もつけられるパッケージです。


$ npm install cliff
cliff@0.1.7 ../../../node_modules/cliff 
├── colors@0.6.0-1
├── eyes@0.1.7
└── winston@0.5.11

CoffeeScriptで書いてみます。

cliff = require 'cliff'

rows = [
    ['Name',  'Flavor',    'Dessert'],
    ['Alice', 'cherry',    'yogurt'],
    ['Bob',   'carmel',    'apples'],
    ['Joe',   'chocolate', 'cake'],
    ['Nick',  'vanilla',   'ice cream']
]

cliff.putRows 'data', rows, ['red', 'blue', 'green']

実行結果

日本語ですと上手く整形されないようです。

2012年5月16日水曜日

finditを試してみた

finditは、ディレクトリを再帰的に探索できるパッケージです。

$ npm install findit

CoffeeScriptで書いてみます。

findit = require 'findit'

finder = findit.find('..')

finder.on 'directory', (dir, stat)->
 console.log dir + '/'

finder.on 'file', (file, stat)->
 console.log 'File: ' + file

finder.on 'link', (link, stat)->
 console.log 'Link: ' + link

findメソッドで、対象ディレクトリを指定します。EventEmitterのonメソッドでdirectory, file, link毎に処理を書けます。

実行してみます。expressでファイルを増やしています。

$ express .
$ coffee sample.coffee
File: ./app.js
File: ./package.json
./public/
./public/images/
./public/javascripts/
./public/stylesheets/
File: ./public/stylesheets/style.css
./routes/
File: ./routes/index.js
File: ./sample.coffee
./views/
File: ./views/index.jade
File: ./views/layout.jade

あまりにファイル数が多いディレクトリを指定すると、コールスタックがサイズオーバーして落ちる場合があります。

/Users/inouetomoyuki/node_modules/findit/node_modules/seq/index.js:76
        f.apply(cb, context.stack);
          ^
RangeError: Maximum call stack size exceeded
    at Function.APPLY_OVERFLOW (native)
    at action (/Users/inouetomoyuki/node_modules/findit/node_modules/seq/index.js:76:11)
    at next (/Users/inouetomoyuki/node_modules/findit/node_modules/seq/index.js:208:17)
    at /Users/inouetomoyuki/node_modules/findit/node_modules/seq/index.js:213:30
    at /Users/inouetomoyuki/node_modules/findit/node_modules/seq/index.js:55:24
    at Function.<anonymous> (/Users/inouetomoyuki/node_modules/findit/index.js:75:25)
    at Function.<anonymous> (/Users/inouetomoyuki/node_modules/findit/node_modules/seq/index.js:210:38)
    at action (/Users/inouetomoyuki/node_modules/findit/node_modules/seq/index.js:76:11)
    at next (/Users/inouetomoyuki/node_modules/findit/node_modules/seq/index.js:208:17)
    at /Users/inouetomoyuki/node_modules/findit/node_modules/seq/index.js:213:30

依存モジュールのseqから発火されています。未解決のようです。node 0.7.8(Win版)ではhack方法が紹介されています。

2012年5月15日火曜日

[Node.js] dnodeで簡単に非同期通信してみた

dnodeは、ソケット通信を利用して、クライアント/サーバ間で簡単に関数を実行できるNode.jsらしいパッケージです。

$ npm install dnode

サーバ側はこんな感じです。

server.coffee

dnode = require 'dnode'

server = dnode {
 hoge: (str, cb)->
  cb str + ' World!'
}
server.listen(8080)

dnodeメソッドで関数を指定し、listenでサーバを起動します。ここではhogeという関数を指定しています。

クライアント側はこんな感じで。

client.coffee

dnode = require 'dnode'

dnode.connect 8080, (remote)->
 remote.hoge 'Hello', (result)->
  console.log 'result=' + result

connect関数でポートを指定してサーバに接続。引数remoteで、サーバ側で指定した関数hogeを実行しています。第一引数に「Hello」を与えると、サーバ側で「World」が追加されて、resultに返却されます。

サーバーを起動してから、別ターミナルでクライアントを実行します。

サーバ側を起動

$ coffee server.coffee

クライアントを起動

$ coffee client.coffee 
result=Hello World!

socket.ioで実装することも可能ですが、dnodeを使うと、非常に簡単に通信が可能になります。

ブラウザ側にも対応しています。サンプルも豊富ですのでぜひお試しあれ。

それにしても、このキャラはなに?有名なの?

2012年5月14日月曜日

promptを使ってみた

promptは、コマンドラインからプロンプト入力できる Node.jsのパッケージです。

$ npm install prompt
prompt@0.1.12 ../../../node_modules/prompt 
├── pkginfo@0.2.3
├── colors@0.6.0-1
├── async@0.1.18
└── winston@0.5.11

CoffeeScriptはこんな感じです。

prompt = require 'prompt'

prompt.start()

prompt.get ['username', 'email'], (err, result)->
 console.log 'コマンドラインからの入力値:'
 console.log '  username: ' + result.username
 console.log '  email   : ' + result.email

実行してみます。

$ coffee sample.coffee 
prompt: username: ニャルラトホテプ
prompt: email: nyaruko@Lovecraft.com
コマンドラインからの入力値:
  username: ニャルラトホテプ
  email   : nyaruko@Lovecraft.com

prompt.get() メソッドの第1引数に、プロンプトに入力するキーを配列で指定します。第2引数には、エラーと結果(result)を引数としたコールバックを渡します。入力値はresultにキーを指定して取得できます。

入力値のバリデーションやパスワード入力(非表示)も可能です。

prompt = require 'prompt'

props = [
 {
  name: 'email'
  validator: /^([a-zA-Z0-9])+([a-zA-Z0-9\._-])*@([a-zA-Z0-9_-])+([a-zA-Z0-9\._-]+)+$/
  warning: '正しいEmailを入力して下さい'
  empty: false
 }
 {
  name: 'password'
  hidden: true
 }
]

prompt.start()

prompt.get props, (err, result)->
 console.log 'コマンドラインからの入力値:'
 console.log '  email   : ' + result.email
 console.log '  password: ' + result.password

変数propsを作成します。各キーをオブジェクトで指定し、プロパティを設定します。

  • name:キーの名前を指定します。ユーザからの入力値を取り出す場合に使います。
  • validator:入力チェックを正規表現で指定します。
  • warning:入力チェックでNGだった場合の警告メッセージを指定します。
  • empty:必須入力ならfalse。
  • hidden:パスワード入力のように入力値を隠すならtrue。

実行結果です。

$ coffee sample.coffee 
prompt: email:  a 
error:  Invalid input for email
error:  正しいEmailを入力して下さい
prompt: email: sample@sample.com
prompt: password: 
コマンドラインからの入力値:
  email   : sample@sample.com
  password: password

promptは、hook.ioやwizardなど、27のパッケージから使われています。shouldやjshintと同じくらいでしょうか。充分使えるようです。

2012年5月10日木曜日

Nodepressを試してみた

Nodepressはシンプルなブログシステムです。

$ npm install nodepress
$ cp ./node_modules/nodepress/skeletons/blog/server.js .
$ node server.js 

Wordpressのようにはいけませんが、コードリーディングには最適です。

2012年5月9日水曜日

diskspaceで容量確認してみた

diskspaceは、ドライブの使用容量と空き容量、状態を確認できるパッケージです。

$ npm install diskspace

コードはこんな感じです。

diskspace = require 'diskspace'

diskspace.check '/', (total, free, status)->
 console.log 'Total : ' + total + ' Byte'
 console.log 'Free  : ' + free + ' Byte'
 console.log 'Status: ' + status

実行すると、こんな感じ。

$ coffee sample.coffee 
Total : 319213174784 Byte
Free  : 82739359744 Byte
Status: READY

大体あってますね。

使いどころがそんなに無いかも。

2012年5月8日火曜日

サンダルを履くようにブログを作成する「flipflop」

flipflopは、作者曰く「サンダルを履くような感覚でブログを作成できる」パッケージです。markdown形式で記事を書けます。記事は手動で書きます。

$ npm install -g flipflop

flipflop create でプロンプトが表示されるので、ブログの情報を入力します。

$ flipflop create
prompt: Blog title: My Blog
prompt: Blog description: This my blog site
prompt: May I create your blog @ "/Users/inouetomoyuki/Projects/node/my-blog"?: yes

my-blog というディレクトリが作成されます。早速起動してみます。

$ cd my-blog
$ flipflop start
/Users/inouetomoyuki/Projects/node/my-blog/articles
info:   http server listening. port=8080

http://localhost:8080 にアクセスします。

トレードマークなのか、サンダルが表示されます。シンプルなブログです。

記事を追加するには、articles ディレクトリに markdown形式で記述します。

その前に作者を登録します。blog.jsonを以下のように書き換えます。

{
 "title": "My Blog",
 "description": "This my blog site",
 "keywords": [],
 "authors": {
  "bradharris": {
   "name": "Brad Harris",
   "gravatar": "bmharris@gmail.com",
   "github": "bmharris"
  },
  "tomoyuki": {
   "name": "Tomoyuki INOUE",
   "gravatar": "sample@gmail.com",
   "github": "tomoyukiinoue"
  }
 },
 "articles": "articles",
 "domain": "http://yourdomain.com"
}

サンプルの記事をコピーして作ってみます。

$ cp -R articles/flipflop-ftw/ articles/hello-world

article.json に記事のメタ情報を記述します。authorには、blog.jsonに追記した作者のキーを記述します。

{
 "author": "tomoyuki",
 "title": "Hello World",
 "date": "05/09/2012",
 "publish": true,
 "tags": [
  "flipflop",
  "sample",
  "node.js"
 ]
}

article.md に記事の内容を記述します。

# flipflop

## サンダルを履くようにブログを作成しよう

+ **[markdown][]** - 記事をMarkdown形式で記述できます。
+ **[jade][]** - テーマをJadeテンプレートと[less][]でカスタマイズできます。
+ run it from a [node.js http server](#start-er-up), or [generate a static site](#static-sites-are-hawt) that you can host pretty much anywhere and not worry about dependencies.

---

## インストールする

**flipflop** はグローバルインストールすることでcliを提供します。

```
> npm install -g flipflop
```

## 新しいブログを作成する

```
> flipflop create
```

This starts a cli app that will prompt for a few bits of info about your blog, and create a directory for it in the `process.cwd()`.

## 起動する

Make sure you're inside your blog's directory.

```
> flipflop start <port>
```
check your browser @ `http://localhost:8080`
+ port is optional, defaults to 8080

起動してみます。

lessを使ってテーマも変更できます。2つのファイルだけで記事を追加できます。サンダルを履いたようには簡単、かもしれません、たぶん。

2012年5月7日月曜日

punchでサクッとHTMLを作る

punchは、サクッとHTMLを作れるパッケージです。JSONでデータ部分を、Mustacheでテンプレートを記述してサーバを起動するとHTMLができあがります。

$ npm install -g punch
$ mkdir sample
$ cd sample
$ npm install mime
$ punch setup

punch setup で以下のようなディレクトリが作成されます。

$ tree .
.
├── config.json
├── contents
└── templates

templatesディレクトリには、mustache形式でテンプレートを作成していきます。contentsディレクトリには、JSON形式でmustacheファイルへのデータwp記述します。

templates/about.mustache

<!doctype html>

  <head>
  <meta charset="utf-8">

  <title>{{title}}</title>
  </head>

  <body>

    <h1>{{title}}</h1>

   <p>{{{overview}}}</p> 

    <ul>
      {{#team}}
        <li><strong>{{name}}</strong> - {{bio}}</li>
      {{/team}}
    </ul>
  </body>
  </html>

contents/about.json

{
    "title": "About Us",
    "team": [
      {
        "name": "Pointy-Haired Boss",
        "bio": "Incompetent Manager"
      },

      {
        "name": "Wally",
        "bio": "Senior Engineer"
      },

      {
        "name": "Dilbert",
        "bio": "Engineer"
      }
    ]
  }

サーバを起動します。

$ punch server
Server is running on localhost:9009
Generating the site...
Serving requests...

ターミナルに戻ると、publicディレクトリにabout.htmlが作成されています。

<!doctype html>

  <head>
  <meta charset="utf-8">

  <title>About Us</title>
  </head>

  <body>

    <h1>About Us</h1>

   <p></p> 

    <ul>
        <li><strong>Pointy-Haired Boss</strong> - Incompetent Manager</li>
        <li><strong>Wally</strong> - Senior Engineer</li>
        <li><strong>Dilbert</strong> - Engineer</li>
    </ul>
  </body>
  </html>

mustacheで見た目よくテンプレートを作成できます。ちょっとしたHTML作成にはいいかもれません。