Skip to content

Instantly share code, notes, and snippets.

@udzura udzura/tutorial.md
Created Jun 2, 2014

Embed
What would you like to do?
Hubot + CoffeeScript ではじめるやわらかプログラミング入門

やわらかプログラミング入門

  • Hubot であそぼう


始めに、地図を描く


Joel on Software - 5つの世界

  • パッケージ
  • インターナル
  • 組み込み
  • ゲーム
  • 使い捨て

パッケージ && Webサービスの世界の地図

  • Windows と UN*X
  • クライアントとサーバー
  • アプリとバッチ
  • ブラウザとネイティブ

演習

  • プログラミング言語を地図の上に置く
    • Ruby
    • JavaScript
    • Perl
    • Python
    • PHP
    • Java
    • Haskell
    • C
    • C++
    • Lua
    • Objective-C
    • C#
    • VisualBasic

まとめ

  • プログラミングでできることは果てしなく広い
  • 何のためにプログラミングをするかが重要、目的がはっきりしていればそれに向いた言語を学べ、学習が効率的になる

CoffeeScriptとHubot


今日の仮の目的

  • どのプログラミング言語でも使えるような基本中の基本を学ぶ
  • なるべく短い時間でSUGEEE経験をする
  • なるべく身近な役立つツールを作る

CoffeeScriptとは

  • 「スクリプト言語」
  • JavaScriptに変換できる言語
  • JavaScriptなので、サーバ(node.js)、クライアント(ブラウザやTitanium)、バッチ(Grunt)に使えて便利

