「モダンPerl入門」の入門
   Songhee Han
   Kazuya Shono
自己紹介
                                              • 韓 松熙(song)
                                                      • 韓国出身のPerlエンジニア
                                                      • Perl歴4年目のnewbieです!
                                              • 荘野 和也(miniturbo)
                                                      • SBMカウンタの開発者
                                                      • Perl歴半年のnewbieです!




9/17/2009   Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved.       2
サービス紹介
      • スクールガーディアン
            • 世界初の学校裏サイト・ネットいじめ対策サービス

            • インターネット上からネットいじめに関する書き込みなどを収集
              し学校に対策を提案するサービス

            • 元々手動でこなしていたサービスを自動化することに




9/17/2009          Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved.   3
プロジェクトの紹介
      • スクールガーディアンツール
            • 掲示板やプロフなどから特定の学校の学校裏サイトの情報を
              収集するツールです

            • 学校の先生が内容を確認できるように、サイト画面全体のスク
              リーンショットや投稿データを取得できます




9/17/2009          Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved.   4
モダンPerl との出会い
            2008年9月   2009年1月              2009年4月                    2009年7月           2009年9月



                      モダンPerl                    Catalyst5.8                         YAPC::Asia
                      入門発売                        リリース                                モダンPerl
                                                                                     の入門の入門
             モダン
            Perl界隈                             JPAセミナー#1
                                              モダンPerlの現場




                                                 Catalyst
            プロジェクト
                                企画             5.7ベースで                       Catalyst 5.8で開発
            スケジュール                             調査/設計




9/17/2009               Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved.                5
Catalyst & API 設計
Presented by Songhee Han
アプリケーションの構成




9/17/2009     Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved.   7
アプリケーションの分割
      • Catalyst
            • SchoolG::Client                 (エンドユーザ機能)
            • SchoolG::Work                   (管理者機能)
      • ジョブ
            • SchoolG::Batch                  ( TheSchwartz Job )
      • 共通
            • SchoolG                         (共有モジュール/API)



9/17/2009               Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved.   8
フォルダ構造
            app_root/
             SchoolG-Client/
              lib/
              root/                                                          CatalystApp
              script/
              template/
             SchoolG-Work/
              lib/
              root/                                                          CatalystApp
              script/
              template/
             SchoolG-Batch/
              lib/
              script/                                                            バッチ
              t/
             SchoolG/
              config/
              extlib/
              lib/                                                             共通部分
              script/
              t/
              template/




9/17/2009                      Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved.   9
実装




9/17/2009   Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved.   10
使いたかった技術
      •     Catalyst 5.8 + Moose
      •     API
      •     Web::Scraper
      •     TheSchwartz
      •     local::lib




9/17/2009             Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved.   11
Catalyst 5.8
      • local::libで運用
            • 開発環境でCatalyst5.7と5.8を共存させたかった


      • Catalyst::UpgradingのPODを参考にした
            • Catalystをextendsしていた
            • Pluginは極力使わないようにした




9/17/2009          Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved.   12
最小限のPlugin
      • ログイン関連
            • Catalyst::Plugin::Authentication
            • Catalyst::Plugin::Authorization::Roles
      • Session関連
            • Catalyst::Plugin::Session
            • Catalyst::Plugin::Session::Store::Memcached
            • Catalyst::Plugin::Session::State::Cookie
      • その他
            • Catalyst::Plugin::FillInForm




9/17/2009                 Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved.   13
API化までの試行錯誤




9/17/2009     Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved.   14
APIへの第一歩
      • モダンPerl入門
            これをより汎用的にして他のスクリプトからも呼べるようにするには、$c->model()
            が呼び出された時にCatalyst依存のMyApp::Model::Userではなく単体で
            動作するオブジェクトを返すようにしてしまえばいいのです。


                                                                        「モダンPerl入門」 より引用




9/17/2009               Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved.         15
Modelの分離
      • Controllerにロジックを書いていた時代
            • Controllerの見通しが悪くなっていった
      • Controllerからロジックを分離する
            • ロジックはModelに切り出した
            • 但し、ModelはCatalystに依存したまま
      • Modelからロジックを分離する
            • Model::Adaptorを利用してModelとロジックをマ
              ッピングさせた



9/17/2009           Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved.   16
Modelの分離
      • Model::Adaptorで一つ一つマッピングするの
        は意外と大変
      • Model::MultiAdaptorでつなぐようにした




9/17/2009     Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved.   17
Modelの分離(API)
            package SchoolG::Work::Model::API::Logic;

            use strict;
            use warnings;
            use parent 'Catalyst::Model::MultiAdaptor';

            1;




9/17/2009               Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved.   18
Modelの分離(YAML)
            Model::API::Logic:
              package: 'SchoolG::API::Logic'
              lifecycle: Singleton
              except:
                - 'Plugin::Filter'




9/17/2009               Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved.   19
Modelの分離はいったん完成
             でも画面を書いていくうちに、
             APIの中身がごちゃごちゃに…
                   これでAPI?
            分離するだけは何かが足りない…



9/17/2009       Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved.   20
API?
      • Wikipedia
            Application programming interface (API) is an interface in computer
            science that defines the ways by which an application program may request
            services from libraries and/or operating systems

            The API initialism may sometimes be used as a reference, not only to the
            full interface, but also to one function, or even a set of multiple APIs
            provided by an organization. Thus, the scope of meaning is usually
            determined by the person or document that
            communicates the information.
                                                                                            Wikipediaより引用




9/17/2009                      Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved.                   21
なら、APIは自分たちなりに
                  定義して
              決めたらいいの?



9/17/2009      Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved.   22
社内での議論(1)
      • 分離したロジックはなぜごちゃごちゃになっている?
            • APIモジュール群がうまく分類されていなくて、どこにどの処
              理が書いてあるのか見失いやすくなった
            • 結局ロジックを書く場所が変わっただけ?


      • 分離したロジックを整理していかなければいけない




