Hatena::Grouperlang

檜山正幸のErlang未確認情報 RSSフィード

 | 

2008-12-24 (水)

argのダンプとか

| 12:37

YAWSを使うにはargについて知っている必要がある。学習、テスト、デバッグに、argのダンプがあると便利だろう。YAWSバージョンによってargが多少違うようだが、yaws-1.77 ベース。

書いただけで全然テストしてないが(苦笑):

%% -*- coding: utf-8 -*-

%% @doc YAWSを利用する際に便利な関数群.
-module(yaws_util).

-export([ % プロパティリストの生成
          full_arg_plist/1, std_arg_plist/1, 
          full_headers_plist/1, std_headers_plist/1,
          request_plist/1
         ]).
-export([ % プロパティリストからテーブルの生成
          full_arg_table/2, std_arg_table/2,
          full_headers_table/2, std_headers_table/2,
          request_table/2,

          full_arg_table/1, std_arg_table/1,
          full_headers_table/1, std_headers_table/1,
          request_table/1
         ]).
-export([ % ダンプ関数
          dump/1, dump_full_arg/1, dump_full_headers/1
         ]).
-export([ % テストに使うダミーデータ
          dummy_arg/0, dummy_headers/0, dummy_request/0
         ]).

-include("../../yaws/include/yaws_api.hrl").

-define(DEFAULT_TABLE_ATTRS, [{border, 2}]).

%% ==================================================