言語的に難解すぎない割にモダンな特徴を持っている

  • たとえば
    • オブジェクト指向
    • 無名関数
    • 非同期
    • 動的型付け
  • JavaScript、Ruby、Pythonにステップアップできる(と思う

Hubotとは

  • 「Bot」のための「フレームワーク」
  • 「フレームワーク」は雑な言い方をすれば、ソフトウェアを作るためのソフトウェア
  • 皆さんが今後毎日使うIRCのBotを簡単に作る
  • IRC以外にも、HipchatなどAPIの公開されたチャットサービスの多くで使えるようになっている(skypeはもうすぐ使えなくなる、残念!)

セットアップとHello, world


CoffeeScriptのインストール

  • まず、JavaScriptを入れる
    • 同じ言語でも、いろいろな実装があることを覚えておく。今回はnode.js
  • npmが一緒に入る
    • node package manager = node の便利なツール、ライブラリを入れてくれるコマンド

Mac

$ curl -L git.io/nodebrew | perl - setup
$ echo 'export PATH=$HOME/.nodebrew/current/bin:$PATH' >> ~/.bash_profile
$ source ~/.bash_profile
$ nodebrew install-binary v0.10.28
$ nodebrew use v0.10.28

Windows


そしたら

  • やっとhubotをインストール
$ npm install -g coffee-script hubot

Windowsの方へ...

  • 将来、Webサービスの開発に行くならLinuxかせめてOS Xを使おう
  • どうしても動かない時は https://www.nitrous.io/ を使う

エディタのインストール

  • ファイルの編集
  • Vim, Emacs, 別にいいけど...今日教えること何もありません
  • 秀丸、TeraPad、さくらエディタ、たぶんJavaScriptなんで使えるけど...
  • それっぽいのなら Sublime Text 評価版だが、永遠に使える...

Hubotのプロジェクトを作る

  • コマンドライン操作
  • PATHを通す必要があるかも
$ hubot -c yawaraka-hubot

Hello, hubot

  • shellアダプター
  • デフォルトの機能(pingとかyoutubeとか)
$ cd yawaraka-hubot
$ npm install
$ echo "[]" > hubot-scripts.json
(ファイルの中身 ["redis-brain.coffee", "shipit.coffee"] -> [] )
$ ./bin/hubot
Hubot> 
Hubot> hubot, ping
Hubot> PONG

IRC に接続する

$ npm install --save hubot-irc

スクリプトをいじる

  • bin/hubot-irc というファイルを新規作成して実行権限を付ける
#!/bin/sh

export PATH="node_modules/.bin:node_modules/hubot/node_modules/.bin:$PATH"

npm install

export HUBOT_IRC_SERVER="irc.example.jp" # サーバ名
export HUBOT_IRC_PORT=6668 # ポート
export HUBOT_IRC_ROOMS="#bot_test" # channel
export HUBOT_IRC_NICK="hubot-udzura" # ニックネーム
export HUBOT_IRC_PASSWORD="XXXXXX" # パスワード
export HUBOT_IRC_USESSL="true" # SSLを使う
export HUBOT_IRC_SERVER_FAKE_SSL="true" # SSLが社内独自なので
export HUBOT_IRC_SEND_NOTICE_MODE="true" # 全発言をNotice
export HUBOT_IRC_DEBUG="true" # デバッグ

exec node_modules/.bin/hubot "$@"

exportとか暗号が出てきた


Windowsの

  • TODO そもそも hubot-irc がインスコできないよ〜
@echo off

SET HUBOT_IRC_SERVER=irc.example.jp
SET HUBOT_IRC_PORT=6668
SET HUBOT_IRC_ROOMS=#bot_test
SET HUBOT_IRC_NICK=hubot-udzura
SET HUBOT_IRC_PASSWORD=XXXXXX
SET HUBOT_IRC_USESSL=true
SET HUBOT_IRC_SERVER_FAKE_SSL=true
SET HUBOT_IRC_SEND_NOTICE_MODE=true
SET HUBOT_IRC_DEBUG=true

npm install && node_modules\.bin\hubot.cmd %*

起動?どう?

./bin/hubot-irc

Bot完成!おめでとう!

未完


Hubot script を書く


CoffeeScript入門

$ coffee
coffee> 1 + 2
coffee> 3 * 9
coffee> Math.power 3, 2

coffee> process.exit()

言語の基本

  • 制御構造
  • データ構造

関数

./sample.coffee というファイルに以下を書く(ここからのサンプルも同様)

power2 = (num) ->
  num * num
console.log power(1234)

$ coffee sample.coffee すると?


分岐(if)

is_odd_even = (num) ->
  if num % 2 == 0
    'even'
  else
    'odd'

console.log '4 is', is_odd_even(4)
console.log '185 is', is_odd_even(185)

繰り返し

for i in [1 .. 10]
  console.log "Hello! #{i}"

1, 2, 3 #=> 整数
1.2, 3.45 #=> 小数
"Coffee" #=> 文字列

(val) -> console.log(val)
#=> 関数、手続き

配列

fib = [1, 1, 2, 3, 5, 8]
branches = ["Tokyo", "Fukuoka", "Kyoto"]
# 繰り返しに便利
for city in branches
  console.log "Welcome to #{city}!!"

連想配列

whereis = {
  "lolipop": "Fukuoka",
  "minne": ["Fukuoka", "Tokyo", "Kyoto"],
  "suzuri": "Tokyo"
}

console.log 'lolipop is located in', whereis["lolipop"]
  • オブジェクト、ハッシュテーブル、辞書、などとも

Hubotスクリプトを書く

$ open scripts/yawaraka.coffee

なかみ

# Description:
#   説明を書く
#
# Commands:
#   コマンドの説明を書く
#   hubot hello, I am <名前> - <名前> に挨拶をする
#
module.exports = (robot) ->
  robot.respond /hello, I am (.*)/i, (msg) ->
    # この中で処理を書く
    name = msg.match[1] # () の中が取れる
    msg.send "Test" # 発言をする
    msg.send "ちょりーっす、 #{name}"
    
  robot.respond /goodbye (.*)/i, (msg) ->
    # いくつでもコマンドを追加できる

試し方

$ ./bin/hubot
Hubot> hubot, hello ...
# ローカルで試してからIRCでも試す!

ほらちゃんにだけツンデレbot

module.exports = (robot) ->
  robot.respond /hello, I am (.*)/i, (msg) ->
    name = msg.match[1]
    if name == "horaotoko"
      msg.send "べ、別にあんたに挨拶なんかしたくないんだからねっ!"
    else
      msg.send "ちょりーっす、 #{name}"

局長にだけテンションが高いbot

module.exports = (robot) ->
  robot.respond /hello, I am (.*)/i, (msg) ->
    name = msg.match[1]
    if name == "kyokutyo"
      for i in [1 .. 3]
        msg.send "ちょりーっす、 #{name}"
    else
      msg.send "ちょりーっす、 #{name}"

うらないボット

random = (n) -> Math.floor(Math.random() * n)

module.exports = (robot) ->
  robot.respond /今日の運勢/i, (msg) ->
    fortunes = [
      '大吉',
      '末吉',
      '大凶'
    ]
    result = fortunes[random(3)]
    msg.send "今日の運勢: #{result}"

他己紹介ボット

module.exports = (robot) ->
  robot.respond /about (.*)/i, (msg) ->
    name = msg.match[1]
    profiles = {
      'udzura' : '基盤ティーム',
      'horaotoko' : '3.5期生',
      'kyokutyo' : '隠れ変態'
    }
    result = profiles[name]
    if result
      msg.send "#{name}さんのプロフィール: #{result}"
    else
      msg.send "#{name}さんのことなんて知りません"

課題

  • (1) 電卓ボット(記号を見て四則計算する)
  • (2) 現在時刻を教えてくれるボット
now = new Date
now.toString()
now.getFullYear(), now.getFullYear(), now.getDay() #...
  • (3) クイズを出すボット

応用編


tiqav 画像検索ボット


Web API

  • 外部サービスと連携する!!
  • あたらしいnpmモジュールを入れる
$ npm install --save request

実装の例

module.exports = (robot) ->
  robot.respond /tiqav (.*)/i, (msg) ->
    request = require('request');
    request.get("http://api.tiqav.com/search.json?q=#{msg.match[1]}", (error, response, body) ->
      if error or response.statusCode != 200
        return msg.send('画像検索に失敗しました...')
      data = JSON.parse(body)[0]
      # robot.logger.info data
      msg.send "画像の様子です: http://img.tiqav.com/#{data.id}.#{data.ext}" )

デプロイをする

  • デプロイ=配備
  • 準備OKにする

デーモン化する必要性

  • 皆さんの使うプログラムは、人間が立ち上げ、人間が終了させる(アプリケーション)
  • 今回は、ボットなので、ずっと立ち上がっていなければいけない
  • ずっと立ち上がっているプログラムをサーバとかデーモンと呼ぶ

社内ツール専用のPaaS - Dokku


セットアップ(簡易)

  • 今回研修用に用意した秘密鍵 を取ってくる(取り扱い注意だよ〜)
  • $ chmod 600 ~/.ssh/id_dsa.pb
  • 疎通確認
    • $ ssh -i ~/.ssh/id_dsa.pb dokku@dokku001.tokyo.lan help
  • .ssh/config を編集
Host dokku001.tokyo.lan
    HostName dokku001.tokyo.lan
    User dokku
    IdentityFile ~/.ssh/id_dsa.pb
  • Procfile を編集
web: bin/hubot-irc -a irc

注:社外向け解説


Gitでデプロイ

  • みんなもちろんGitは入ってるよね???(Macなら最初から入ってます)
$ git init .
$ git add .
$ git commit
$ git remote add dokku dokku@dokku001.tokyo.lan:udzura-hubot
$ git push dokku master

デモ


終わりに


いい話


Enjoy Programming!


Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.