9/17/2009          Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved.   23
社内での議論(1)
      • WebアプリケーションはDB処理が多い

      • 至るところで繰り返し呼び出されるDB処理(CRUD処
        理)と、一連の処理の流れ(ビジネスロジック)を整理す
        ることでAPIの見通しがよくなるのではないかと考えた

      • それぞれどこに、どのように書くべきか?




9/17/2009    Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved.   24
社内での議論(2)
            A案:API≒CRUD処理派

                 SchoolG               API                                CRUD処理


                                       Logic                              ビジネスロジック


                                       DBIC                               DBICの接続



            B案:API≒ビジネスロジック派

                 SchoolG               DBIC                               CRUD処理(DBICの接続)


                                       API                                ビジネスロジック




9/17/2009                  Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved.       25
社内での議論(3)
      • APIは隠ぺい化された機能

      • CRUD処理も ビジネスロジックも、隠蔽化さ
        れた機能として(どのコンテキストからも呼び
        出せるように)実装していきたい

      • つまりCRUD処理もビジネスロジックもAPI!



9/17/2009    Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved.   26
社内での議論(4)


                 SchoolG          API                 Data                   CRUD処理


            最終
            案
                                                     Logic                   ビジネスロジック




9/17/2009            Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved.         27
実装してフィードバック、
            また修正してフィードバック、
                  …
              出来上がってきた!



9/17/2009      Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved.   28
API
                                                                              API::Data
      APIの構成                                                                  API::Logic
                                                                              API

      • API::Data
         • DBへの接続
         • SQLの発行
      • API::Logic
         • ビジネスロジック
         • Dataを呼び出してデータを取得・整形
      • API
      • API::Jobqueue
      • API::Plugin




9/17/2009       Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved.                 29
API
                                                                          API::Data
                                                                          API::Logic
                                                                          API




                  API::Data




9/17/2009   Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved.                 30
API
                                                                                API::Data

      API::Data                                                                 API::Logic
                                                                                API



        • 役割
            • DBへの接続とSQLの発行を行う
            • 子クラスにCRUD処理を記述する
        • 機能
            • レプリケーション管理
            • コネクションプーリング
            • 返値のデータ形式の統一
        • 実装のポイント
            • 子クラスはテーブル毎に作るようにした



9/17/2009         Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved.                 31
API::DataとDBICのつなぎ方
      package SchoolG::API::Data;
      has _master_schema => (
          is       => 'rw',
          required => 1,
          isa      => 'DBIx::Class::Schema',
          default =>
             sub {
               # Singleton化した
               SchoolG::DBIC::Singleton->instance->_master
             }
      );
      sub master {
          my ( $self, $table_name ) = @_;
          $table_name ||= $self->_table_name;
          return $self->_master_schema
                      ->resultset($table_name);
      }

9/17/2009            Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved.   32
API::Dataのデータの返し方
      package SchoolG::API::Data;
      # DBICのsearchは直接利用せずに親クラス(このクラス)のsearchを利用する
      sub search {
          my ( $self, $args ) = @_;
          my $conditions = $args->{conditions};
          my $options    = $args->{options};
          # searchの場合はslaveのschemaを利用
          my $resultset =
            $self->slave->search( $conditions, $options );
          # DBICのオブジェクトではなくHashRefかArrayRefで返すようにした
          $resultset->result_class
               ('DBIx::Class::ResultClass::HashRefInflator');
          return
            exists $options->{page} && exists $options->{rows}
            ? {
                 result => [ $resultset->all ],
                 pager => $resultset->pager
              }
            : [ $resultset->all ];
      }
9/17/2009             Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved.   33
API
                                                                          API::Data
                                                                          API::Logic
                                                                          API




                 API::Logic




9/17/2009   Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved.                 34
API
                                                                                    API::Data

      API::Logic                                                                    API::Logic
                                                                                    API



      • 役割
            • 子クラスにビジネスロジックを記述する
              • Catalyst のComponentにはビジネスロジックは極力書かない
              • CRUD処理はAPI::Dataに記述し、API::Logicから呼び出す
      • API::Logicの子クラスで行う処理の流れ
            • Validation処理
            • 一連のCRUD処理(トランザクション管理も含む)
            • CRUD処理結果の加工
      • 実装のポイント
            • Catalystアプリケーション及びジョブの両方からAPI::Logicを呼び出
              せるようにした




9/17/2009             Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved.                 35
package SchoolG::API::Logic::ManageStaff;
      extends 'SchoolG::API::Logic';
      sub create {
          my ( $self, $args ) = @_;

            my $created_by = delete $args->{created_by};
            my $validation = $self->validate(
                $args->{columns}, 'create' );
            return $validation unless $validation->{success};

            delete $args->{columns}->{cancel};
            delete $args->{columns}->{submit};
            $args->{columns}->{staff_created_by} = $created_by;
            $args->{columns}->{staff_updated_by} = $created_by;

            my $txn = sub {
                $self->data('MasterStaff')->create($args);
            };
            $self->txn($txn);
      }

9/17/2009              Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved.   36
API
                                                                          API::Data
                                                                          API::Logic
                                                                          API




                                API




9/17/2009   Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved.                 37
API
                                                                                    API::Data
                                                                                    API::Logic

      API                                                                           API



      • 役割
            • API::DataとAPI::Logicの親クラス
      • 機能
            • API::DataとAPI::Logicのアクセサの提供
            • API::DataとAPI::Logicで共通メソッドの提供
      • 実装のポイント
            • ジョブからAPIを経由してAPI::DataとAPI::Logic両方を簡
              単に呼べるようにした




9/17/2009             Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved.                 38
API
                                                                                          API::Data

      APIの最終形                                                                             API::Logic
                                                                                          API



      Catalyst からも ジョブからもAPIを呼べる

                                                    API

                                                   Data
            Catalyst

              Job                                                                   DB
                                                  Logic