%% @doc #arg{}から、項目名/値を要素とするプロパティリストを作る.
%% @spec (#arg{}) -> [{atom(), term()}]
full_arg_plist(Arg) when is_record(Arg, arg) ->
  [
   {clisock, Arg#arg.clisock}, 
   {client_ip_port, Arg#arg.client_ip_port}, 
   {headers, Arg#arg.headers}, 
   {req, Arg#arg.req}, 
   {clidata, Arg#arg.clidata}, 
   {server_path, Arg#arg.server_path}, 
   {querydata, Arg#arg.querydata}, 
   {docroot, Arg#arg.docroot}, 
   {docroot_mount, Arg#arg.docroot_mount}, 
   {fullpath, Arg#arg.fullpath}, 
   {cont, Arg#arg.cont}, 
   {state, Arg#arg.state}, 
   {pid, Arg#arg.pid}, 
   {opaque, Arg#arg.opaque}, 
   {prepath, Arg#arg.prepath}, 
   {pathinfo, Arg#arg.pathinfo}
  ].

%% @doc #arg{}から、headersとreqを除き、項目名/値を要素とするプロパティリストを作る.
%% @spec (#arg{}) -> [{atom(), term()}]
std_arg_plist(Arg) when is_record(Arg, arg) ->
  [
   {clisock, Arg#arg.clisock}, 
   {client_ip_port, Arg#arg.client_ip_port}, 
%   {headers, Arg#arg.headers}, 
%   {req, Arg#arg.req}, 
   {clidata, Arg#arg.clidata}, 
   {server_path, Arg#arg.server_path}, 
   {querydata, Arg#arg.querydata}, 
   {docroot, Arg#arg.docroot}, 
   {docroot_mount, Arg#arg.docroot_mount}, 
   {fullpath, Arg#arg.fullpath}, 
   {cont, Arg#arg.cont}, 
   {state, Arg#arg.state}, 
   {pid, Arg#arg.pid}, 
   {opaque, Arg#arg.opaque}, 
   {prepath, Arg#arg.prepath}, 
   {pathinfo, Arg#arg.pathinfo}
  ].

%% @doc #headers{}から、項目名/値を要素とするプロパティリストを作る.
%% @spec (#headers{}) -> [{atom(), term()}]
full_headers_plist(Headers) when is_record(Headers, headers) ->
  [
   {connection, Headers#headers.connection}, 
   {accept, Headers#headers.accept}, 
   {host, Headers#headers.host}, 
   {if_modified_since, Headers#headers.if_modified_since}, 
   {if_match, Headers#headers.if_match}, 
   {if_none_match, Headers#headers.if_none_match}, 
   {if_range, Headers#headers.if_range}, 
   {if_unmodified_since, Headers#headers.if_unmodified_since}, 
   {range, Headers#headers.range}, 
   {referer, Headers#headers.referer}, 
   {user_agent, Headers#headers.user_agent}, 
   {accept_ranges, Headers#headers.accept_ranges}, 
   {cookie, Headers#headers.cookie}, 
   {keep_alive, Headers#headers.keep_alive}, 
   {location, Headers#headers.location}, 
   {content_length, Headers#headers.content_length}, 
   {content_type, Headers#headers.content_type}, 
   {content_encoding, Headers#headers.content_encoding}, 
   {authorization, Headers#headers.authorization}, 
   {transfer_encoding, Headers#headers.transfer_encoding}, 
   {other, Headers#headers.other}
  ].

%% @doc #headers{}から、otherを除いて、項目名/値を要素とするプロパティリストを作る.
%% @spec (#headers{}) -> [{atom(), term()}]
std_headers_plist(Headers) when is_record(Headers, headers) ->
  [
   {connection, Headers#headers.connection}, 
   {accept, Headers#headers.accept}, 
   {host, Headers#headers.host}, 
   {if_modified_since, Headers#headers.if_modified_since}, 
   {if_match, Headers#headers.if_match}, 
   {if_none_match, Headers#headers.if_none_match}, 
   {if_range, Headers#headers.if_range}, 
   {if_unmodified_since, Headers#headers.if_unmodified_since}, 
   {range, Headers#headers.range}, 
   {referer, Headers#headers.referer}, 
   {user_agent, Headers#headers.user_agent}, 
   {accept_ranges, Headers#headers.accept_ranges}, 
   {cookie, Headers#headers.cookie}, 
   {keep_alive, Headers#headers.keep_alive}, 
   {location, Headers#headers.location}, 
   {content_length, Headers#headers.content_length}, 
   {content_type, Headers#headers.content_type}, 
   {content_encoding, Headers#headers.content_encoding}, 
   {authorization, Headers#headers.authorization}, 
   {transfer_encoding, Headers#headers.transfer_encoding} %,
%   {other, Headers#headers.other}
  ].

%% @doc #http_request{}から、項目名/値を要素とするプロパティリストを作る.
%% @spec (#http_request{}) -> [{atom(), term()}]
request_plist(Request) when is_record(Request, http_request) ->
  [
   {method, Request#http_request.method},
   {path, Request#http_request.path},
   {version, Request#http_request.version}
  ].


%% ==================================================
%%  tables
%% ==================================================

%% @spec ({atom(), term()}) -> term()
tr({Name, Value}) ->
  % 注意:属性リストを省略できない!
  Title = if
            is_atom(Name) -> atom_to_list(Name);
            true -> Name
          end,
  Item = io_lib:format("~p", [Value]),
  {tr, [],
   [
    {td, [], [Title]},
    {td, [], [Item]}
   ]
  }.

%% @spec (PList, Attrs) -> Table
%% where
%%   PList = [{atom(), term()}]
%%   Attrs = [{atom(), term()}]
%%   Table = term()
make_table(PList, Attrs) ->
  TableContent = lists:map(fun tr/1, PList),
  {table, Attrs, TableContent}.

%% @doc #arg{}から、EHTMLテーブルを作る.
%% 引数Attrsは、tableタグに付加する属性リスト.
%% @spec (#arg{}, Attrs) -> Table
%% where
%%   Attrs = [{atom(), term()}]
%%   Table = term()
full_arg_table(Arg, Attrs) when is_record(Arg, arg) ->
  make_table(full_arg_plist(Arg), Attrs).

%% @doc #arg{}から、reqとheadersを除いたEHTMLテーブルを作る.
%% 引数Attrsは、tableタグに付加する属性リスト.
%% @spec (#arg{}, Attrs) -> Table
%% where
%%   Attrs = [{atom(), term()}]
%%   Table = term()
std_arg_table(Arg, Attrs) when is_record(Arg, arg) ->
  make_table(std_arg_plist(Arg), Attrs).

%% @doc #headers{}から、EHTMLテーブルを作る.
%% 引数Attrsは、tableタグに付加する属性リスト.
%% @spec (#headers{}, Attrs) -> Table
%% where
%%   Attrs = [{atom(), term()}]
%%   Table = term()
full_headers_table(Headers, Attrs) when is_record(Headers, headers) ->
  make_table(full_headers_plist(Headers), Attrs).

%% @doc #headers{}から、otherを除いて、EHTMLテーブルを作る.
%% 引数Attrsは、tableタグに付加する属性リスト.
%% @spec (#headers{}, Attrs) -> Table
%% where
%%   Attrs = [{atom(), term()}]
%%   Table = term()
std_headers_table(Headers, Attrs) when is_record(Headers, headers) ->
  make_table(std_headers_plist(Headers), Attrs).

%% @doc #http_request{}から、EHTMLテーブルを作る.
%% 引数Attrsは、tableタグに付加する属性リスト.
%% @spec (#http_request{}, Attrs) -> Table
%% where
%%   Attrs = [{atom(), term()}]
%%   Table = term()
request_table(Request, Attrs) when is_record(Request, http_request) ->
  make_table(request_plist(Request), Attrs).

%% @equiv full_arg_table(Arg, DEFAULT_TABLE_ATTRS)
%% @spec (#arg{}) -> Table
%% where
%%   Table = term()
full_arg_table(Arg) when is_record(Arg, arg) ->
  make_table(full_arg_plist(Arg), ?DEFAULT_TABLE_ATTRS).

%% @equiv std_arg_table(Arg, DEFAULT_TABLE_ATTRS)
%% @spec (#arg{}) -> Table
%% where
%%   Table = term()
std_arg_table(Arg) when is_record(Arg, arg) ->
  make_table(std_arg_plist(Arg), ?DEFAULT_TABLE_ATTRS).

%% @equiv full_header_table(Headers, DEFAULT_TABLE_ATTRS)
%% @spec (#headers{}) -> Table
%% where
%%   Table = term()
full_headers_table(Headers) when is_record(Headers, headers) ->
  make_table(full_headers_plist(Headers), ?DEFAULT_TABLE_ATTRS).

%% @equiv std_header_table(Headers, DEFAULT_TABLE_ATTRS)
%% @spec (#headers{}) -> Table
%% where
%%   Table = term()
std_headers_table(Headers) when is_record(Headers, headers) ->
  make_table(std_headers_plist(Headers), ?DEFAULT_TABLE_ATTRS).

%% @equiv request_table(Request, DEFAULT_TABLE_ATTRS)
%% @spec (#http_request{}) -> Table
%% where
%%   Table = term()
request_table(Request) when is_record(Request, http_request) ->
  make_table(request_plist(Request), ?DEFAULT_TABLE_ATTRS).
 
%% ==================================================
%%  dumpers
%% ==================================================

%% @doc #arg{}に含まれるすべての情報を多少整理変形して表示する.
%% @spec (#arg{}) -> EHTML
%%  where
%%    EHTML = {ehtml, term()}
dump(Arg) ->
  {ehtml,
   {html, [],
    [
     {body, [],
      [
       request_table(Arg#arg.req),
       full_headers_table(Arg#arg.headers),
       std_arg_table(Arg)
      ]
     }
    ]
   } % /html
  }. % /ehtml

%% @doc #arg{}に含まれるすべての情報を表示する.
%% @spec (#arg{}) -> EHTML
%%  where
%%    EHTML = {ehtml, term()}
dump_full_arg(Arg) ->
  {ehtml,
   {html, [],
    [
     {body, [],
      [
       full_arg_table(Arg)
      ]
     }
    ]
   } % /html
  }. % /ehtml

%% @doc #headers{}に含まれるすべての情報を表示する.
%% ただし、引数は#arg{}である点に注意
%% @spec (#arg{}) -> EHTML
%%  where
%%    EHTML = {ehtml, term()}
dump_full_headers(Arg) ->
  Headers = Arg#arg.headers,
  Table = full_headers_table(Headers),
  {ehtml,
   {html, [],
    [
     {body, [],
      [
       Table
      ]
     }
    ]
   } % /html
  }. % /ehtml

%% ==================================================
%%  dummy data
%% ==================================================

%% @doc テストに使うダミー#arg{}.
%% @spec () -> #arg{}
dummy_arg() ->
  #arg {
           clisock = "clisock", 
           client_ip_port = "client_ip_port", 
           headers = dummy_headers(), 
           req = dummy_request(), 
           clidata = "clidata", 
           server_path = "server_path", 
           querydata = "querydata", 
           docroot = "docroot", 
           docroot_mount = "docroot_mount", 
           fullpath = "fullpath", 
           cont = "cont", 
           state = "state", 
           pid = "pid", 
           opaque = "opaque", 
           prepath = "prepath", 
           pathinfo = "pathinfo"
          }.

%% @doc テストに使うダミー#headers{}.
%% @spec () -> #headers{}
dummy_headers() ->
  #headers {
               connection = "connection", 
               accept = "accept", 
               host = "host", 
               if_modified_since = "if_modified_since", 
               if_match = "if_match", 
               if_none_match = "if_none_match", 
               if_range = "if_range", 
               if_unmodified_since = "if_unmodified_since", 
               range = "range", 
               referer = "referer", 
               user_agent = "user_agent", 
               accept_ranges = "accept_ranges", 
               cookie = "cookie", 
               keep_alive = "keep_alive", 
               location = "location", 
               content_length = "content_length", 
               content_type = "content_type", 
               content_encoding = "content_encoding", 
               authorization = "authorization", 
               transfer_encoding = "transfer_encoding", 
               other = ["other1", "other2"]
              }.

%% @doc テストに使うダミー#http_request{}.
%% @spec () -> #http_request{}
dummy_request() ->
  #http_request{
               method = "method",
               path = "path",
               version = "version"
               }.

[追記]動かしてみたら、テーブルのレイアウトがひどすぎるのが判明。少しは直そう、そのうち。[/追記]

 |