ニンジャー
こっちみてね: https://gist.github.com/mzp/5692680
- 特定キーワードを含むTweetをふぁぼるプログラムを書いてみましょう。
- 単体テストは次の機会にしましょう(主催者都合)
OCamlは型が非常に強力なので、型だけである程度実装をしばることができます。 なので開発する場合は、まずは型から書きはじめることが多いです。 一部では 型駆動開発(TDD) と呼ばれていることが多いです。
例: https://twitter.com/bleis/status/173593199875600384
なので、まずは、 src/bot.mli
に必要と思う型宣言を書いていきます。
(* botに必要な情報を格納する型(詳細は外部には公開しない) *)
type t
(* 初期化 *)
val init : unit -> t
(* キーワードで検索してTweetのリストを返す *)
val search : string -> t -> Twitter.Api_intf.Tweet.t list
(* 対象のTweetをふぁぼる *)
val fav : Twitter.Api_intf.Tweet.t -> t -> unit
コンパイル通したいので、 src/bot.ml
に適当な実装を書きましょう。 assert false
と書けば、 'a
型が作れるので、とりあえずコンパイルを通せます。(余談: AST上ではassert falseと assert condは別の要素らしいです。曰く、最適化をやりやすくするため。ただ実際に確認したわけじゃないので、そんなに信用しないでね)
type t = unit
let init _ = assert false
let search _ = assert false
let fav _ = assert false
あとは、src/ninja.ml
から依存がないとコンパイルされないので、適当に書きます。
type t = Bot.t
コンパイルできることを確認しましょう。
$ make
utopでBotモジュールを動作を確認しましょう。 まずは動作確認に必要な設定を .ocamlinit
に書きます。
(* twitter モジュールのロード *)
#require "twitter";;
(* ビルド結果を置いてあるロード対象に含める *)
#directory "_build/src";;
(* OCamltterのモジュールをロードする *)
#load "minOCamltter.cmo";;
(* Botモジュールをロードする *)
#load "bot.cmo";;
そして utop を起動します。 Botモジュールが扱えるので、いろいろ試してみましょう。
utop # Bot.init;;
- : unit -> Bot.t = <fun>
utop # Bot.init ();;
Exception: Assert_failure ("src/bot.ml", 2, 13).
とりあえず型tはOauthでいいでしょう。 複数持たせたくなったら、レコードにしましょう。 tの中身は外部には公開していないので、わりと気楽に変えれます。
type t =
Twitter.Oauth.t
init
は、前回使ったOAuthの認証コードを流用します。
let init () =
MinOCamltter.get_oauth ()
make
してから動きを確認してみましょう。
utop # Bot.init ();;
- : Bot.t = <abstr>
次は、 search
の実装です。
まずは、ユーティリティ関数を src/base.ml
に移動させます。
let (+>) x f = f x
そして、 .ocamlinit
に追記します。
#require "twitter";;
#directory "_build/src";;
(* 追記 *)
#load "base.cmo";;
#load "minOCamltter.cmo";;
#load "bot.cmo";;
さて、 search
関数を実装します。 ちなみに ~count:count は ~count と略記できます。
let count = 100
let search str oauth =
Twitter.Api11.Search.tweets oauth ~count str
+> (function
| `Ok s -> s#statuses
| `Error _ -> [])
+> List.filter (fun x -> x#retweeted_status = None)
さて make
して、動作を確認しましょう。
utop # let t = Bot.init ();;
val t : Bot.t = <abstr>
utop # Bot.search "#functionalNinja" t;;
- : Twitter.Api_intf.Tweet.t list = [<obj>; <obj>; <obj>]
fav
関数を実装する。
let fav tweet oauth =
Twitter.Api11.Favorites.create oauth tweet#id
+> ignore
実験しておきましょう。
utop # let t = Bot.init ();;
val t : Bot.t = <abstr>
utop # let xs = Bot.search "#functionalNinja" t;;
val xs : Twitter.Api_intf.Tweet.t list = [<obj>; <obj>; <obj>]
utop # Bot.fav (List.hd xs) t;;
- : unit = ()
まずは src/base.ml
にユーティリティ関数を実装します。
let flip f x y = f y x
src/ninja.ml
を実装します。
open Base
let () =
let t =
Bot.init ()
in
Bot.search "#functionalNinja" t
+> List.iter (flip Bot.fav t)
実行してふぁぼられることを確認します。
$ make
$ ./ninja.byte
最後に、無限ループを作ってbotっぽくしましょう。
open Base
let run () =
let t =
Bot.init ()
in
Bot.search "#functionalNinja" t
+> List.iter (flip Bot.fav t)
let () =
while true do
print_endline "wakeup";
run ();
Unix.sleep 60
done
https://github.com/mzp/ninja_bot