このブログは、旧・はてなダイアリー「檜山正幸のキマイラ飼育記 メモ編」(http://d.hatena.ne.jp/m-hiyama-memo/)のデータを移行・保存したものであり、今後(2019年1月以降)更新の予定はありません。

今後の更新は、新しいブログ http://m-hiyama-memo.hatenablog.com/ で行います。

最近のCatyScriptコード

可読性に難ありだったCatyScriptもけっこう改善された。普通に読める。

最近書いたスクリプト。二百数十行、30行限界説を唱えていた頃に比べると……

// -*- coding: utf-8 -*-
/** 
 *
 * リソースマトリックス (Resource Matrices) の操作
 * 
 */
module resmat;

/** リソースインスタンスのパス */
type instancePath = string(remark="リソースインスタンスのパス");

/** コロンドットパス */
type cdpath = string(remark="コロンドットパス");

/** アクションのエントリーポイント
 * public:Trigger と類似している。
 *
 * inputDatatype --> inputType これはTriggerも変更する。
 * paramsDatatype --> paramsType これはTriggerも変更する。
 * 
 */
type EntryPoint = {
  /** エントリーポイントのURI */
  "href": uri,

  /** HTTPメソッド */
  @[default("GET")]
  "method": httpMethod?,
  /** 動詞 */
  @[default("")]
  "verb": string?,

  /** 入力(リクエストボディ)の型 */
  @[default("void")]
  "inputType": typeName?,
  /** パラメータの型 */
  @[default("EmptyObject")]
  "paramsType": typeName?,

  *: any?
};

/** リソースマトリックス (Resource Matrix) */
type ResMat = {
  /** リソースのコロンドットパス 
   * アプリケーション名は除き、モジュールパス:ローカル名
   */
  "resourceClassCdpath" : cdpath,
  "pathPattern": [string*],

  "instances": [instancePath*],

  "actions" : {* /*アクションのローカル名*/: ActionSummary?},

};

/** アクション情報のサマリー */
type ActionSummary = {
 "name": string,

  /** HTTPメソッド */
  @[default("GET")]
  "method": httpMethod?,

  /** 動詞 */
  @[default("")]
  "verb": string?,

  /** 入力(インレットの入力)の型 
   */
  @[default("void")]
  "inputType": typeName?,
  /** パラメータ(オプション)の型 */
  @[default("EmptyObject")]
  "paramsType": typeName?,
};

/** リソースマトリックス・データの置き場所 */
@[hidden]
const RES_MAT_DIR = "data@this:/res-matrices/";

/**  サンプルのリソースマトリックス */
@[hidden]
const SAMPLE = {
  "resourceClassCdpath" : "pkgFoo.modBar:CSVRes",
  "pathPattern": ["/csv/*.csv", "/a/*.csv"],

  "instances": ["/csv/file1.csv", "/a/file2.csv"],

  "actions" : {
    "get": {
       "name": "get",
       "method": "GET",
       "verb": "",
       "inputType": "void",
       "paramsType": "EmptyObject",
     },
    "getRaw": {
       "name": "getRaw",
       "method": "GET",
       "verb": "raw",
       "inputType": "void",
       "paramsType": "EmptyObject",
     },
  },

};

/** リソースマトリックスデータをセットアップする */
command setup :: void -> void {
 SAMPLE > sample | $.resourceClassCdpath > cdpath;
 %cdpath | res-name-to-file-path > path;
 %sample | json:pretty | file:write --mkdir %path
};

/** エラー時の処理(例外生成)をする */
@[hidden]
command error :: string -> never {
 pass > msg;
 @UnknownError {"message":%msg} | throw-if-can
};

/** リソースのファイル名からCDパスに変換する */
@[hidden]
command file-name-to-res-name :: string -> string {
 text:split "." | [list:slice -2 -1 > res-local, list:slice 0 -2 > mod];
 [%mod | text:join "." , %res-local | item 0] | text:join ":"
};

/** リソースのCDパスからファイルパスに変換する */
@[hidden]
command res-name-to-file-path :: string -> string {
 text:split ":" | text:join "." > base;
 [RES_MAT_DIR, %base, ".xjson"] | text:concat
};

/** リソースマトリックスをロードする */
@[hidden]
command load-matrix [string res-name] :: void -> ResMat {
  %1 | res-name-to-file-path > path;
  xjson:read %path
};


/** 現在のリソースマトリックス名(=リソース名)をリストする */
command list :: void -> [string*] {
 RES_MAT_DIR > dir;
 file:list %dir | each {pv name | file-name-to-res-name}
};

/** リソースマトリックスのインスタンスセット(配列)を取り出す */
command instances [string res-name] :: void -> [instancePath*] {
 %1 > res-name;
 load-matrix %res-name | $.instances
};

/** リソースマトリックスのアクションセット(オブジェクト)を取り出す */
command actions [string res-name] :: void -> {*: ActionSummary?} {
 %1 > res-name;
 load-matrix %res-name | $.actions
};

/** リソースマトリックスの成分(エントリーポイント)を取り出す */
command entry-point [string res-name, (string|null)? action-name, (instancePath|null)? instance] 
:: void -> any/*EntryPoint | [EntryPoint*]*/
{
  %1  > res-name;
  %2? > action-name;
  %3? > instance;

  [%action-name?, %instance?] |
  cond {
    [string, string]  => entry-point-one       %res-name %action-name %instance,
    [null,   string]  => entry-point-actions   %res-name              %instance,
    [string, null?]   => entry-point-instances %res-name %action-name,
    [null?,  null?]   => entry-point-all       %res-name,
    * => "No Argument" | error,
  }
};

/** エントリーポイントを作る */
@[hidden]
command make-entry-point :: [ActionSummary, string] -> any/*EntryPoint*/
{
  [nth 1 > action, nth 2 > instance];
  [%HOST_URL, %APP_PATH] | text:concat > url-base;

  {
    "href": [%url-base, %instance] | text:concat,
    "method": %action | $.method?,
    "verb": %action | $.verb?,
    "inputType": %action | $.inputType?,
    "paramsType": %action | $.paramsType?,
  }
};

/** リソースマトリックスの1つの成分を取り出す */
command entry-point-one [string res-name, string action-name, instancePath instance] 
:: void -> any/*EntryPoint*/
{
  %1  > res-name;
  %2  > action-name;
  %3  > instance;

  load-matrix %res-name | [$.instances > instances, $.actions > actions];

  [%instances, %instance] | list:contains |
  when {
    False => ["No Instance: ", %instance] | text:concat | error ,
    True  =>
      %actions | pv --safe %action-name |
      when {
        undefined => ["No Action", %action-name] | text:concat | error ,
        * => [(%actions | pv %action-name), %instance] | make-entry-point
      }
    ,
  }
};

/** 指定されたインスタンスに対して、リソースマトリックスの列ベクトルを取り出す */
command entry-point-actions [string res-name, instancePath instance] 
:: void -> any/*EntryPoint*/
{
  %1  > res-name;
  %2  > instance;

  load-matrix %res-name | [$.instances > instances, $.actions > actions];

  %actions | each {[pass, %instance] | make-entry-point}
};

/** 指定されたアクションに対して、リソースマトリックスの行ベクトルを取り出す */
command entry-point-instances [string res-name, string action-name] 
:: void -> any/*EntryPoint*/
{
  %1  > res-name;
  %2  > action-name;

  load-matrix %res-name | [$.instances > instances, $.actions > actions];

  %actions | pv %action-name > action;
  %instances | each {[%action, pass] | make-entry-point}

};

/** リソースマトリックスのすべての成分を取り出す */
command entry-point-all [string res-name] 
:: void -> any
{
  %1 > res-name;

  load-matrix %res-name | [$.instances > instances, $.actions > actions];

  %actions |
  each {
    pass > action;
    %instances | 
    each {
      [%action, pass] | make-entry-point
    }
  }

};

// End of Module