9/17/2009              Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved.                      39
実装:Catalystからの呼び出し




9/17/2009    Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved.   40
package SchoolG::Work::Controller::Manage::Staff::Create;

      sub execute : Local {
          my ( $self, $c ) = @_;

            my $result = $c->model('API::Logic::ManageStaff')
                ->create(
                {
                    columns    => $c->req->params,
                    created_by => $c->user->staff_seq
                }
            );

            $c->res->redirect( $c->uri_for('/manage/staff') );
      }




9/17/2009              Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved.   41
package SchoolG::API::Logic::ManageStaff;
      extends 'SchoolG::API::Logic';
      sub create {
          my ( $self, $args ) = @_;

            my $created_by = delete $args->{created_by};
            my $validation = $self->validate(
                $args->{columns}, 'create' );
            return $validation unless $validation->{success};

            delete $args->{columns}->{cancel};
            delete $args->{columns}->{submit};
            $args->{columns}->{staff_created_by} = $created_by;
            $args->{columns}->{staff_updated_by} = $created_by;

            my $txn = sub {
                $self->data('MasterStaff')->create($args);
            };
            $self->txn($txn);
      }

9/17/2009              Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved.   42
package SchoolG::API::Data::MasterStaff;

      use Moose;
      extends 'SchoolG::API::Data';

      sub BUILD {
          my $self = shift;
          $self->_table_name('MasterStaff');
          $self->_table_prefix('staff');
          $self->_default_conditions( {
            staff_delete => 0,
            staff_seq => { '>' => 1 }
          } );
          $self->_default_options(
            { order_by => [qw/staff_office/] }
          );
      }




9/17/2009            Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved.   43
package SchoolG::API::Data;
      use Moose;

      has _table_prefix => (
          is => 'rw',
          isa => 'Str',
      );

      sub create {
          my ( $self, $args ) = @_;

            my $prefix = $self->_table_prefix;
            my $columns = $args->{columns};
            my $result = $self->master->create($columns);
            return $result ?
              { success => 1 } : { success => 0 };
      }



9/17/2009              Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved.   44
実装:ジョブからの呼び出し




9/17/2009   Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved.   45
package SchoolG::Batch::Job::CountTask;

      sub work {
          my ( $class, $job ) = @_;

            my $api    = SchoolG::API->new();

            my $result = $api->logic('CountTask')
                           ->get_profile_count( $job->arg );

            $job->completed;
      }




9/17/2009              Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved.   46
package SchoolG::API::Logic::CountTask;
      extends 'SchoolG::API::Logic';

      sub get_profile_count {
          my ( $self, $args ) = @_;

            undef my $counts;
            return $counts if $args->{operation} == 3;

            $counts->{count_profile} =
              $self->data('DataProfile')->count_for_count_task(
                {
                    school_seq => $args->{school_seq},
                    status     => 0
                }
            );

            return $counts;
      }




9/17/2009               Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved.   47
package SchoolG::API::Data::DataProfile;

      use Moose;
      extends 'SchoolG::API::Data';

      sub count_for_count_task {
          my ( $self, $args ) = @_;

            my $conditions;
            $conditions->{profile_school_seq} =
              $args->{school_seq};

            $self->SUPER::count(
              { conditions => $conditions }
            );
      }




9/17/2009              Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved.   48
APIの設計・リファクタを振りかえって




9/17/2009   Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved.   49
APIを設計しながら
      • 機能単位の分割するのが難しかった
      • ルールをすべて守るのが難しかった
            • リファクタリング5回くらい!!!
      • まとまってきれいにかけた




9/17/2009         Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved.   50
まとめ
      • API設計
            • CRUD処理はAPI::Dataに、ビジネスロジックは
              API::Logicに分けることで見通しがよくなった
            • Catalystからもジョブからも呼べるような構成となった
      • Catalyst 5.8
            • 今回CatalystのComponentではMooseの機能は使って
              いない
            • Mooseの機能をCatalyst内で使わない限りは5.7とほとん
              ど同じように書くことができた




9/17/2009              Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved.   51
今後に向けて
      • 別のプロジェクトでも通用するのか試してみたい
      • ガイアックスでは今回APIをこのように考えて実装し
        てみました
      • 「APIってこんな考え方もあるよ」などの意見があれ
        ば是非教えて下さい
      • パフォーマンス向上などこれからも新しいことに挑戦
        していきます




9/17/2009    Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved.   52
参考にさせていただきました
      • Catalyst::Upgrading
            • http://search.cpan.org/~flora/Catalyst-Runtime-
              5.80011/lib/Catalyst/Upgrading.pod
      • モダンPerlの世界へようこそ - 第6回
        Catalyst::Upgrading:検証はお早めに
            • http://gihyo.jp/dev/serial/01/modern-perl/0006
      • Moosification: Catalyst 5.8に移行した際にちょっと
        気づいた事。
            • http://mt.endeworks.jp/d-6/2009/05/moosification-catalyst-
              58.html




9/17/2009                   Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved.   53
まだ終わってないです!
            Perlじゃないって言われても
                 気にしません!




9/17/2009      Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved.   54
おまけ:Canvasでスクリーンショット
   Presented by Kazuya Shono
スクリーンショットの要件
      • 学校裏サイトのスクリーンショッ
        トが欲しかった
      • サムネイルではなく、ページ全
        体のスクリーンショットが必要
        だった
      • 長いページでもページ全体を
        撮る必要があった

      • 実装にあたって、2つのアプ
        ローチがありました




9/17/2009      Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved.   56
アプローチ
      • Xvfb案
            • Xvfb(Xの仮想環境)にブラウザを立ち上げて、Xvfb
              自体をキャプチャ!
      • Canvas案
            • FirefoxのCanvas要素でWebページをキャプチャ!

      • まずはXvfbの実装から試してみることに!!




