CodeZine(コードジン)

特集ページ一覧

Curl+JRuby+Google App EngineでTwitter風アプリを作る
~GAE編~

最終回

  • ブックマーク
  • LINEで送る
  • このエントリーをはてなブックマークに追加
2009/09/30 14:00
目次

Curl製Twitterクライアントからのつぶやきポスト

 さて、GAEサーバ上のアプリとCurlクライアントはうまく接続できたでしょうか。GAEというクラウド上にアプリ(サーバ)を立てることで、あとは専用のCurlクライアントさえあれば、誰でも接続できるようになります。しかも自分専用、あるいは少人数で使う分にはデータ量も少ないため、無料で使い続けることができます。

 せっかくですのでCurlクライアントを機能拡張してみましょう。前回作った、Curl製Twitterクライアントにはつぶやきをポストする機能がありませんでしたので、追加してみます。

 コードは次のようになります。フォームを作って入力された値をサーバにポストするコードは連載第2回 リッチクライアントCRUDアプリを作成するで作ったものを流用しました。HttpFormを使う事で入力したつぶやきを簡単にサーバにポストできます。

{curl 7.0 applet}
{curl-file-attributes character-encoding = "utf8"}

{import * from CURL.IO.JSON}

{let server_url = "http://<%= request.host_with_port() %>/"}
{let json_data_path = "statuses/friends_timeline.json"}
{let login = "neko"}
{let password = "pass"}
{set-http-authentication {url server_url}, login, password}


{let twitters: RecordSet =
    {RecordSet
        {RecordFields
            {RecordField "screen_name", caption = "", domain = String},
            {RecordField "text", caption = "", domain = String},
            {RecordField "icon", caption = "", domain = String}
        }
    }
}

{define-proc public {add-rec
                        text: String,
                        screen_name: String,
                        profile_image_url: String
                    }: void
    let new-rec: Record = {twitters.new-record}
    {new-rec.set "text", text}
    {new-rec.set "screen_name", screen_name}
    {new-rec.set "icon", profile_image_url}
    {twitters.append new-rec}
}


{define-proc public {get-time-line}:void
    {let twittersJsonValue: JsonValue =
        {JsonValue-parse
            {url server_url & json_data_path}
        }
    }
    {twitters.delete-all}
    {for twitter: JsonObject in twittersJsonValue do
        let found?: bool = false
        let text: String = {String}
        let screen_name: String = {String}
        let profile_image_url: String = {String}

        let user: JsonObject = {twitter.get "user"}
        set (text, found?) = {twitter.get-if-exists "text"}
        set (screen_name, found?) = {user.get-if-exists "screen_name"}
        set (profile_image_url, found?) = {user.get-if-exists "profile_image_url"}
        {if found? then
            {add-rec text, screen_name, profile_image_url}
        }
    }
}

{define-class public open IconCell
  {inherits StandardRecordGridCell}
  
  field private icon:Frame = 
      {Frame width={make-elastic}, height={make-elastic}}

  {constructor public {default}
    {construct-super}
    set self.height = 48px
    {self.add-internal self.icon}
    set self.cells-take-focus? = self.can-update?
  }
  
  {method public open {refresh-data}:void
    let (data:String, valid?:bool) = {self.get-formatted-data}
    {try
        set self.icon.background = {url data}
     catch e:Exception do
        {unset self.icon.background}
        {output "icon get error " & e.message & " " & data }        
    }
  }
}

{let form_text:TextField = {TextField name = "status[text]", width = 17.5cm, height = 0.8cm}}
{let post_form:HttpForm =
    {HttpForm
        {url server_url & "statuses.json"},
        method = HttpRequestMethod.post,
        encoding = HttpFormData.urlencoded-mime-type,
        default-character-encoding = "utf8",
        
        {spaced-vbox
            width = 20cm,
            margin = 5pt,
            "いまなにしてる?",
            {HBox
                spacing = 0.3cm,
                form_text,
                {CommandButton
                    horigin="right",
                    label = "つぶやく",
                    {on Action do
                        {try
                            {with-open-streams response:#TextInputStream =
                                {post_form.submit-open
                                    character-encoding = {get-character-encoding-by-name "utf8"}}
                            do
                                {set form_text.value = ""}
                            }
                        catch e:Exception do
                            {popup-message "Error :" & e.message}
                        }
                        {get-time-line}
                    }
                }   
            }
        }
    }
}

{let time_line: RecordGrid =
    {RecordGrid
        width=20cm,
        height=12.7cm,
        editable? = false,
        record-source = twitters,
        {RecordGridColumn  "icon", width = 48px, 
                column-resizable? = false, cell-spec = IconCell},
        {RecordGridColumn  width = 3cm, "screen_name"},
        {RecordGridColumn  width = 15cm, "text"}
    }
}

{get-time-line}
{value
    {spaced-vbox
        post_form,
        time_line
    }
}

まとめ

 本連載ではRuby on RailsとCurlをかんたんに接続できることについて、実際のコードを交えながら解説してきました。第3回ではRailsの特徴であるScaffoldを使ってCurlソースを生成する方法も紹介しました。

 連載後半では、今話題のクラウド(GAE)上のサーバにRailsを配置し、クライアントCurlと連携する方法について説明しました。開発ライセンスのためやや煩雑な部分もありましたが、正規ライセンスであればこういった問題も解消され、手軽にクラウドを活用できることがご理解いただけたかと思います。将来的には自社サーバではなくクラウドを軸にしたクライアント配布体制の構築も視野に入ってきます。

 業務の効率化を高めるためにもユーザーインターフェースの重要性は増すばかりです。クライアントにCurlを使い、環境構築がすぐにできるRailsをサーバーサイドに使うことで、こういった要望にも応えられるシステムを手軽に構築することも可能です。Curl + Ruby on Rails、ぜひ試してみてください。



  • ブックマーク
  • LINEで送る
  • このエントリーをはてなブックマークに追加

著者プロフィール

  • 吉田裕美(ヨシダユウミ)

    有限会社 EY-Office 取締役 CADのベンチャー企業でCADのコア部分や図面管理システムなどの開発に従事した後、独立しJava,Ruby,PerlでWebアプリを中心に開発してきた。現在は殆どの開発はRuby on Rails。 ここ数年はソフトウェアエンジニアの教育に興味をもち、従来の...

バックナンバー

連載:Ruby on Rails + Curl
All contents copyright © 2005-2020 Shoeisha Co., Ltd. All rights reserved. ver.1.5