ニンジャー
$ sudo aptitude install curl m4 build-essential libcurl4-openssl-dev
$ curl -kL https://raw.github.com/hcarty/ocamlbrew/master/ocamlbrew-install | bash
インストール後に表示されるメッセージに従い、以下の行を~/.bashrcに追記する
source ~/ocamlbrew/ocaml-4.00.1/etc/ocamlbrew.bashrc
Homebrewユーザ
$ brew install opam
MacPortユーザ
$ port install opam
その後、OPAMを初期化します。
$ opam init
- VirtualBox をインストールする
- Ubuntu をインストールする
- "Ubuntu/Debian ユーザ" の節と同じ
以下のものがインストールされている状態にしてください。
$ opam install ocamltter
$ opam install utop
$ opam install oasis
- 静的型付け関数型言語
- 非純粋なので破壊的操作も書ける
- 比較的高速に動作する
ホームディレクトリに以下のような .ocamlinit
を作ります。 4行目は、自分のホームディレクトリに読み替えてください。
let interactive = !Sys.interactive;;
Sys.interactive := false;; (*Pretend to be in non-interactive mode*)
(* 自分のホームディレクトリに書き換える。 ~は使えない:( *)
#use "/home/mzp/.opam/system/lib/toplevel/topfind";;
Sys.interactive := interactive;; (*Return to regular interactive mode*)
ディレクトリを作る。
$ mkdir ninja_bot
$ cd ninja_bot
$ git init
_oasis
というファイルを作る。
直接以下の内容を書いてもいいし、 oasis quickstart
で対話的に作ってもいい。
OASISFormat: 0.3
Name: ninja_bot
Version: 1.00
Synopsis: ninja
Authors: mzp
License: GPL-3.0
Plugins: META (0.3), StdFiles (0.3), DevFiles (0.3)
Executable ninja
Path: src
BuildTools: ocamlbuild
MainIs: ninja.ml
簡単なhello worldを書いてみる。
$ mkdir src
$ echo 'let _ = print_endline "hello, world!"' > src/ninja.ml
ビルドする。
$ oasis setup
$ make
$ ./ninja.byte
hello, world!
この辺で一回コミットしておきましょう。
OCamltterのコードを流用するため、いくつか魔術的なことをします。
$ curl https://raw.github.com/mzp/ninja_bot/master/src/minOCamltter.ml > src/minOCamltter.ml
_oasis
を以下のようにします。
OASISFormat: 0.3
Name: ninja_bot
Version: 1.00
Synopsis: ninja
Authors: mzp
License: GPL-3.0
Plugins: META (0.3), StdFiles (0.3), DevFiles (0.3)
BuildTools: ocamlbuild, camlp4
Executable ninja
Path: src
BuildTools: ocamlbuild
MainIs: ninja.ml
Builddepends: twitter, meta_conv.syntax, ocaml_conv, camlp4
ByteOpt: -w +a -warn-error +a -annot
_tags
の一番下に追記します。
<src/*.ml{,i}>: syntax_camlp4o
ninja.ml
を以下のように変更し、MinOCamltterへの依存関係を追加します。
let _ = MinOCamltter.get_oauth
そしてビルドします。
$ oasis setup
$ make
では対話環境で遊びましょう。
$ rlwrap ocaml # もしくは utop
# #require "twitter";;
# #directory "_build/src";;
# #load "minOCamltter.cmo";;
# let o = MinOCamltter.get_oauth ()
val o : Twitter.Oauth.t =
{Twitter.Oauth.consumer_key = "vS0nKAS6ieWL76zZaQgF4A";
Twitter.Oauth.consumer_secret = "XHa1ZiPcNRsYKw4mdIv8wHUiNulpBFxKT1ntXXuJgo";
Twitter.Oauth.access_token = "-"
Twitter.Oauth.access_token_secret = "-"
Twitter.Oauth.verif = "-"}
(* 発言してみる *)
# Twitter.Api11.Tweets.update o "#functionalNinja hello";;
- : [> `Error of [> `Http of int * string | `Json of Twitter.Api_intf.Json.t Meta_conv.Error.t ]
| `Ok of Twitter.Api_intf.Tweet.t ]
= `Ok <obj>
(* 検索したいな *)
# Twitter.Api11.Search.tweets;;
- : ?count:int ->
?since_id:int64 ->
Twitter.Oauth.t ->
string ->
[> `Error of [> `Http of int * string | `Json of Twitter.Api_intf.Json.t Meta_conv.Error.t ]
| `Ok of Twitter.Api_intf.Search_tweets.t ]
= <fun>
(* oauthと文字列をわたせばいいのか。 たぶん検索キーワードだな *)
# let xs = Twitter.Api11.Search.tweets o "#functionalNinja";;
val xs :
[> `Error of [> `Http of int * string | `Json of Twitter.Api_intf.Json.t Meta_conv.Error.t ]
| `Ok of Twitter.Api_intf.Search_tweets.t ] =
`Ok <obj>
(* `Okの中身を取得する *)
# let ys = match xs with `Ok ok -> ok | _ -> failwith "oops"
val ys : Twitter.Api_intf.Search_tweets.t = <obj>
(* Twitter.Api_inf.Search_tweets.t ってなんだろう *)
# module M = Twitter.Api_intf.Search_tweets;;
module M :
sig
module Search_metadata :
sig
type t =
< completed_in : float; count : int; max_id : int64; next_results :
string; query : string; refresh_url : string; since_id :
int64; unknowns : Twitter.Api_intf.Json.t Twitter.Api_intf.mc_leftovers >
val json_of_t : t -> Twitter.Api_intf.Json.t
val t_of_json : (t, Twitter.Api_intf.Json.t) Meta_conv.Types.Decoder.t
val t_of_json_exn : (t, Twitter.Api_intf.Json.t) Meta_conv.Types.Decoder.t_exn
val ocaml_of_t : t -> Ocaml.t
val t_of_ocaml : (t, Ocaml.t) Meta_conv.Types.Decoder.t
val t_of_ocaml_exn : (t, Ocaml.t) Meta_conv.Types.Decoder.t_exn
end
type t = < statuses : Twitter.Api_intf.Tweet.t list; unknowns : Twitter.Api_intf.Json.t Twitter.Api_intf.mc_leftovers >
val json_of_t : t -> Twitter.Api_intf.Json.t
val t_of_json : (t, Twitter.Api_intf.Json.t) Meta_conv.Types.Decoder.t
val t_of_json_exn : (t, Twitter.Api_intf.Json.t) Meta_conv.Types.Decoder.t_exn
val ocaml_of_t : t -> Ocaml.t
val t_of_ocaml : (t, Ocaml.t) Meta_conv.Types.Decoder.t
val t_of_ocaml_exn : (t, Ocaml.t) Meta_conv.Types.Decoder.t_exn
val format : Format.formatter -> t -> unit
end
(* ふむ, statusesを持つオブジェクトなのか *)
# let zs = ys#statuses;;
val zs : Twitter.Api_intf.Tweet.t list =
[<obj>; <obj>; <obj>; ]
(* Twitter.Api_intf.Tweet.t ってなんだろう *)
# module M = Twitter.Api_intf.Tweet;;
module M :
sig
type t =
< contributors : Twitter.Api_intf.Json.t option; coordinates :
Twitter.Api_intf.Json.t option; created_at : Twitter.Api_intf.Time.t;
entities : Twitter.Api_intf.Entities.t Meta_conv.Open.mc_option; favorited :
bool; geo : Twitter.Api_intf.Json.t option; id : int64; in_reply_to_screen_name :
string option; in_reply_to_status_id : int64 option; in_reply_to_user_id :
int64 option; place : Twitter.Api_intf.Json.t option; possibly_sensitive :
bool Meta_conv.Open.mc_option; retweet_count : int; retweeted :
bool; retweeted_status : t Meta_conv.Open.mc_option; source :
Twitter.Api_intf.Client.t; text : Twitter.Api_intf.Text.t; truncated :
bool; unknowns : Twitter.Api_intf.Json.t Twitter.Api_intf.mc_leftovers; user :
Twitter.Api_intf.User.t >
val json_of_t : t -> Twitter.Api_intf.Json.t
val t_of_json : (t, Twitter.Api_intf.Json.t) Meta_conv.Types.Decoder.t
val t_of_json_exn : (t, Twitter.Api_intf.Json.t) Meta_conv.Types.Decoder.t_exn
val ocaml_of_t : t -> Ocaml_conv.target
val t_of_ocaml : (t, Ocaml_conv.target) Meta_conv.Types.Decoder.t
val t_of_ocaml_exn : (t, Ocaml.t) Meta_conv.Types.Decoder.t_exn
type ts = t list
val json_of_ts : ts -> Twitter.Api_intf.Json.t
val ts_of_json : (ts, Twitter.Api_intf.Json.t) Meta_conv.Types.Decoder.t
val ts_of_json_exn : (ts, Twitter.Api_intf.Json.t) Meta_conv.Types.Decoder.t_exn
val ocaml_of_ts : ts -> Ocaml.t
val ts_of_ocaml : (ts, Ocaml.t) Meta_conv.Types.Decoder.t
val ts_of_ocaml_exn : (ts, Ocaml.t) Meta_conv.Types.Decoder.t_exn
val format : Format.formatter -> t -> unit
val format_ts : Format.formatter -> ts -> unit
end
(* とりあえずtextとかもってるのか。出力してみるか *)
# List.iter (fun z -> print_endline z#text) zs;;
.....
.....
....
(* ふぁぼりたい *)
# Twitter.Api11.Favorites.create;;
- : ?include_entities:bool ->
Twitter.Oauth.t ->
int64 ->
[> `Error of [> `Http of int * string | `Json of Twitter.Api_intf.Json.t Meta_conv.Error.t ]
| `Ok of Twitter.Api_intf.Tweet.t ]
= <fun>
(* ふむIDがいるのか *)
# (List.hd zs)#id;;
- : int64 = 342261499638718464L
(* ふぁぼる *)
# Twitter.Api11.Favorites.create o (List.hd zs)#id;;
- : [> `Error of [> `Http of int * string | `Json of Twitter.Api_intf.Json.t Meta_conv.Error.t ]
| `Ok of Twitter.Api_intf.Tweet.t ]
= `Ok <obj>
だいたい挙動がわかったので、「#functinalNinja」とつぶやいている人をふぁぼりまくってみましょう。
解答例: https://github.com/mzp/ninja_bot