9/17/2009           Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved.   57
案①
      • Xvfbでキャプチャ!
            • XvfbにFirefoxを起動し、                                                   取得
              X Window Dumpで                                                      範囲
              ファイルとして保存する

      • …この案では、 Xの仮
      想環境の高さまでしかペ
      ージのキャプチャが取得
      できない!




9/17/2009            Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved.    58
案②
      • Canvasでキャプチャ!
            • Firefoxで、Canvas要素
              へWebサイトを描画し、
              それをファイルとして保
              存する
                                                                                  取得
                                                                                  範囲
            • …コンテンツ量の多いサ
              イトで、メモリ不足になり、
              キャプチャが取得できな
              いときがある!




9/17/2009            Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved.    59
案③
      • Canvasでキャプチャ!
                                                                                 取得
            • Canvas要素でスクリーン                                                     範囲
              ショットを取得
            • 工夫として、撮影領域の
              高さを固定し、分割して
              キャプチャするようにした

            • →高さを固定できるので、                                                       取得
              1回のキャプチャのメモリ                                                       範囲
              使用量の上限を固定でき
              る




9/17/2009           Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved.    60
結果…
      • Canvas案を採用しました!
            • この案をもとに、開いたページのスクリーンショットを
              撮るFirefoxのアドオンを制作しました

            • Canvasでスクリーンショットを取得
            • XPCOMでディスクへファイルとして書き込み




9/17/2009         Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved.   61
実装




9/17/2009   Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved.   62
CanvasでWebページを描画
            • canvas要素を作成し、Webページを描画する
            • toDataURL()を用いて描画したデータの
              data:URLを取得する



      var canvas = window.document.createElement(‘canvas’);
      var ctx = canvas.getContext('2d');

      // Webページの描画
      ctx.drawWindow(window, X開始点, Y開始点,
           X終了点, Y終了点, ‘rgb(0,0,0)’);
      ctx.restore();

      // 描画したデータをBASE64エンコードしたdata:URLを取得
      var url = canvas.toDataURL(‘image/png’);


9/17/2009             Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved.   63
ファイルの保存
            • nsIURIオブジェクトの生成
            • nsILocalFileでファイルオブジェクトを生成
            • nsIWebBrowserPersistでファイルに保存する
      var Cc = Components.classes;
      var Ci = Components.interfaces;

      // URIオブジェクトの生成
      var URI = Cc['@mozilla.org/network/io-service;1']
        .getService(Ci.nsIIOService).newURI(url, null, null);

      // ファイルオブジェクトの生成
      var file = Cc["@mozilla.org/file/local;1"]
        .createInstance(Ci.nsILocalFile);
      file.initWithPath(保存先のファイルパス);

      // ファイルに保存
      var wbp = Cc['@mozilla.org/embedding/browser/nsWebBrowserPersist;1']
        .createInstance(Ci.nsIWebBrowserPersist);
      wbp.saveURI(url, null, null, null, null, file);

9/17/2009               Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved.   64
分割キャプチャ
              以上の実装を、ブラウザの高さで
              分割して、繰り返しキャプチャするようにした
      var     max = window.document.height;
      var     width = window.outerWidth;
      var     fromY = window.scrollY;
      var     height = window.innerHeight;

      while (fromY <= max) {
        var toY = (fromY + height) > max ?
          max : fromY + height;

            // キャプチャするメソッド
            capture(window, width, fromY, toY);
            if (fromY + height > max) break;

            fromY = toY;
      }
9/17/2009                  Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved.   65
実演
      • デモをご覧ください




9/17/2009     Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved.   66
参考にさせていただきました
      • SCRAPBLOG : canvas要素によるWebペー
        ジのスクリーンショット保存機能
            • http://www.xuldev.org/blog/?p=37
      • File I/O – MDC
            • https://developer.mozilla.org/ja/Code_snippets/File_I
              %2F%2FO




9/17/2009                Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved.   67
最後に告知




9/17/2009   Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved.   68
仲間募集中!
      • ガイアックスでは、小さなチームで新しい技術を積極的に取り入れながら
        自社プロダクトを開発しています。
      • 一緒にチャレンジし、成長していく意欲のある開発者を募集中です。




9/17/2009       Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved.   69

More Related Content

PDF
Red5とFlexで作るmixiアプリ「ビデオチャット」事例紹介
PDF
OSC2011 Tokyo/Spring 『Red5とFlexで「簡易電子会議室システム」を作ってみよう!』
PDF
OSC福岡 20111203
PDF
マイクロサービス時代の動画配信基Ruby×go=∞
PPTX
Anyca におけるUIフレームワークと スマホによるドア操作の仕組み
PPTX
GREE-Fsite
PDF
グリーにおけるスマホアプリ開発~HTML5編
PDF
チラシルiOSでの広告枠開発
Red5とFlexで作るmixiアプリ「ビデオチャット」事例紹介
OSC2011 Tokyo/Spring 『Red5とFlexで「簡易電子会議室システム」を作ってみよう!』
OSC福岡 20111203
マイクロサービス時代の動画配信基Ruby×go=∞
Anyca におけるUIフレームワークと スマホによるドア操作の仕組み
GREE-Fsite
グリーにおけるスマホアプリ開発~HTML5編
チラシルiOSでの広告枠開発

Viewers also liked (6)

PDF
Codificação lossy do JPEG
PDF
KEY
Kansai.pmと僕 - Kansaipm#14
PDF
LWP + libcurl
PDF
Perl5環境構築 Kansaipm#13
KEY
PHPerのためのPerl入門@ Kansai.pm#12
Codificação lossy do JPEG
Kansai.pmと僕 - Kansaipm#14
LWP + libcurl
Perl5環境構築 Kansaipm#13
PHPerのためのPerl入門@ Kansai.pm#12
Ad

Similar to 「モダンPerl入門」の入門 (20)

PDF
Pylons ユーザのための Pyramid 移行ガイド
PPTX
AndApp開発における全て #denatechcon
PPTX
ML Ops NYC 19 & Strata Data Conference 2019 NewYork 注目セッションまとめ
PDF
Ahead-of-Time Compilation with JDK 9 [Java Day Tokyo 2017 D1-A1]
PPT
ネイティブ機能を利用する Webアプリの実例 ~PhoneGap×Rails~
PPTX
Spring tools4
PPTX
いまさら聞けない!HTML5超入門
PDF
CakePHPとYii_エンジニア勉強会20130820
KEY
PhoneGapの始め方
PDF
MuleアプリケーションのCI/CD
PDF
Rubyプログラミング教育に対する取り組みと事例紹介
PDF
Spring Boot on Kubernetes : Yahoo!ズバトク事例 #jjug_ccc
PDF
【アシアル塾】PHPオブジェクト指向再入門・第四回デザインパターンに学ぶクラス設計
PDF
OCI serverless introduction
PDF
GitHubのリポジトリ(32個)を 覗いてみよう。 ただし、READMEだけね
PDF
CloudHubのログバックアップについて
PPTX
技術選択とアーキテクトの役割
PPTX
EclipseCon Europe 2019 modeling report
PDF
PPTX
Oracle APEXユーザー会の紹介
Pylons ユーザのための Pyramid 移行ガイド
AndApp開発における全て #denatechcon
ML Ops NYC 19 & Strata Data Conference 2019 NewYork 注目セッションまとめ
Ahead-of-Time Compilation with JDK 9 [Java Day Tokyo 2017 D1-A1]
ネイティブ機能を利用する Webアプリの実例 ~PhoneGap×Rails~
Spring tools4
いまさら聞けない!HTML5超入門
CakePHPとYii_エンジニア勉強会20130820
PhoneGapの始め方
MuleアプリケーションのCI/CD
Rubyプログラミング教育に対する取り組みと事例紹介
Spring Boot on Kubernetes : Yahoo!ズバトク事例 #jjug_ccc
【アシアル塾】PHPオブジェクト指向再入門・第四回デザインパターンに学ぶクラス設計
OCI serverless introduction
GitHubのリポジトリ(32個)を 覗いてみよう。 ただし、READMEだけね
CloudHubのログバックアップについて
技術選択とアーキテクトの役割
EclipseCon Europe 2019 modeling report
Oracle APEXユーザー会の紹介
Ad

Recently uploaded (7)

PDF
ココロ分解帳|感情をやさしく分解し自分と他者を理解するためのモバイルノートアプリ
PDF
翔泳社 「C++ ゼロからはじめるプログラミング」対応 C++学習教材(三谷純)
PPTX
生成AIとモデルベース開発:実はとても相性が良いことを説明します。まあそうだろうなと思われる方はご覧ください。
PDF
Working as an OSS Developer at Ruby Association Activity Report 2025
PDF
AIシステムのセキュリティ:脅威となりつつあるAIの現状と課題 [English] Security of AI Systems: The Current...
PDF
20250826_Devinで切り拓く沖縄ITの未来_AI駆動開発勉強会 沖縄支部 第2回
ココロ分解帳|感情をやさしく分解し自分と他者を理解するためのモバイルノートアプリ
翔泳社 「C++ ゼロからはじめるプログラミング」対応 C++学習教材(三谷純)
生成AIとモデルベース開発:実はとても相性が良いことを説明します。まあそうだろうなと思われる方はご覧ください。
Working as an OSS Developer at Ruby Association Activity Report 2025
AIシステムのセキュリティ:脅威となりつつあるAIの現状と課題 [English] Security of AI Systems: The Current...
20250826_Devinで切り拓く沖縄ITの未来_AI駆動開発勉強会 沖縄支部 第2回

「モダンPerl入門」の入門

  • 1. 「モダンPerl入門」の入門 Songhee Han Kazuya Shono
  • 2. 自己紹介 • 韓 松熙(song) • 韓国出身のPerlエンジニア • Perl歴4年目のnewbieです! • 荘野 和也(miniturbo) • SBMカウンタの開発者 • Perl歴半年のnewbieです! 9/17/2009 Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved. 2
  • 3. サービス紹介 • スクールガーディアン • 世界初の学校裏サイト・ネットいじめ対策サービス • インターネット上からネットいじめに関する書き込みなどを収集 し学校に対策を提案するサービス • 元々手動でこなしていたサービスを自動化することに 9/17/2009 Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved. 3
  • 4. プロジェクトの紹介 • スクールガーディアンツール • 掲示板やプロフなどから特定の学校の学校裏サイトの情報を 収集するツールです • 学校の先生が内容を確認できるように、サイト画面全体のスク リーンショットや投稿データを取得できます 9/17/2009 Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved. 4
  • 5. モダンPerl との出会い 2008年9月 2009年1月 2009年4月 2009年7月 2009年9月 モダンPerl Catalyst5.8 YAPC::Asia 入門発売 リリース モダンPerl の入門の入門 モダン Perl界隈 JPAセミナー#1 モダンPerlの現場 Catalyst プロジェクト 企画 5.7ベースで Catalyst 5.8で開発 スケジュール 調査/設計 9/17/2009 Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved. 5
  • 6. Catalyst & API 設計 Presented by Songhee Han
  • 7. アプリケーションの構成 9/17/2009 Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved. 7
  • 8. アプリケーションの分割 • Catalyst • SchoolG::Client (エンドユーザ機能) • SchoolG::Work (管理者機能) • ジョブ • SchoolG::Batch ( TheSchwartz Job ) • 共通 • SchoolG (共有モジュール/API) 9/17/2009 Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved. 8
  • 9. フォルダ構造 app_root/ SchoolG-Client/ lib/ root/ CatalystApp script/ template/ SchoolG-Work/ lib/ root/ CatalystApp script/ template/ SchoolG-Batch/ lib/ script/ バッチ t/ SchoolG/ config/ extlib/ lib/ 共通部分 script/ t/ template/ 9/17/2009 Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved. 9
  • 10. 実装 9/17/2009 Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved. 10
  • 11. 使いたかった技術 • Catalyst 5.8 + Moose • API • Web::Scraper • TheSchwartz • local::lib 9/17/2009 Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved. 11
  • 12. Catalyst 5.8 • local::libで運用 • 開発環境でCatalyst5.7と5.8を共存させたかった • Catalyst::UpgradingのPODを参考にした • Catalystをextendsしていた • Pluginは極力使わないようにした 9/17/2009 Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved. 12
  • 13. 最小限のPlugin • ログイン関連 • Catalyst::Plugin::Authentication • Catalyst::Plugin::Authorization::Roles • Session関連 • Catalyst::Plugin::Session • Catalyst::Plugin::Session::Store::Memcached • Catalyst::Plugin::Session::State::Cookie • その他 • Catalyst::Plugin::FillInForm 9/17/2009 Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved. 13
  • 14. API化までの試行錯誤 9/17/2009 Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved. 14
  • 15. APIへの第一歩 • モダンPerl入門 これをより汎用的にして他のスクリプトからも呼べるようにするには、$c->model() が呼び出された時にCatalyst依存のMyApp::Model::Userではなく単体で 動作するオブジェクトを返すようにしてしまえばいいのです。 「モダンPerl入門」 より引用 9/17/2009 Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved. 15
  • 16. Modelの分離 • Controllerにロジックを書いていた時代 • Controllerの見通しが悪くなっていった • Controllerからロジックを分離する • ロジックはModelに切り出した • 但し、ModelはCatalystに依存したまま • Modelからロジックを分離する • Model::Adaptorを利用してModelとロジックをマ ッピングさせた 9/17/2009 Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved. 16
  • 17. Modelの分離 • Model::Adaptorで一つ一つマッピングするの は意外と大変 • Model::MultiAdaptorでつなぐようにした 9/17/2009 Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved. 17
  • 18. Modelの分離(API) package SchoolG::Work::Model::API::Logic; use strict; use warnings; use parent 'Catalyst::Model::MultiAdaptor'; 1; 9/17/2009 Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved. 18
  • 19. Modelの分離(YAML) Model::API::Logic: package: 'SchoolG::API::Logic' lifecycle: Singleton except: - 'Plugin::Filter' 9/17/2009 Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved. 19
  • 20. Modelの分離はいったん完成 でも画面を書いていくうちに、 APIの中身がごちゃごちゃに… これでAPI? 分離するだけは何かが足りない… 9/17/2009 Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved. 20
  • 21. API? • Wikipedia Application programming interface (API) is an interface in computer science that defines the ways by which an application program may request services from libraries and/or operating systems The API initialism may sometimes be used as a reference, not only to the full interface, but also to one function, or even a set of multiple APIs provided by an organization. Thus, the scope of meaning is usually determined by the person or document that communicates the information. Wikipediaより引用 9/17/2009 Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved. 21
  • 22. なら、APIは自分たちなりに 定義して 決めたらいいの? 9/17/2009 Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved. 22
  • 23. 社内での議論(1) • 分離したロジックはなぜごちゃごちゃになっている? • APIモジュール群がうまく分類されていなくて、どこにどの処 理が書いてあるのか見失いやすくなった • 結局ロジックを書く場所が変わっただけ? • 分離したロジックを整理していかなければいけない 9/17/2009 Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved. 23
  • 24. 社内での議論(1) • WebアプリケーションはDB処理が多い • 至るところで繰り返し呼び出されるDB処理(CRUD処 理)と、一連の処理の流れ(ビジネスロジック)を整理す ることでAPIの見通しがよくなるのではないかと考えた • それぞれどこに、どのように書くべきか? 9/17/2009 Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved. 24
  • 25. 社内での議論(2) A案:API≒CRUD処理派 SchoolG API CRUD処理 Logic ビジネスロジック DBIC DBICの接続 B案:API≒ビジネスロジック派 SchoolG DBIC CRUD処理(DBICの接続) API ビジネスロジック 9/17/2009 Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved. 25
  • 26. 社内での議論(3) • APIは隠ぺい化された機能 • CRUD処理も ビジネスロジックも、隠蔽化さ れた機能として(どのコンテキストからも呼び 出せるように)実装していきたい • つまりCRUD処理もビジネスロジックもAPI! 9/17/2009 Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved. 26
  • 27. 社内での議論(4) SchoolG API Data CRUD処理 最終 案 Logic ビジネスロジック 9/17/2009 Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved. 27
  • 28. 実装してフィードバック、 また修正してフィードバック、 … 出来上がってきた! 9/17/2009 Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved. 28
  • 29. API API::Data APIの構成 API::Logic API • API::Data • DBへの接続 • SQLの発行 • API::Logic • ビジネスロジック • Dataを呼び出してデータを取得・整形 • API • API::Jobqueue • API::Plugin 9/17/2009 Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved. 29
  • 30. API API::Data API::Logic API API::Data 9/17/2009 Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved. 30
  • 31. API API::Data API::Data API::Logic API • 役割 • DBへの接続とSQLの発行を行う • 子クラスにCRUD処理を記述する • 機能 • レプリケーション管理 • コネクションプーリング • 返値のデータ形式の統一 • 実装のポイント • 子クラスはテーブル毎に作るようにした 9/17/2009 Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved. 31
  • 32. API::DataとDBICのつなぎ方 package SchoolG::API::Data; has _master_schema => ( is => 'rw', required => 1, isa => 'DBIx::Class::Schema', default => sub { # Singleton化した SchoolG::DBIC::Singleton->instance->_master } ); sub master { my ( $self, $table_name ) = @_; $table_name ||= $self->_table_name; return $self->_master_schema ->resultset($table_name); } 9/17/2009 Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved. 32
  • 33. API::Dataのデータの返し方 package SchoolG::API::Data; # DBICのsearchは直接利用せずに親クラス(このクラス)のsearchを利用する sub search { my ( $self, $args ) = @_; my $conditions = $args->{conditions}; my $options = $args->{options}; # searchの場合はslaveのschemaを利用 my $resultset = $self->slave->search( $conditions, $options ); # DBICのオブジェクトではなくHashRefかArrayRefで返すようにした $resultset->result_class ('DBIx::Class::ResultClass::HashRefInflator'); return exists $options->{page} && exists $options->{rows} ? { result => [ $resultset->all ], pager => $resultset->pager } : [ $resultset->all ]; } 9/17/2009 Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved. 33
  • 34. API API::Data API::Logic API API::Logic 9/17/2009 Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved. 34
  • 35. API API::Data API::Logic API::Logic API • 役割 • 子クラスにビジネスロジックを記述する • Catalyst のComponentにはビジネスロジックは極力書かない • CRUD処理はAPI::Dataに記述し、API::Logicから呼び出す • API::Logicの子クラスで行う処理の流れ • Validation処理 • 一連のCRUD処理(トランザクション管理も含む) • CRUD処理結果の加工 • 実装のポイント • Catalystアプリケーション及びジョブの両方からAPI::Logicを呼び出 せるようにした 9/17/2009 Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved. 35
  • 36. package SchoolG::API::Logic::ManageStaff; extends 'SchoolG::API::Logic'; sub create { my ( $self, $args ) = @_; my $created_by = delete $args->{created_by}; my $validation = $self->validate( $args->{columns}, 'create' ); return $validation unless $validation->{success}; delete $args->{columns}->{cancel}; delete $args->{columns}->{submit}; $args->{columns}->{staff_created_by} = $created_by; $args->{columns}->{staff_updated_by} = $created_by; my $txn = sub { $self->data('MasterStaff')->create($args); }; $self->txn($txn); } 9/17/2009 Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved. 36
  • 37. API API::Data API::Logic API API 9/17/2009 Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved. 37
  • 38. API API::Data API::Logic API API • 役割 • API::DataとAPI::Logicの親クラス • 機能 • API::DataとAPI::Logicのアクセサの提供 • API::DataとAPI::Logicで共通メソッドの提供 • 実装のポイント • ジョブからAPIを経由してAPI::DataとAPI::Logic両方を簡 単に呼べるようにした 9/17/2009 Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved. 38
  • 39. API API::Data APIの最終形 API::Logic API Catalyst からも ジョブからもAPIを呼べる API Data Catalyst Job DB Logic 9/17/2009 Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved. 39
  • 40. 実装:Catalystからの呼び出し 9/17/2009 Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved. 40
  • 41. package SchoolG::Work::Controller::Manage::Staff::Create; sub execute : Local { my ( $self, $c ) = @_; my $result = $c->model('API::Logic::ManageStaff') ->create( { columns => $c->req->params, created_by => $c->user->staff_seq } ); $c->res->redirect( $c->uri_for('/manage/staff') ); } 9/17/2009 Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved. 41
  • 42. package SchoolG::API::Logic::ManageStaff; extends 'SchoolG::API::Logic'; sub create { my ( $self, $args ) = @_; my $created_by = delete $args->{created_by}; my $validation = $self->validate( $args->{columns}, 'create' ); return $validation unless $validation->{success}; delete $args->{columns}->{cancel}; delete $args->{columns}->{submit}; $args->{columns}->{staff_created_by} = $created_by; $args->{columns}->{staff_updated_by} = $created_by; my $txn = sub { $self->data('MasterStaff')->create($args); }; $self->txn($txn); } 9/17/2009 Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved. 42
  • 43. package SchoolG::API::Data::MasterStaff; use Moose; extends 'SchoolG::API::Data'; sub BUILD { my $self = shift; $self->_table_name('MasterStaff'); $self->_table_prefix('staff'); $self->_default_conditions( { staff_delete => 0, staff_seq => { '>' => 1 } } ); $self->_default_options( { order_by => [qw/staff_office/] } ); } 9/17/2009 Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved. 43
  • 44. package SchoolG::API::Data; use Moose; has _table_prefix => ( is => 'rw', isa => 'Str', ); sub create { my ( $self, $args ) = @_; my $prefix = $self->_table_prefix; my $columns = $args->{columns}; my $result = $self->master->create($columns); return $result ? { success => 1 } : { success => 0 }; } 9/17/2009 Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved. 44
  • 45. 実装:ジョブからの呼び出し 9/17/2009 Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved. 45
  • 46. package SchoolG::Batch::Job::CountTask; sub work { my ( $class, $job ) = @_; my $api = SchoolG::API->new(); my $result = $api->logic('CountTask') ->get_profile_count( $job->arg ); $job->completed; } 9/17/2009 Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved. 46
  • 47. package SchoolG::API::Logic::CountTask; extends 'SchoolG::API::Logic'; sub get_profile_count { my ( $self, $args ) = @_; undef my $counts; return $counts if $args->{operation} == 3; $counts->{count_profile} = $self->data('DataProfile')->count_for_count_task( { school_seq => $args->{school_seq}, status => 0 } ); return $counts; } 9/17/2009 Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved. 47
  • 48. package SchoolG::API::Data::DataProfile; use Moose; extends 'SchoolG::API::Data'; sub count_for_count_task { my ( $self, $args ) = @_; my $conditions; $conditions->{profile_school_seq} = $args->{school_seq}; $self->SUPER::count( { conditions => $conditions } ); } 9/17/2009 Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved. 48
  • 49. APIの設計・リファクタを振りかえって 9/17/2009 Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved. 49
  • 50. APIを設計しながら • 機能単位の分割するのが難しかった • ルールをすべて守るのが難しかった • リファクタリング5回くらい!!! • まとまってきれいにかけた 9/17/2009 Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved. 50
  • 51. まとめ • API設計 • CRUD処理はAPI::Dataに、ビジネスロジックは API::Logicに分けることで見通しがよくなった • Catalystからもジョブからも呼べるような構成となった • Catalyst 5.8 • 今回CatalystのComponentではMooseの機能は使って いない • Mooseの機能をCatalyst内で使わない限りは5.7とほとん ど同じように書くことができた 9/17/2009 Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved. 51
  • 52. 今後に向けて • 別のプロジェクトでも通用するのか試してみたい • ガイアックスでは今回APIをこのように考えて実装し てみました • 「APIってこんな考え方もあるよ」などの意見があれ ば是非教えて下さい • パフォーマンス向上などこれからも新しいことに挑戦 していきます 9/17/2009 Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved. 52
  • 53. 参考にさせていただきました • Catalyst::Upgrading • http://search.cpan.org/~flora/Catalyst-Runtime- 5.80011/lib/Catalyst/Upgrading.pod • モダンPerlの世界へようこそ - 第6回 Catalyst::Upgrading:検証はお早めに • http://gihyo.jp/dev/serial/01/modern-perl/0006 • Moosification: Catalyst 5.8に移行した際にちょっと 気づいた事。 • http://mt.endeworks.jp/d-6/2009/05/moosification-catalyst- 58.html 9/17/2009 Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved. 53
  • 54. まだ終わってないです! Perlじゃないって言われても 気にしません! 9/17/2009 Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved. 54
  • 56. スクリーンショットの要件 • 学校裏サイトのスクリーンショッ トが欲しかった • サムネイルではなく、ページ全 体のスクリーンショットが必要 だった • 長いページでもページ全体を 撮る必要があった • 実装にあたって、2つのアプ ローチがありました 9/17/2009 Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved. 56
  • 57. アプローチ • Xvfb案 • Xvfb(Xの仮想環境)にブラウザを立ち上げて、Xvfb 自体をキャプチャ! • Canvas案 • FirefoxのCanvas要素でWebページをキャプチャ! • まずはXvfbの実装から試してみることに!! 9/17/2009 Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved. 57
  • 58. 案① • Xvfbでキャプチャ! • XvfbにFirefoxを起動し、 取得 X Window Dumpで 範囲 ファイルとして保存する • …この案では、 Xの仮 想環境の高さまでしかペ ージのキャプチャが取得 できない! 9/17/2009 Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved. 58
  • 59. 案② • Canvasでキャプチャ! • Firefoxで、Canvas要素 へWebサイトを描画し、 それをファイルとして保 存する 取得 範囲 • …コンテンツ量の多いサ イトで、メモリ不足になり、 キャプチャが取得できな いときがある! 9/17/2009 Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved. 59
  • 60. 案③ • Canvasでキャプチャ! 取得 • Canvas要素でスクリーン 範囲 ショットを取得 • 工夫として、撮影領域の 高さを固定し、分割して キャプチャするようにした • →高さを固定できるので、 取得 1回のキャプチャのメモリ 範囲 使用量の上限を固定でき る 9/17/2009 Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved. 60
  • 61. 結果… • Canvas案を採用しました! • この案をもとに、開いたページのスクリーンショットを 撮るFirefoxのアドオンを制作しました • Canvasでスクリーンショットを取得 • XPCOMでディスクへファイルとして書き込み 9/17/2009 Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved. 61
  • 62. 実装 9/17/2009 Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved. 62
  • 63. CanvasでWebページを描画 • canvas要素を作成し、Webページを描画する • toDataURL()を用いて描画したデータの data:URLを取得する var canvas = window.document.createElement(‘canvas’); var ctx = canvas.getContext('2d'); // Webページの描画 ctx.drawWindow(window, X開始点, Y開始点, X終了点, Y終了点, ‘rgb(0,0,0)’); ctx.restore(); // 描画したデータをBASE64エンコードしたdata:URLを取得 var url = canvas.toDataURL(‘image/png’); 9/17/2009 Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved. 63
  • 64. ファイルの保存 • nsIURIオブジェクトの生成 • nsILocalFileでファイルオブジェクトを生成 • nsIWebBrowserPersistでファイルに保存する var Cc = Components.classes; var Ci = Components.interfaces; // URIオブジェクトの生成 var URI = Cc['@mozilla.org/network/io-service;1'] .getService(Ci.nsIIOService).newURI(url, null, null); // ファイルオブジェクトの生成 var file = Cc["@mozilla.org/file/local;1"] .createInstance(Ci.nsILocalFile); file.initWithPath(保存先のファイルパス); // ファイルに保存 var wbp = Cc['@mozilla.org/embedding/browser/nsWebBrowserPersist;1'] .createInstance(Ci.nsIWebBrowserPersist); wbp.saveURI(url, null, null, null, null, file); 9/17/2009 Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved. 64
  • 65. 分割キャプチャ 以上の実装を、ブラウザの高さで 分割して、繰り返しキャプチャするようにした var max = window.document.height; var width = window.outerWidth; var fromY = window.scrollY; var height = window.innerHeight; while (fromY <= max) { var toY = (fromY + height) > max ? max : fromY + height; // キャプチャするメソッド capture(window, width, fromY, toY); if (fromY + height > max) break; fromY = toY; } 9/17/2009 Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved. 65
  • 66. 実演 • デモをご覧ください 9/17/2009 Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved. 66
  • 67. 参考にさせていただきました • SCRAPBLOG : canvas要素によるWebペー ジのスクリーンショット保存機能 • http://www.xuldev.org/blog/?p=37 • File I/O – MDC • https://developer.mozilla.org/ja/Code_snippets/File_I %2F%2FO 9/17/2009 Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved. 67
  • 68. 最後に告知 9/17/2009 Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved. 68
  • 69. 仲間募集中! • ガイアックスでは、小さなチームで新しい技術を積極的に取り入れながら 自社プロダクトを開発しています。 • 一緒にチャレンジし、成長していく意欲のある開発者を募集中です。 9/17/2009 Copyright Since 1999 © GaiaX Co. Ltd. All rights reserved. 69