Caché ObjectScript チュートリアルへようこそ。 このチュートリ … ·...

130
Caché ObjectScript チュートリアル Caché ObjectScript チュートリアルへようこそ。 このチュートリアルでは、強力なオブジェクト型言語の基礎と、特有の機能について学習します。 Caché ObjectScript を使用して、すばやく、リッチなデータベース・アプリケーションを構築できま す。 ここでは以下のことが学習できます。 文字列やリスト、日付の取り扱い 複雑で現実的なリレーションシップを持つ、大規模なデータベースの生成と管理 データベース・オブジェクトの簡単な操作 序文 1

Transcript of Caché ObjectScript チュートリアルへようこそ。 このチュートリ … ·...

Page 1: Caché ObjectScript チュートリアルへようこそ。 このチュートリ … · チュートリアルへようこそ。 このチュートリアルでは、強力なオブジェクト型言語の基礎と、特有の機能について学習します。

Caché ObjectScript チュートリアル

Caché ObjectScript チュートリアルへようこそ。

このチュートリアルでは、強力なオブジェクト型言語の基礎と、特有の機能について学習します。

Caché ObjectScript を使用して、すばやく、リッチなデータベース・アプリケーションを構築できま

す。 ここでは以下のことが学習できます。

• 文字列やリスト、日付の取り扱い

• 複雑で現実的なリレーションシップを持つ、大規模なデータベースの生成と管理

• データベース・オブジェクトの簡単な操作

序文

-1-

Page 2: Caché ObjectScript チュートリアルへようこそ。 このチュートリ … · チュートリアルへようこそ。 このチュートリアルでは、強力なオブジェクト型言語の基礎と、特有の機能について学習します。

Caché ObjectScript チュートリアル

第 1 章

基礎編

この章では、他言語と類似した Caché ObjectScript の基本的なコマンドについて学習します。

第 1 章で学習することは以下のとおりです。

• ObjectScript ルーチンの構造

• Caché ターミナルと Caché スタジオの使用方法

• 後置条件を含む引数なしの Write、Read、Set、Kill、Do および Quit などの

ObjectScript コマンド

• If、For、While、Do/While などの ObjectScript 構文

• 適切な構文と一般的なエラー

• プロシージャ

-2-

Page 3: Caché ObjectScript チュートリアルへようこそ。 このチュートリ … · チュートリアルへようこそ。 このチュートリアルでは、強力なオブジェクト型言語の基礎と、特有の機能について学習します。

Caché ObjectScript チュートリアル

第 1 章 – Chapter1

チュートリアル演習

このチュートリアルでは、Caché スタジオを使用して、いくつかのプログラムを作成し、Caché

ObjectScriptのすべての特徴を体験することができます。 また、Cachéターミナルでの、コマンド

や関数の使用法の例もあります。 これらの例を自由に試してください。

Caché ObjectScript を学ぶ 適な方法は、チュートリアルにある練習問題を実践することです。

練習問題の解答は標準インストールに含まれており、SAMPLES ネームスペースにロードされてい

ます。詳細は、[Appendix B:サンプル・アプリケーション] を参照してください。

-3-

Page 4: Caché ObjectScript チュートリアルへようこそ。 このチュートリ … · チュートリアルへようこそ。 このチュートリアルでは、強力なオブジェクト型言語の基礎と、特有の機能について学習します。

Caché ObjectScript チュートリアル

第 1 章 – Chapter2

Caché ObjectScript ルーチン

ここでは、簡単ですが重要な Caché ObjectScript ルーチンについて学習します。 このルーチン

では、直角三角形の両辺の長さを元に面積と斜辺を計算します。 では、見てみましょう。

SAMPLES>do ^RightTriangle

Compute the area and hypotenuse of a right triangle

given the lengths of its two sides.

First, choose a unit of measurement.

(i)nches, (f)eet, (m)iles, (c)entimeters, m(e)ters, (k)ilometers: i

Length of side 1: 3 Accepted.

Length of side 2: 4 Accepted.

The area of this triangle is 6.00 square inches.

The hypotenuse is 5.00 inches.

SAMPLES>

ObjectScript は Basic や C などの他のプログラミング言語と類似しています。 このルーチンファ

イルには、ルーチンの主なセクション([RightTriangle])の他に、ユーザ定義関数の例である

[IsNegative]、プロシージャの例である[Compute]があります。 また、Write、Read、Set、Do、

Quit コマンド、If/Else、Do/While 文、後置条件文、$Justify、$Extract、$Case 関数も含まれ

ています。

次ページから、コマンド、文、関数の詳細について学習します。

RightTriangle ルーチンの完全なコードは、[Appendix C :Right Triangle ルーチン] を参照し

てください。

-4-

Page 5: Caché ObjectScript チュートリアルへようこそ。 このチュートリ … · チュートリアルへようこそ。 このチュートリアルでは、強力なオブジェクト型言語の基礎と、特有の機能について学習します。

Caché ObjectScript チュートリアル

第 1 章 – Chapter3

コマンド

ObjectScript を使用してチュートリアルを実行するため、 初に Caché ターミナルを開始します。

タスク・バーの Caché キューブ・アイコン を右クリックし、メニューから [ターミナル]を選択します。

ターミナル・ウィンドウが表示され、そのプロンプトから現在はUSERネームスペースで作業している

ことがわかります。 ネームスペースは論理的なディレクトリで、ルーチン(プログラム)とグローバル

(データ)を含みます。

Caché ターミナルでは、ObjectScript コマンドを入力することができ、瞬時に結果が表示されます。

この章では、以下のようにテキスト表示の例を示し、Caché ターミナル・セッションをいくつかシミュレ

ートします。 また、Caché スタジオを使用してルーチンを記述します。

Caché ターミナル開始時の、デフォルトネームスペースは USER ネームスペースです。

do ̂ %CD を使用し、SAMPLES ネームスペースに移動します。 ここでは、提供された例を参考にし、

自身の演習を実行できます。

USER>do ^%CD

Namespace: SAMPLES

You're in namespace SAMPLES

Default directory is c:\cachesys\mgr\samples\

SAMPLES>

-5-

Page 6: Caché ObjectScript チュートリアルへようこそ。 このチュートリ … · チュートリアルへようこそ。 このチュートリアルでは、強力なオブジェクト型言語の基礎と、特有の機能について学習します。

Caché ObjectScript チュートリアル

第 1 章 – Chapter4

Write コマンド

Write コマンドで情報を表示します。 テキストを表示するには、そのテキストを二重引用符で囲み

ます(例えば "Hello World!")。 Write コマンドを使用して、コンマで区切られたリスト項目を

一度に記述することができます。 特殊な形式制御 (!、?、#) を使用すると、それぞれ、改行、列

の位置の指定、画面をクリアすることができます。 また、式を評価することもできます。 この詳細

は、後に説明します。

コマンドは完全形でも、短縮形(通常 1 文字)でも使用できます。 コマンドは大文字と小文字を区別

しません。

SAMPLES>write "Hello World!"

Hello World!

SAMPLES>write !, "This", !, "Is", !, "A", !, "Multi-line", !, "Message!", !

This

Is

A

Multi-line

Message!

SAMPLES>write !, "This", ?9, "Is", ?18, "A", ?27, "Columnar", ?36, "Message!", !

This Is A Columnar Message!

SAMPLES>write 7.95 * 1.15

9.1425

SAMPLES>

-6-

Page 7: Caché ObjectScript チュートリアルへようこそ。 このチュートリ … · チュートリアルへようこそ。 このチュートリアルでは、強力なオブジェクト型言語の基礎と、特有の機能について学習します。

Caché ObjectScript チュートリアル

第 1 章 – Chapter5

Read コマンド

Read コマンドは、ユーザが入力した情報を受け取り、その応答を一時的に変数に保存します。

Write コマンドを使用すると、変数の内容を表示できます。変数の詳細は後で学習します。 変数

は大文字と小文字を区別します。 このチュートリアルでは、Read コマンドによるユーザ入力は大

文字で表示されています。

SAMPLES>read x

BEST FRIEND

SAMPLES>write "You just typed: ", x

You just typed: BEST FRIEND

SAMPLES>

プロンプトが返された場合、Read コマンドと Write コマンドはいくつかの機能を共有します。 ユ

ーザが入力するまでプロンプトを待機させるか、あるいは秒単位でタイムアウトを指定できます。

文字を入力せずに Enter を押した場合、変数は長さがゼロ (空)の文字を保存します。

入力できる文字数は無制限ですが、 大文字数を指定することもできます。 この場合、ユーザは

指定した文字数以下の文字を入力し Enter を押します。 大文字数以上の文字を入力しようとし

た場合は、Read が自動的に終了します。

SAMPLES>read ?30, "Enter your name: ", n

Enter your name: ALEXANDER

SAMPLES>read !, "You have 5 seconds to respond: ", x:5

You have 5 seconds to respond:

I TYPED THIS IN 5 SECONDS

SAMPLES>read !, "Type 5 characters and don't press Enter: ", z#5

Type 5 characters and don't press Enter: ABCDE

SAMPLES>

-7-

Page 8: Caché ObjectScript チュートリアルへようこそ。 このチュートリ … · チュートリアルへようこそ。 このチュートリアルでは、強力なオブジェクト型言語の基礎と、特有の機能について学習します。

Caché ObjectScript チュートリアル

変数と数式については、既に少しだけ述べてきました。 ObjectScript では変数を宣言する必要

がありません。 これにより、アプリケーション開発時間を大幅に削減することができます。 Set コ

マンドを使用して数式を評価し、変数に結果を割り当てます。 変数には 32K(32,768)文字まで格

納できます。

SAMPLES>set x = 4 + 2

SAMPLES>write x

6

SAMPLES>

ObjectScript には 7 つの二項算術演算子があります。 初の 2 つは単項演算子としても機能し

ます。

算術演算子

演算子 演算 例 (結果)

+

加算。単項演算子として式の先頭で

使用された場合、式を数値として解釈

します。

set x = 4 + 2 (x=6) set z =

"546-FRJ", y = +z (y=546)

-

減算。単項演算子として式の先頭で

使用された場合、式を数値として解釈

し、符号を反転します。

set x = 4 - 2 (x=2) set z = "-5

degrees", y = -z (y=5)

* 乗算 set x = 4 * 2 (x=8)

/ 除算 set x = 5 / 2 (x=2.5)

** べき乗 set x = 5 ** 2 (x=25)

¥

整数除算。第 1 オペランドを第 2 オペ

ランドで除算し、剰余は切り捨て結果

を整数で返します。

set x = 5 ¥ 2 (x=2)

#

モジュロ。第 1 オペランドを第 2 オペ

ランドで除算し、整数の剰余を返しま

す。

set x = 5 # 2 (x=1)

第 1 章 – Chapter6

Set コマンド

-8-

Page 9: Caché ObjectScript チュートリアルへようこそ。 このチュートリ … · チュートリアルへようこそ。 このチュートリアルでは、強力なオブジェクト型言語の基礎と、特有の機能について学習します。

Caché ObjectScript チュートリアル

第 1 章 – Chapter7

演算子の優先順位

算術演算子を結合して、複雑な算術式を記述することができます。 ObjectScript は他のプログ

ラミング言語とは異なり、演算子に優先順位がありません。 式の評価は演算子に関係なく、左から

右に処理されます。

しかし他言語と同様、括弧を使用して演算子の処理順序を指定できます。 どの言語を使用するか

にかかわらず、演算子の優先順位規則を当てにして、括弧を使用せずに複雑な式を記述しないでく

ださい。 必ず括弧を使用してください。

SAMPLES>set x = 3 + 5 * 6 - 4

SAMPLES>write x

44

SAMPLES>set x = 3 + ( 5 * 6 ) - 4

SAMPLES>write x

29

SAMPLES>

-9-

Page 10: Caché ObjectScript チュートリアルへようこそ。 このチュートリ … · チュートリアルへようこそ。 このチュートリアルでは、強力なオブジェクト型言語の基礎と、特有の機能について学習します。

Caché ObjectScript チュートリアル

第 1 章 – Chapter8

Do コマンド

ObjectScript では、プログラムはルーチンと呼ばれます。 Do コマンドを使用してルーチンを実行

します。 ルーチンには Caché が提供するシステム・ルーチンとユーザが記述するルーチンがあり

ます。 以下は、平方根を計算するシステム・ルーチン%SQROOT で、RightTriangle ルーチン

で使用しました。 Do コマンドで%SQROOT を実行し、ルーチン名の先頭には必ずサーカムフ

レックス“^”を付けます。 %文字で始まるルーチンは Caché システム・ルーチンを表します。

また、ルーチン内でプロシージャの開始場所を示すラベル(タグと呼ばれることもあります)を参照し

て、プロシージャを実行することもできます。 サーカムフレックスの前にラベルを配置します。 例え

ば、%SQROOT の INT プロシージャは%X に平方根の値を生成しますが、返り値を直接表示せ

ず%Y に格納します。

ルーチン名とラベルは大文字と小文字を区別します。

SAMPLES>do ^%SQROOT

Square root of: 100 is: 10

Square root of:

SAMPLES>set %X = 25 do INT^%SQROOT write %Y

5

SAMPLES>

-10-

Page 11: Caché ObjectScript チュートリアルへようこそ。 このチュートリ … · チュートリアルへようこそ。 このチュートリアルでは、強力なオブジェクト型言語の基礎と、特有の機能について学習します。

Caché ObjectScript チュートリアル

第 1 章 – Chapter9

文法(シンタックス)

ここまで Write、Read、Set と Do コマンドについて学習してきました。 次は一般的なコマンドの

文法について学習します。 コマンドの構文は、コマンド(またはその省略形)、1 つのスペース、コン

マで区切られた 1 つ以上の引数の順で記述されます。引数内にあるスペースの位置は問いませ

ん。

また、1 行に複数のコマンドを記述することもできます。 コマンドの 後の引数と次のコマンドの間

には、少なくとも 1 つのスペースが必要です。 後述する一部のコマンドには引数がありません。

引数のないコマンドの後に、別のコマンドを記述する場合は、2 つ以上のスペースが必要です。

以下は、複数の引数を持つ 3 つのコマンドの例です。 また、後ほど説明する $Zdateh 関数、

$Zdate関数と$Horologシステム変数も使用します。 $Horologは、“$h”に省略することがで

きます。

SAMPLES>read !, "DOB: ", dob set days = $h - $zdateh(dob), today = $zdate(+$h)

DOB: 7/7/1921

SAMPLES>write !, "On ", today, ", you are ", days, " days old."

On 12/27/2001, you are 29393 days old.

SAMPLES>

-11-

Page 12: Caché ObjectScript チュートリアルへようこそ。 このチュートリ … · チュートリアルへようこそ。 このチュートリアルでは、強力なオブジェクト型言語の基礎と、特有の機能について学習します。

Caché ObjectScript チュートリアル

第 1 章 – Chapter10

一般的なエラー

Cachéは誤った入力に対し、エラー・メッセージを返します。 エラー・メッセージの詳細情報は

Cachéドキュメント:[Caché開発リファレンス]-[Cachéエラー・リファレンス]に記述されています。

以下は、一般的な 4 つのエラーです。

• <SYNTAX>は余分なスペースやコマンドのスペル・ミスを示します。

• <NOROUTINE>は存在しないルーチンを実行しようとした場合に返されます。

• <NOLINE>は存在しないプロシージャを呼び出した場合に返されます。

• <UNDEFINED>は値を割り当てていない変数を使用した場合に返されます。 メッセ

ージには、先頭にアスタリスクの付いた未定義の変数名が示されます。

SAMPLES> write "hi" WRITE "hi"

^

<SYNTAX>

SAMPLES>s et x = 5

S et x = 5

^

<SYNTAX>

SAMPLES>sit x=5

SIT x=5

^

<SYNTAX>

SAMPLES>do ^%DD

DO ^%DD

^

<NOROUTINE>

SAMPLES>do INT^%DD

DO INT^%DD

^

<NOROUTINE>

SAMPLES>do INTT^%SQROOT

<NOLINE>^%SQROOT

SAMPLES>write xx

WRITE xx

^

<UNDEFINED> *xx

-12-

Page 13: Caché ObjectScript チュートリアルへようこそ。 このチュートリ … · チュートリアルへようこそ。 このチュートリアルでは、強力なオブジェクト型言語の基礎と、特有の機能について学習します。

Caché ObjectScript チュートリアル

第 1 章 – Chapter11

Write コマンドと Kill コマンド

これまで、データを保持するために変数を使用することを学習してきました。 また、タグ(do

INT^%SQROOT)によるルーチンの実行方法、変数%Y に平方根を格納する方法も学習してきまし

た。 引数を持たない Write(“引数なし Write”)を使用すると、すべての変数の値を表示できま

す。

Killコマンドを使用して変数を削除することができます。 また、引数なしのKillコマンドはすべての

変数を削除します。 Kill と引数なしの Write は、ルーチンをデバックする場合に便利です。

SAMPLES>set a = 1, b = 2, c = 3, d = 4, e = 5

SAMPLES>write

a=1

b=2

c=3

d=4

e=5

SAMPLES>kill c

SAMPLES>write

a=1

b=2

d=4

e=5

SAMPLES>kill

SAMPLES>write

SAMPLES>

-13-

Page 14: Caché ObjectScript チュートリアルへようこそ。 このチュートリ … · チュートリアルへようこそ。 このチュートリアルでは、強力なオブジェクト型言語の基礎と、特有の機能について学習します。

Caché ObjectScript チュートリアル

第 1 章 – Chapter12

If 文

If 文を使用して条件を評価し、その条件を元に実行するコードを決定できます。 単純なコマンドと

異なり、文は複数の引数、コマンド・キーワード、コード・ブロックを含みます。 コード・ブロックとは、

中括弧内にある複数のコード行のことです。 コード・ブロック内や前に、改行が存在する場合もあり

ます。 If 文の構文は以下のとおりです。

If condition { code } elseif condition {code} else {code}

ElseIf と Else はオプションで、通常 2 つ以上の ElseIf を指定します。 他の文については後で

学習します。

root ルーチン内で If を使用した例は以下のとおりです。

root ; root for my favorite team

read "Team: ", t

if ( t = "METS" ) {

write !, "Go METS!" }

else {

write !, "Boo ", t, "!" }

quit

そして、Caché ターミナルを使用して、テストを行います。

SAMPLES>do ^root

Team: METS

Go METS!

SAMPLES>do ^root

Team: BLUE SOX

Boo BLUE SOX!

SAMPLES>

-14-

Page 15: Caché ObjectScript チュートリアルへようこそ。 このチュートリ … · チュートリアルへようこそ。 このチュートリアルでは、強力なオブジェクト型言語の基礎と、特有の機能について学習します。

Caché ObjectScript チュートリアル

第 1 章 – Chapter13

関係演算子

If 文の条件は、真か偽に評価される論理式です。 条件は関係演算子で記述されます。

関係演算子

演算子 演算 例 (条件が真の場合)

= 等しい if (2 = 2) { write "equal" }

> より大きい if (4 > 3) { write "greater than" }

< より小さい if (3 < 4) { write "less than" }

>= より大きいか等

しい if (4 >= 3) { write "greater than or equal" }

<= より小さいか等

しい if (3 <= 3) { write "less than or equal" }

-15-

Page 16: Caché ObjectScript チュートリアルへようこそ。 このチュートリ … · チュートリアルへようこそ。 このチュートリアルでは、強力なオブジェクト型言語の基礎と、特有の機能について学習します。

Caché ObjectScript チュートリアル

第 1 章 – Chapter14

論理演算子

二項論理演算子は 2 つあり、複数の条件から構成される複合条件を評価します。 また単項論理

演算子は、条件の値を反転します。 複合条件を指定する場合、括弧を使用して式をわかりやすく

表現します。

論理演算子

演算子 演算 例 (条件が真の場合)

&& And。 条件が真になるには、すべての条

件が真である必要があります。

if (2 = 2) && (3 = 3) {write "both

are true"}

||

Or。 条件が真になるには、少なくとも 1

つの条件 (あるいは両方) が、真の必要

があります。

if (2 = 2) || (3 = 4) {write "one

is true"}

' Negation (Not)。 否定条件が真になる

には、元の条件が偽の必要があります。 if '(2 = 3) {write "unequal"}

-16-

Page 17: Caché ObjectScript チュートリアルへようこそ。 このチュートリ … · チュートリアルへようこそ。 このチュートリアルでは、強力なオブジェクト型言語の基礎と、特有の機能について学習します。

Caché ObjectScript チュートリアル

第 1 章 – Chapter15

否定演算子

否定演算子は、括弧内の条件の前、あるいは結合した関係演算子の前に使用します。

否定演算子

演算子 演算 例 (条件が真の場合)

'= 等しくない if (2 '= 3) || '(2 = 3) {write "unequal"}

'> より小さいか等しい(文字

どおり “より大きくない”)

if (2 '> 3) || '(2 > 3) {write "less than

or equal"}

'< より大きいか等しい(文字

どおり “より小さくない”)

if (3 '< 3) || '(3 < 3) {write "greater than

or equal"}

-17-

Page 18: Caché ObjectScript チュートリアルへようこそ。 このチュートリ … · チュートリアルへようこそ。 このチュートリアルでは、強力なオブジェクト型言語の基礎と、特有の機能について学習します。

Caché ObjectScript チュートリアル

第 1 章 – Chapter16

Quit コマンド

以下に、簡単なルーチンの例を示しています。 後の行に Quit コマンドが記述されています。

Quit コマンドを使用して、実行中のルーチンを終了することができます。ルーチン内の多くの場所に

Quit を配置することができ、特定の条件が Quit を引き起こします。 後に記述する必要はあり

ません。

ここでは引数なしの Quit コマンドを使用しているため(引数を持つ Quit は後ほど説明します)、コ

マンドの後に 2 つスペースを配置しています。

hello ; hello world routine

write !, "hello world"

write !, "bye"

end quit ; end

Quitコマンドはルーチンを抜ける用途もあります。 ルーチンを記述している間に、Cachéスタジオ

は文法のエラーを警告します。 一方、未定義の変数などの実行時エラーの場合は、実行中のルー

チンを終了します。 エラー・メッセージは、Caché ターミナル・ウィンドウでエラーを含む行(オフセッ

トを追加したラベル名)に表示されます。また、SAMPLES>プロンプトは SAMPLES 2d0>のように変

更されます。 そのプロンプトには意味がありますが、ここでは通常の状態にプロンプトを戻すため

Quit を入力します。

SAMPLES>do ^badroutine

write c

^

<UNDEFINED>start+3^badroutine *c

SAMPLES 2do>quit

SAMPLES>

-18-

Page 19: Caché ObjectScript チュートリアルへようこそ。 このチュートリ … · チュートリアルへようこそ。 このチュートリアルでは、強力なオブジェクト型言語の基礎と、特有の機能について学習します。

Caché ObjectScript チュートリアル

第 1 章 – Chapter17

ルーチン行の文法(1)

これまで、複数のコマンドを含む ObjectScript 行の構文について学習しました。 ルーチンの記述

に関連し、注意しなければならないことがいくつかあります。 ルーチン行はオプションとして、

ObjectScript コードの 初にラベル(タグとも呼びます)を、 後にコメントを置くことができます。

行にラベルを置く場合、タブを含む残りの行からラベル行を離す必要があります。 つまり、Caché

スタジオを使用してルーチンに行を追加し、ObjectScript コードに従ってラベルとタブを入力、ある

いはラベルを置かずにタブを入力します。 したがって、いずれの場合でも、各行は 初のコマンド

の前にタブが必要です。 行にコメントしかない場合、コメントの前にタブがきます。

Caché スタジオでは 初のコマンドの前に入力するタブはスペースでもかまいません。

hello ; hello world routine

write !, "hello world"

write !, "bye"

end quit ; end

-19-

Page 20: Caché ObjectScript チュートリアルへようこそ。 このチュートリ … · チュートリアルへようこそ。 このチュートリアルでは、強力なオブジェクト型言語の基礎と、特有の機能について学習します。

Caché ObjectScript チュートリアル

第 1 章 – Chapter18

ルーチン行の文法(2)

1 行にコメントも記述する場合、行内のその他のコード部分と区別するために、少なくとも 1 つのス

ペースを入れてから、コメントを記述する必要があります。

コメントを示す場合は、“;”または“//”を使用します。 コメントが複数行にわたる場合、コメントの

初に“/*”を、コメントの 後に“*/”を記述します。

ルーチンの 1 行目はルーチン名を表すラベルを置き、その後ろにタブ、次にルーチンの簡単な説明

がきます。

前述のように、ObjectScriptコードは改行できます。 例外として、コマンドと引数の間、あるいは1

行内のコメントは分けることができません。

既定で Caché スタジオは、ラベルを赤、ObjectScript を青、コメントを緑で表示します(例を参照)。

行の左側に赤色で構文エラーのフラグを立て、障害の原因となる行の下に赤い線を表示します。

hello ; hello world routine

write !, "hello world"

write !, "bye"

end quit ; end

-20-

Page 21: Caché ObjectScript チュートリアルへようこそ。 このチュートリ … · チュートリアルへようこそ。 このチュートリアルでは、強力なオブジェクト型言語の基礎と、特有の機能について学習します。

Caché ObjectScript チュートリアル

第 1 章 – Chapter19

初のルーチン

これまでの学習で、実際のルーチンを記述する準備ができました。 も簡単なデータ入力ルーチ

ンは、Caché スタジオ開発環境で参照できます。 まず、タスク・バーにある Caché のキューブ・ア

イコンを右クリックし、メニューから[スタジオ]を選択してください。

Cachéスタジオを使用するときは、 初にネームスペースを選択します。 Cachéターミナルで行っ

たように、[SAMPLES]を選択します。 接続すると、Caché スタジオ・インタフェースで Project1 と

呼ばれる既定(空)プロジェクトが表示されます。

Caché スタジオを以前使用したことがある場合は、 後に使用したネームスペースに接続します。

SAMPLES ネームスペースに変更するには、[ファイル]→[ネームスペース変更]をクリックします。

-21-

Page 22: Caché ObjectScript チュートリアルへようこそ。 このチュートリ … · チュートリアルへようこそ。 このチュートリアルでは、強力なオブジェクト型言語の基礎と、特有の機能について学習します。

Caché ObjectScript チュートリアル

hello と呼ばれるルーチンの例を以下に示します。 このチュートリアルにある例はすべて、

SAMPLES ネームスペースの COS プロジェクトで参照できます。 これをロードするには、[ファイ

ル]→[プロジェクトを開く]をクリックし、COS を選択します。 プロジェクトを開くと、 [ルーチン] フ

ォルダが表示され、そこに、このルーチンのソースコードである hello.mac が含まれています。

[第1章-Chapter12:If 文]で参照した root ルーチンのソースは root.mac にあります。

hello ; hello world routine

write !, "hello world"

write !, "bye"

end quit ; end

-22-

Page 23: Caché ObjectScript チュートリアルへようこそ。 このチュートリ … · チュートリアルへようこそ。 このチュートリアルでは、強力なオブジェクト型言語の基礎と、特有の機能について学習します。

Caché ObjectScript チュートリアル

第 1 章 – Chapter20

Caché スタジオ

[ファイル]→[プロジェクトの新規作成]をクリックして、新しいプロジェクトを作成します(Project1

に戻ります)。 [ファイル]→[ 近使用したプロジェクト]を使用すると、このプロジェクトとCOSプロ

ジェクトの間を簡単に行き来することができます。 保存する際、MyWork のようなもっと良い名前

をプロジェクトに付けることができます。

次に、[ファイル]→[新規作成]をクリックし、新しい ObjectScript ルーチンを作成します。

Cachéスタジオを使用して、異なる種類のファイルも作成できます(このチュートリアルでは説明して

いません)。

初めてルーチンを保存する場合、MACルーチンとして保存します。 また、Cachéスタジオを使用し

て、INC ルーチンを作成することもできます。 その違いは以下のとおりです。

• Macro ルーチン(拡張子 MAC)は ObjectScript、ObjectScript に展開するマクロ・

コード、インクルード・ルーチンへの参照を含みます。 Macro ルーチンをコンパイルし、

ObjectScript とオブジェクト・コード・バージョン(拡張子 OBJ)を含む中間ルーチンを作

成します。

• インクルード・ルーチン(拡張子 INC)は、ObjectScript マクロ定義および他のインクル

ード・ルーチンへの参照を含めることができます。 コンパイルは行いません。 コードは

Macro ルーチンからの参照によって含まれます。

-23-

Page 24: Caché ObjectScript チュートリアルへようこそ。 このチュートリ … · チュートリアルへようこそ。 このチュートリアルでは、強力なオブジェクト型言語の基礎と、特有の機能について学習します。

Caché ObjectScript チュートリアル

第 1 章 – Chapter21

演習1

演習 1 では、以下の項目に沿って小規模なデータ入力ルーチンを作成します。

• 3 つのプロンプト Name、Phone (US スタイル)、Date of Birth を作成します。

• Write コマンドを使用して、以下の形式で入力されたデータを表示します。

Name: John Smith

Phone: 555-1111

DOB: 1/23/45

• Name プロンプトと Phone プロンプトの間に 1 行挿入し、ユーザが Name プロンプト

に何も入力せずに Enter を押したかどうかを判断します。 この場合、ルーチンを終了し

ます。

• [ファイル]→[プロジェクトを保存]をクリックし、[ビルド]→[コンパイル]でルーチンをコ

ンパイルします。

• Caché ターミナル・セッションを開始し、ルーチンを実行(Do)します。

詳細は、[Appendix D: 演習 1 : 初のデータ入力ルーチン] を参照してください。

-24-

Page 25: Caché ObjectScript チュートリアルへようこそ。 このチュートリ … · チュートリアルへようこそ。 このチュートリアルでは、強力なオブジェクト型言語の基礎と、特有の機能について学習します。

Caché ObjectScript チュートリアル

第 1 章 – Chapter22

ルーチン・フローの制御

ルーチン・フローを制御するには、条件付きでコードを実行するか、もしくは特定のコード・セクション

を経由する方法があります。 また、特定のコード・セクションを繰り返し実行させる方法も必要です。

前述した If 文は、条件を評価する基本的な方法です。 ここでは、If 文に代わるコードを繰り返し

実行するいくつかの方法を学習します。

演習では、If 文の条件が真の場合にのみ特定の処理を行う、つまり Quit コマンドでルーチンを終

了するというコードを学習しました。 しかし If 文を使用して、複数のコマンドを含むコード・ブロック

を実行するか、あるいは経由する方が適切です。 また、1 つのコマンドに条件を付ける場合は、後

置条件コマンドを使用することもできます。これまで学習してきたすべてのコマンド(If 文は除く)は、

コロンや条件が後ろに続き、単純であったり、あるいは必要に応じて複雑であったりします。 コマン

ドは、条件が真の場合にのみ実行します。

後置条件内にスペースを挿入するには、条件を括弧で囲みます。

postcond ; postconditionals versus If construct

if name="" { quit } ; you should replace this

quit:(name = "") ; with this postconditional

if name="" { write "...Exiting" quit } ; 2 commands after the if,

; so do this

write:name="" "...Exiting" quit:name="" ; instead of this

-25-

Page 26: Caché ObjectScript チュートリアルへようこそ。 このチュートリ … · チュートリアルへようこそ。 このチュートリアルでは、強力なオブジェクト型言語の基礎と、特有の機能について学習します。

Caché ObjectScript チュートリアル

第 1 章 – Chapter23

$Case 関数

$Case 関数は式 ( 初の引数) を評価し、式の値 (残りの引数) に対応する結果を返します。

式に一致する引数値が存在しない場合、 後の引数が既定値として返されます。

初の例のように$Case 関数はリテラル値を返します。 また、2 番目の例のように Do コマンド

の引数として使用している場合は、プロシージャ名あるいはルーチン名を返します。

SAMPLES>set surv = 3

SAMPLES>write $case( surv, 1:"Rich", 2:"Kelly", 3:"Rudy", 4:"Sue", :"")

Rudy

SAMPLES>set surv = 1

SAMPLES>do $case( surv, 1:celebrate^survivor() , :complain^survivor() )

Yippee! I won!

SAMPLES>

以下は survivor.mac のコードです。

survivor ; celebrate or complain

celebrate() PUBLIC

{ Write !, "Yippee! I won!" }

complain() PUBLIC

{ write !, "Oh well, I lost." }

complain() PUBLIC { write !, "Oh well, I lost." }

-26-

Page 27: Caché ObjectScript チュートリアルへようこそ。 このチュートリ … · チュートリアルへようこそ。 このチュートリアルでは、強力なオブジェクト型言語の基礎と、特有の機能について学習します。

Caché ObjectScript チュートリアル

第 1 章 – Chapter24

For 文(1)

For 文を使用すると、コードのセクションを繰り返し実行できます。 以下は For の引数の構文です。

変数、開始値、増分値、終了値が割り当てられています。 すべての値は正、または負で、コロンで

区切られています。 For に続くコード・ブロックは、変数に割り当てられた各値を繰り返します。

また、For の引数にリストの値を割り当てることもできます。 この場合、コード・ブロックはそれぞれ

のリスト項目を、変数に繰り返し割り当てます。 他の文と同様、For 文はコンマで区切られた複数

の引数を持つことができます。 また、1 つの For 文にカウンタとリスト引数の両方を持つことができ

ます。

SAMPLES>do ^forexample

I 1 the sandbox.

I 2 the sandbox.

I 3 the sandbox.

I 4 the sandbox.

I 5 the sandbox.

I 6 the sandbox.

I 7 the sandbox.

I 8 the sandbox.

Was John the leader? y

Was Paul the leader? n

Was George the leader? n

Was Ringo the leader? n

forexample.mac コードのパート 1 は以下のとおりです。

forexample ; examples of the for construct

for i = 1:1:8 {

write !, "I ", i, " the sandbox."

}

write !!

for b = "John", "Paul", "George", "Ringo" {

write !, "Was ", b, " the leader? "

read yn

}

-27-

Page 28: Caché ObjectScript チュートリアルへようこそ。 このチュートリ … · チュートリアルへようこそ。 このチュートリアルでは、強力なオブジェクト型言語の基礎と、特有の機能について学習します。

Caché ObjectScript チュートリアル

第 1 章 – Chapter25

For 文(2)

ここでは For 文について詳細に学習します。 値を終了せずに For のカウンタ引数を指定できます。

通常、これは無限ループとなります。 しかし、コード・ブロック内に Quit コマンドを配置し、For 文

を終了させることができます。 For 文中の Quit コマンドが For ループを終了させるため、繰り

返し処理を実行できます。 この場合、繰り返し内でカウンタを使用します。 しかし、カウンタ値を条

件にしないFor文も制御できます。 カウンタの必要がない場合、引数なしのFor文を使用します。

以下の例では、 初の For 文は If 文を含みます。

forexample 例は以下のとおり続きます。

Capital of MA? BAHSTON

Capital of MA? WORCESTER

Capital of MA? SPRINGFIELD

Capital of MA? BOSTON...did it in 4 tries

Know what? WHAT? That's what!

Know what? WHAT? That's what!

Know what? WHAT? That's what!

Know what? NO!

SAMPLES>

forexample.mac コードのパート 2 は以下のとおりです。

for i = 1:1 {

read !, "Capital of MA? ", a

if a = "BOSTON" {

write "...did it in ", i, " tries"

quit

}

}

write !!

for {

read !, "Know what? ", wh

quit:(wh = "NO!")

write " That's what!"

}

-28-

Page 29: Caché ObjectScript チュートリアルへようこそ。 このチュートリ … · チュートリアルへようこそ。 このチュートリアルでは、強力なオブジェクト型言語の基礎と、特有の機能について学習します。

Caché ObjectScript チュートリアル

第 1 章 – Chapter26

WHILE 文と DO/WHILE 文

While 文や Do/While 文を使用して、引数なしの For 文と同様のコードを繰り返し実行し、条件

を元に終了させることができます。 While と Do/While の違いは、条件の評価をコード・ブロッ

クの前に行うか(While)後で行うか(Do/While)です。For 文と同様、コード・ブロック内に Quit

コマンドを記述してループを終了できます。以下はその構文です。

do {code} while condition

while condition {code}

SAMPLES>do ^fibonacci

Generate Fibonacci sequence up to where? 100

1 2 3 5 8 13 21 34 55 89

1 2 3 5 8 13 21 34 55 89

SAMPLES>

fibonacci.mac コードは以下のとおりです。

fibonacci ; generate Fibonacci sequences

read !, "Generate Fibonacci sequence up to where? ", upto

set t1 = 1, t2 = 1, fib = 1

write !

do {

write fib," " set fib = t1 + t2, t1 = t2, t2 = fib

}

while ( fib '> upto )

set t1 = 1, t2 = 1, fib = 1

write !

while ( fib '> upto ) {

write fib," " set fib = t1 + t2, t1 = t2, t2 = fib

}

-29-

Page 30: Caché ObjectScript チュートリアルへようこそ。 このチュートリ … · チュートリアルへようこそ。 このチュートリアルでは、強力なオブジェクト型言語の基礎と、特有の機能について学習します。

Caché ObjectScript チュートリアル

第 1 章 – Chapter27

プロシージャ

他のプログラミング言語と同様、プロシージャは特定のタスクを実行する一連の ObjectScript コ

マンド(大規模なルーチン)です。 If文の構造のように、プロシージャのコードは中括弧({})で囲ま

れています。

既定では、プロシージャはプライベートであるため、同じルーチン内でのみ呼び出すことができます。

しかし、プロシージャ名の後ろに PUBLIC キーワードを指定すると、パブリック・プロシージャも生成

できます。 パブリック・プロシージャは他のルーチンからも呼び出せます。

プロシージャでは、定義済みのパラメータは必要ありません。 パラメータ付きでプロシージャを生成

する場合、ラベルの直後に括弧で囲んだ変数リストを置きます。

プロシージャでパラメータを取得し、値を返すユーザ関数の記述方法は後で学習します。

SAMPLES>do ^procexample

Enter a number: 4

setting a

setting b

setting c

setting d

SAMPLES>do proc2^procexample(7)

my favorite number is 7

SAMPLES>

-30-

Page 31: Caché ObjectScript チュートリアルへようこそ。 このチュートリ … · チュートリアルへようこそ。 このチュートリアルでは、強力なオブジェクト型言語の基礎と、特有の機能について学習します。

Caché ObjectScript チュートリアル

以下は、procexample.mac コードです。

procexample ; examples of procedures

read !, "Enter a number: ", x

if x = 4 {do proc1()} ; call a procedure

quit ; end of the main routine

proc1() ; a private procedure

{

write !, "setting a" set a = 1

write !, "setting b" set b = 2

write !, "setting c" set c = 3

write !, "setting d" set d = 4

}

proc2(num) PUBLIC

; a public procedure with a parameter

{ write !, "my favorite number is ",num }

-31-

Page 32: Caché ObjectScript チュートリアルへようこそ。 このチュートリ … · チュートリアルへようこそ。 このチュートリアルでは、強力なオブジェクト型言語の基礎と、特有の機能について学習します。

Caché ObjectScript チュートリアル

第 1 章 – Chapter28

プロシージャ変数

プロシージャ内で使用される変数は、自動的にそのプロシージャに対してプライベートになります。

つまり、その範囲はプロシージャに対してローカルになります。 変数の宣言は必要ありません。 こ

のプロシージャが呼び出すプロシージャの変数を共有したい場合、変数をパラメータとして他のプロ

シージャに渡します。

パブリック変数の宣言も可能です。 パブリック変数は、プロシージャの呼び出し元と呼び出し先の

すべてのプロシージャで共有されます。 アプリケーションで環境変数として動作するよう、比較的少

数のパブリック変数を定義します。 パブリック変数を定義するには、プロシージャ名とパラメータの

後に大括弧内([ ])で変数をリストします。

SAMPLES>w

SAMPLES>d ^publicvarsexample

setting a

setting b

setting c

The sum is: 6

SAMPLES>w

a=1

b=2

SAMPLES>

-32-

Page 33: Caché ObjectScript チュートリアルへようこそ。 このチュートリ … · チュートリアルへようこそ。 このチュートリアルでは、強力なオブジェクト型言語の基礎と、特有の機能について学習します。

Caché ObjectScript チュートリアル

以下は、procexample.mac のコードです。

publicvarsexample

; examples of public variables

;

do proc1() ; call a procedure

quit ; end of the main routine

;

proc1() [a, b]

; a private procedure

; "c" and "d" are private variables

{

write !, "setting a" set a = 1

write !, "setting b" set b = 2

write !, "setting c" set c = 3

set d = a + b + c

write !, "The sum is: ", d

}

-33-

Page 34: Caché ObjectScript チュートリアルへようこそ。 このチュートリ … · チュートリアルへようこそ。 このチュートリアルでは、強力なオブジェクト型言語の基礎と、特有の機能について学習します。

Caché ObjectScript チュートリアル

第 1 章 – Chapter29

多目的文字

次の演習を開始する前に、ここではもう 1 つ別の内容について学習します。ObjectScript には、多

目的に使用できる文字があります。 以下はその概要です。

文字 目的

? Write 用タグ。 パターン・マッチ演算子の 1 つ(後で学習します)。

: (コロン) Read用タイマー。 すべてのコマンドに対する後置条件。 For文用カウ

ンタ指定。

# Read コマンド用固定長。 算術式用モジュロ演算子。

. (ピリオド) オブジェクトメンバ・セパレータ(後で学習します)。 パターン・マッチ演算

子用範囲指定子(後で学習します)。

^ (キャレット) Do コマンド用ルーチン接頭語。 グローバル接頭語(後で学習します)。

-34-

Page 35: Caché ObjectScript チュートリアルへようこそ。 このチュートリ … · チュートリアルへようこそ。 このチュートリアルでは、強力なオブジェクト型言語の基礎と、特有の機能について学習します。

Caché ObjectScript チュートリアル

第 1 章 – Chapter30

演習 2

演習 2 では、前回の演習で記述した mydatent ルーチンに修正を加えます。

• 新規プロシージャ prompt を作成し、既に存在する 3 つのプロンプトを持たせます。

新規プロシージャ display に表示コードを記入します。 パブリック変数を使用し、両方

のプロシージャで変数を共有できるようにします。

• ループ内のルーチンの中で上位レベルに main ルーチンを置き、prompt と display

プロシージャを呼び出します。 上位レベルのループは、ユーザが Name プロンプトに

何も入力しない場合は終了します。

• ルーチンの新しいバージョンを保存し、起動します。

詳細は、[Appendix E: 演習 2 : 2 番目のデータ入力ルーチン] を参照してください。

-35-

Page 36: Caché ObjectScript チュートリアルへようこそ。 このチュートリ … · チュートリアルへようこそ。 このチュートリアルでは、強力なオブジェクト型言語の基礎と、特有の機能について学習します。

Caché ObjectScript チュートリアル

第 1 章 – Chapter31

第 1 章の要約

第 1 章で学習したことは以下のとおりです。

• ObjectScript ルーチンの構造

• Caché ターミナルと Caché スタジオの使用方法

• 後置条件を含む引数なしの Write、Read、Set、Kill、Do および Quit などの

ObjectScript コマンド

• If、For、While、Do/While などの ObjectScript 構文

• 適切な構文と一般的なエラー

• プロシージャ

-36-

Page 37: Caché ObjectScript チュートリアルへようこそ。 このチュートリ … · チュートリアルへようこそ。 このチュートリアルでは、強力なオブジェクト型言語の基礎と、特有の機能について学習します。

Caché ObjectScript チュートリアル

第 2 章

便利な機能

この章では、Caché ObjectScript が提供する独自の機能について学習します。

第 2 章では、ObjectScript を強力にする以下の機能について学習します。

• 文字列(数字やリストを含めすべてのデータは文字列であること)

• パターン・マッチング演算子

• 多機能な文字列とリスト

• 日付の機能

• 特殊関数の記述法

• Caché デバッガの使用法

• 配列、ツリー構造、グローバル変数の存在のテスト法

• データベースとインデックスの簡単な作成方法

-37-

Page 38: Caché ObjectScript チュートリアルへようこそ。 このチュートリ … · チュートリアルへようこそ。 このチュートリアルでは、強力なオブジェクト型言語の基礎と、特有の機能について学習します。

Caché ObjectScript チュートリアル

第 2 章-Chapter1

文字列

第 1 章では ObjectScript の例を参照し、変数を利用したコードの記述方法を学習してきました。

また、変数に文字列と数値を代入する方法も学習してきました。ObjectScript には宣言文は必要

ありません。 また他言語と異なりデータの型(例えば文字列型、数値型など)はありません。 すべ

てのデータ(値と変数)は、プログラムの内容により適切に解釈され、使用されます。

ObjectScriptは、数式内の文字列を数値として評価します。 変数に数値が割り当てられた場合、

文字と異なり引用符は必要ありません。 例えば“fred”では、この文字列に 3 を加算する場合、

ObjectScript は“fred”を 0 と解釈します。 これは、“fred”には先頭から連続する数字が含まれ

ていないからです。 一方、文字列 “32hut”を 4 で除算する場合、“32hut”は 32 と解釈されます。

これは、“32hut” という文字列が先頭から32という数字を含むからです。 文字列がどのように数

値として解釈されるかは、プラスの算術演算子で確認できます。 また、算術演算子(ここでは+)が

引用符で囲まれていない場合、演算対象値が引用符に囲まれているかどうかにかかわらず、数値

として解釈します。

特別なコマンドを使用しない限り、変数は大文字と小文字を区別します。

SAMPLES>set x = 4 write x + 2

6

SAMPLES>set x = "5" write x * 2

10

SAMPLES>set x = "fred" write x + 3

3

SAMPLES>set x = "32hut" write x / 4

8

SAMPLES>write +x

32

SAMPLES>write 5 + 2, ?10, "5" + "2" , ?20, "5 + 2"

7 7 5 + 2

SAMPLES>

-38-

Page 39: Caché ObjectScript チュートリアルへようこそ。 このチュートリ … · チュートリアルへようこそ。 このチュートリアルでは、強力なオブジェクト型言語の基礎と、特有の機能について学習します。

Caché ObjectScript チュートリアル

第 2 章-Chapter2

文字列の格納

ObjectScript では、通常の変数を使用するのと同様に、簡単にデータをディスクに格納できます。

このためには、変数名の先頭にサーカムフレックス(^)を付けます。以下の例では、通常の変数 x と

は異なる変数^x で文字列を保存します。 通常の変数のすべてで Kill を実行しても^x は残ります。

詳細は後で学習します。

SAMPLES>set x = 4

SAMPLES>set ^x = "Store this on disk"

SAMPLES>kill

SAMPLES>write

SAMPLES>write ^x

Store this on disk

SAMPLES>

-39-

Page 40: Caché ObjectScript チュートリアルへようこそ。 このチュートリ … · チュートリアルへようこそ。 このチュートリアルでは、強力なオブジェクト型言語の基礎と、特有の機能について学習します。

Caché ObjectScript チュートリアル

第 2 章-Chapter3

連結演算子

初の文字列演算子は結合演算子(_)です。 これは単一の文字列に複数の文字列を結合しま

す。

SAMPLES>set a = "license", b = "to", c = "speed", d = " ", e = "!"

SAMPLES>set s=a _ d _ b _ d _ c _ e

SAMPLES>write s

license to speed!

SAMPLES>

-40-

Page 41: Caché ObjectScript チュートリアルへようこそ。 このチュートリ … · チュートリアルへようこそ。 このチュートリアルでは、強力なオブジェクト型言語の基礎と、特有の機能について学習します。

Caché ObjectScript チュートリアル

第 2 章-Chapter4

パターン・マッチ演算子

2 つ目はパターン・マッチ演算子(?)で、これは ObjectScript の も重要で有効な機能の 1 つです。

この関係演算子は、ユーザが入力した文字列がパターンと正確に一致しているかどうかを検査しま

す。 パターン指定には 1 つ、あるいはそれ以上のパターンを組み合わせて使用できます。 以下

の構文を使用します。

<Quantity><Code>[<Quantity><Code>]...

さらに、それぞれをコンマで区切りながら複数のパターンの一部を括弧で囲み、代替のリストを作成

できます。 括弧で囲んだ数量のセクションを前に置くと、仕様内でオプションのサブパターン、ある

いは繰り返しのサブパターンとみなされます。

数量 意味 - コード 意味 コード 意味

3 ちょうど 3 A アルファベット (大文字あ

るいは小文字) C 制御文字

1.3 1 から 3 U 大文字 E すべての文字

.3 大 3 L 小文字 ANP コードの組み合わせ

3. 小 3 N 数値 “anp” リテラル文字

. 0 を含むす

べての値 P 句読点

テーブル内のパターン・マッチ・コードの既定値は英語です。 Caché ロケールを使用して別の言語

の代替コードを指定します。 ロケールの説明は、このチュートリアルでは触れていません。

-41-

Page 42: Caché ObjectScript チュートリアルへようこそ。 このチュートリ … · チュートリアルへようこそ。 このチュートリアルでは、強力なオブジェクト型言語の基礎と、特有の機能について学習します。

Caché ObjectScript チュートリアル

第 2 章-Chapter5

パターン・マッチングの例

ここではパターンの例をいくつか示し、パターン・マッチング演算子がどのように機能するかを学習し

ます。

• 社会保障番号の形式は、3桁の数字、ハイフン、2桁の数字、ハイフン、4桁の数字です。

初心者が間違いやすいパターンは、3N"-"2N"-"4N あるいは 3N1P2N1P4N です。

前者はハイフン記号の数の指定が足りず、後者はすべての句読記号を許可していま

す。

• フィートやインチなど高さの単位は、文字でも記号でも表記することができます。 引用

符を引用文の中に含むには(変数 ht2 とパターン)、二重に引用符を記述します。

• 通常、姓は文字のみで表記されますが、記号や数を含む場合もあります。 .ANP パタ

ーンは、姓もしくは姓以外の文字列も認識します (偽陽性)。

• 文字列の 初の文字のみを検証したい場合、.Eで終わるパターンを記述します。 これ

は、後に続く文字列はどのような文字でも何文字あってもよいということを表していま

す。

SAMPLES>set ssn = "012-34-5678"

SAMPLES>if ssn?3N1"-"2N1"-"4N write "valid"

valid

SAMPLES>set ht1 = "6 feet 2 inches", ht2 = "5'3"""

SAMPLES>if ht1?1N1(1" feet",1"'").1" "1N1(1" inches",1"""") {write "valid"}

valid

SAMPLES>if ht2?1N1(1" feet",1"'").1" "1N1(1" inches",1"""") {write "valid"}

valid

SAMPLES>set last1 = "O'Reilly-McMahon 3rd", last2 = "/////32351abcde"

SAMPLES>if last1?.ANP {write "valid"} ; good name

valid

SAMPLES>if last2?.ANP {write "valid"} ; bad name

valid

SAMPLES>set c="InterSystems" if c?1"Inter".E {write "valid"}

valid

SAMPLES>

-42-

Page 43: Caché ObjectScript チュートリアルへようこそ。 このチュートリ … · チュートリアルへようこそ。 このチュートリアルでは、強力なオブジェクト型言語の基礎と、特有の機能について学習します。

Caché ObjectScript チュートリアル

第 2 章-Chapter6

複合パターン・マッチング

以下の複合パターンを使用すると、.ANP が受け入れた文字列を拒否する一方で、前の例

(O'Reilly-McMahon 3rd)のような姓を検証できます。 この例では、間接指定演算子@と共にパ

ターン・マッチを使用してパターンのコンポーネントを明確にしています。 間接演算の説明は、この

チュートリアルの対象ではありません。

SAMPLES>set lastname = ".1(1""O'"",1""Mc"")1U.L"

SAMPLES>set hyphenname = ".1(1""-"".1(1""O'"",1""Mc"")1U.L)"

SAMPLES>set title = ".1(1"" ""1(1""Sr"",1""Jr"",1""3rd"",1""4th""))"

SAMPLES>set complete = lastname _ hyphenname _ title

SAMPLES>if last1?@complete {write "valid"}

valid

SAMPLES>if last2?@complete {write "valid"}

SAMPLES>

-43-

Page 44: Caché ObjectScript チュートリアルへようこそ。 このチュートリ … · チュートリアルへようこそ。 このチュートリアルでは、強力なオブジェクト型言語の基礎と、特有の機能について学習します。

Caché ObjectScript チュートリアル

第 2 章-Chapter7

文字列関数(1)

ObjectScript は、文字列を操作するための関数を提供しています。 他言語と同様に、関数はパ

ラメータを受け取り、結果を返します。 ここでは、よく利用される関数をいくつか紹介します。

• $Length は文字列の長さを返します。

• $Extract は、開始位置と終了位置から部分文字列を返します。

• $Find は、文字列内の部分文字列を検索し、部分文字列の次の 文字位置を返しま

す。

• $Piece は、区切り記号を使用して文字列を区分けし、部分文字列を返します。

• $Justify は、指定された長さの文字列を右揃えして返し、小数点の丸め位置も指定し

ます。

SAMPLES>write $length("how long is this?")

17

SAMPLES>write $extract("there's gold in them hills", 9, 12)

gold

SAMPLES>write $find("there's gold in them hills", "gold")

13

SAMPLES>write $piece("slice of pizza", " ", 3)

pizza

SAMPLES>write $justify(3.1415, 10, 3)

3.142

SAMPLES>

各関数は他の書式でも記述できます。 詳細は Caché ドキュメントを参照してください。関数はコマ

ンドと同様に大文字と小文字の区別はなく、略書きも可能です。

-44-

Page 45: Caché ObjectScript チュートリアルへようこそ。 このチュートリ … · チュートリアルへようこそ。 このチュートリアルでは、強力なオブジェクト型言語の基礎と、特有の機能について学習します。

Caché ObjectScript チュートリアル

第 2 章-Chapter8

文字列関数(2)

$Piece には他にも特徴があります。 一つの部分文字列だけでなく、指定した範囲の一連の部分

文字列を返します。同じ文字列から、異なる区切り文字を使用して分文字列を返すこともできます。

$Piece は返り値が空の場合、空文字列を返します(1 つ目の区切り文字の前に何も無い場合や、

1 つ目と 2 つ目の区切りの間に値がない場合)。

$Piece 関数を使用して 1 つの文字列に複数の部分文字列を含ませ、任意の区切り文字(例えば

“^”)で、文字列を分割できます。 長い文字列はレコードとして、部分文字列はそのフィールドとし

て動作します。 また、$Length には部分文字型の変異形があり、区切りを元にして文字列内の

部分文字列数を返します。

SAMPLES>write $piece("slice of pizza", " ", 1, 2)

slice of

SAMPLES>write $piece("slice of pizza", "i", 2)

ce of p

SAMPLES>write $piece("slice of pizza", "z", 2)

SAMPLES>set city=$piece("One Memorial Drive^Cambridge^MA^02142", "^", 2)

SAMPLES>write city

Cambridge

SAMPLES>write $length("slice of pizza", " ")

3

SAMPLES>

-45-

Page 46: Caché ObjectScript チュートリアルへようこそ。 このチュートリ … · チュートリアルへようこそ。 このチュートリアルでは、強力なオブジェクト型言語の基礎と、特有の機能について学習します。

Caché ObjectScript チュートリアル

第 2 章-Chapter9

リスト

これまで ObjectScript のすべてのデータが、文字列であることを学習しました。 リストとは、部分

文字列のリストを形成する特殊な文字列です。 ここでは、List 関数を学習します(これらの List 関

数は文字列関数に類似しています)。

• $ListBuild は、1 つ以上の部分文字列から生成されたリストを返します。

• $List はリストで指定された要素を返します。

• $ListLength は、リストの要素数を返します。

• $ListFind は、部分文字列のリストを検索し、要素数を返します。

SAMPLES>set addr = "One Memorial Drive", city = "Cambridge"

SAMPLES>set st = "MA", zip = "02142"

SAMPLES>set mail = $listbuild(addr, city, st, zip)

SAMPLES>write $list(mail, 2)

Cambridge

SAMPLES>write $listlength(mail)

4

SAMPLES>write $listfind(mail, "MA")

3

SAMPLES>

通常の文字列ではList関数は使用できません。使用すると、<LIST>エラーが発生します。同様に、

リストに対して文字列関数を使用しません。 List 関数は 2 文字の略語で表示できます。

-46-

Page 47: Caché ObjectScript チュートリアルへようこそ。 このチュートリ … · チュートリアルへようこそ。 このチュートリアルでは、強力なオブジェクト型言語の基礎と、特有の機能について学習します。

Caché ObjectScript チュートリアル

第 2 章-Chapter10

部分文字列とリストの比較

これまで、リストのような機能を提供する$Piece と区切り文字について学習しました。区切り文字

を使用したくない場合に、リストは便利です。 区切り文字を使う場合、部分文字列が区切り文字を

含み、部分文字列のリスト内の位置を返す可能性があります。 リストはこれを防ぎます。

以下で、2 つの方法を比較して見てみましょう。 部分文字型関数は、類似のリスト型関数を持って

います。その違いは区切り文字の有無によります。 ここでは、$ListFind が$Find よりも便利で

す。 $ListBuild で構築される変数 Lmail は Write コマンドで表示できますが、制御文字を含

むため、お勧めできません。 したがって、専用の List 関数を使用してリストにアクセスするようにし

ます。 Caché ターミナルを使用してリストで作業する場合は、%r ルーチンを使用してリストの内

容(単純変数、配列、またはグローバル内)を表示できます。

SAMPLES>set addr = "One Memorial Drive"

SAMPLES>set city = "Cambridge" ; for both examples below

SAMPLES>set st = "MA", zip = "02142" ; for both examples below

SAMPLES>set Pmail = addr _ "^" _ city _ "^" _ st _ "^" _ zip

SAMPLES>set Lmail = $listbuild(addr, city, st, zip)

SAMPLES>write $piece(Pmail, "^", 2), ?20, $list(Lmail, 2)

Cambridge Cambridge

SAMPLES>write $length(Pmail, "^"), ?20, $listlength(Lmail)

4 4

SAMPLES>write $find(Pmail, "MA"), ?20, $listfind(Lmail, "MA")

32 3

SAMPLES>write Pmail

One Memorial Drive^Cambridge^MA^02142

SAMPLES>do ^%r

Array: Lmail

Device:

Right margin: 80 =>

Lmail=$lb("One Memorial Drive","Cambridge","MA","02142")

-47-

Page 48: Caché ObjectScript チュートリアルへようこそ。 このチュートリ … · チュートリアルへようこそ。 このチュートリアルでは、強力なオブジェクト型言語の基礎と、特有の機能について学習します。

Caché ObjectScript チュートリアル

第 2 章-Chapter11

部分文字列、部分文字、リスト項目の設定

これまで、文字列の一部を検索するために、関数$Extract、$Piece と$List を使用しました。

Set コマンドでこれら 3 つの関数を使用すると、文字列内に部分文字列を埋め込むことができます。

以下は変数がまだ存在していない場合に、関数を使用する例です。

Set $Extract は、空文字列の途中に部分文字列を設定する場合に、文字列の左を空白で埋め

ます。新、旧文字列の長さが同じかどうかにかかわらず、指定された部分文字列に特定の文字を置

き換えます。

SAMPLES>set $extract(empty, 4) = "abcde"

SAMPLES>write empty

abcde

SAMPLES>set $extract(empty, 4, 5) = "12345"

SAMPLES>write empty

12345cde

SAMPLES>

Set $Piece は十分な区切り文字を追加し、空文字列に適切な部分文字列を割り当てます。 異

なる区切り文字を使用すると、部分文字列の一部も抽出できます。 部分文字列の一部を検索する

には、$Piece 関数を入れ子にします。

SAMPLES>set $piece(empty, "^", 3) = "abcde" write empty

^^abcde

SAMPLES>write $length(empty, "^")

3

SAMPLES>set $piece(empty, "^", 2) = "9/9/1999" write empty

^9/9/1999^abcde

SAMPLES>write $piece( $piece(empty, "^", 2), "/", 3)

1999

SAMPLES>

-48-

Page 49: Caché ObjectScript チュートリアルへようこそ。 このチュートリ … · チュートリアルへようこそ。 このチュートリアルでは、強力なオブジェクト型言語の基礎と、特有の機能について学習します。

Caché ObjectScript チュートリアル

Set $List はリストの項目を追加する構文で、空のリストに項目となる部分文字列をセットします。

1つのリスト項目でも、1つのリストになります。 部分文字列を検索するには、$List関数を入れ子

にします。

SAMPLES>set $list(empty, 3) = "abcde"

SAMPLES>write $listlength(empty)

3

SAMPLES>set $list(empty, 2)=$listbuild(9, 9, 1999)

SAMPLES>write $list( $list(empty, 2), 3)

1999

SAMPLES>

-49-

Page 50: Caché ObjectScript チュートリアルへようこそ。 このチュートリ … · チュートリアルへようこそ。 このチュートリアルでは、強力なオブジェクト型言語の基礎と、特有の機能について学習します。

Caché ObjectScript チュートリアル

第 2 章-Chapter12

新しい v5.1 の List 関数

バージョン 5.1 以降にはリストで作業するための以下の新しい関数が追加されています。

• $ListFromString は、区切り文字列から生成されたリストを返します。

• $ListToString は、リストから生成された区切り文字列を返します。

• $ListSame は、2 つのリストを比較し、リストが同一の場合、1 を返します。 同一でな

い場合は、0 を返します。

• $ListNext は、1 つのリスト項目を次の項目に順次進めます。

Note:

$ListNext 関数は、呼び出し毎に、その 2 番目と 3 番目の引数値を変更します。

SAMPLES>set addr = "One Memorial Drive", city = "Cambridge"

SAMPLES>set st = "MA", zip = "02142"

SAMPLES>set Pmail = addr _ "^" _ city _ "^" _ st _ "^" _ zip

SAMPLES>set Lmail = $listfromstring(Pmail, "^")

SAMPLES>write $list(Lmail, 2)

Cambridge

SAMPLES>write $listlength(Lmail)

4

SAMPLES>write $listfind(Lmail, "MA")

3

SAMPLES>set Pmail = $listtostring(Lmail,"*")

SAMPLES>write Pmail

One Memorial Drive*Cambridge*MA*02142

SAMPLES>set Lmail2 = $listbuild("One Memorial Drive","Cambridge","MA","02141")

SAMPLES>write $listsame(Lmail, Lmail2)

0

SAMPLES>set p = 0 while $listnext(Lmail,p,value) { write !, value }

One Memorial Drive

Cambridge

MA

02142

-50-

Page 51: Caché ObjectScript チュートリアルへようこそ。 このチュートリ … · チュートリアルへようこそ。 このチュートリアルでは、強力なオブジェクト型言語の基礎と、特有の機能について学習します。

Caché ObjectScript チュートリアル

ビット文字列とは、圧縮された一連のビットで構成される、もう 1 つの特別な文字列です。 32K の

変数には 256K ビットまで格納できます。 ビット文字列の作成および作業用に、以下の特別な関

数が用意されています。

• $Bit は、ビットを取得するか、ビットを 1 または 0 に設定します (Set と共に使用)。

• $BitCount はビットをカウントします。

• $BitFind は、特定の値(1 または 0)を持つ次のビットを検索します。

• $BitLogic は、ビット文字列に対してビット演算(and、or、not、xor)を実行します。

• $Factor は、整数を ASCII ビット文字列に変換します。

ビット文字列は圧縮されているため、Write は使用しないでください。 代わりに $Bit を使用する

か、リストと同様に%r を使用できます。

SAMPLES>for i=1:1:40 {set $bit(b, i) = $random(2)}

SAMPLES>write $length(b)

9

SAMPLES>write $bitcount(b, 0)

23

SAMPLES>write $bitcount(b, 1)

17

SAMPLES>for i = 1:1:40 {write $bit(b, i)}

0100110001000110101011001100010010000111

SAMPLES>write $bitfind(b, 1, 1) // find the first 1 bit

2

SAMPLES>write $bitfind(b, 0, 1) // find the first 0 bit

1

SAMPLES>write $bitfind(b, 1, 3) // find the next 1 bit

5

SAMPLES>for i = 1:1:40 {set $bit(c, i) = $random(2)}

SAMPLES>set d = $bitlogic(b & c)

SAMPLES>for i = 1:1:40 {write $bit(b, i)}

0100110001000110101011001100010010000111

第 2 章-Chapter13

ビット文字列

-51-

Page 52: Caché ObjectScript チュートリアルへようこそ。 このチュートリ … · チュートリアルへようこそ。 このチュートリアルでは、強力なオブジェクト型言語の基礎と、特有の機能について学習します。

Caché ObjectScript チュートリアル

SAMPLES>for i = 1:1:40 {write $bit(c, i)}

0111001111001011110100100110101110111011

SAMPLES>for i = 1:1:40 {write $bit(d, i)}

0100000001000010100000000100000010000011

SAMPLES>set f = $factor(23456)

SAMPLES>d ^%r

Array: f

Device:

Right margin: 80 =>

f=$c(128,0,4,0)_" ["_$c(0,0)/*$bit(000001011101101)*/

-52-

Page 53: Caché ObjectScript チュートリアルへようこそ。 このチュートリ … · チュートリアルへようこそ。 このチュートリアルでは、強力なオブジェクト型言語の基礎と、特有の機能について学習します。

Caché ObjectScript チュートリアル

第 2 章-Chapter14

日付(1)

ObjectScript は、12/31/1840 を示す 0 から始まり、12/31/9999 を示す 2980013 までの整

数値を各日付に割り当てます。 1/1/2002 の場合は 58805 が割り当てられます。 使用可能な

外部形式の数値から(内部)整数形式に(あるいはその逆に)日付を変換するルーチンと関数があり

ます。 詳細は Caché ドキュメントを参照してください。 同様に、ObjectScript は毎日深夜から毎

秒カウントし、時刻の変換ルーチンと関数を提供します。

日付関数に関連した ObjectScript システム変数は、$Horolog と呼ばれています。システム変

数は引数を持たない関数のように動作します。 $Horolog は、アクセスされた時点の日付と時刻

をコンマで結合した形で表示します。 日付ルーチンと関数、および$Horolog により、ユーザがさ

まざまな形式で日付を入力しても、その内容が有効かどうかを検証し、日付演算を処理します。

-53-

Page 54: Caché ObjectScript チュートリアルへようこそ。 このチュートリ … · チュートリアルへようこそ。 このチュートリアルでは、強力なオブジェクト型言語の基礎と、特有の機能について学習します。

Caché ObjectScript チュートリアル

第 2 章-Chapter15

日付(2)

日付関数には$ZDate(内部形式から外部形式へ)と$ZDateH (外部形式から内部形式へ)があ

ります。 日付関数には複数の引数があります。 詳細は Caché ドキュメントを参照してください。

このチュートリアルでは、1 番目(変換される内部日付、もしくは外部日付)、2 番目(外部形式コー

ド)、9 番目(返り値のエラー・コード)の引数について学習します。

初の例は、有効な日付と無効な日付の表示と、$ZDateH 関数による変換の成功例、または失

敗例です。 T(今日を表す)を使用した式は、使用しやすく、日付の加算や減算も可能です。 既定

では、$ZDateH は無効な日付に対しエラーを生成しますが、9 番目の引数は値を返す代わりにエ

ラー・コードを指定します。

SAMPLES>write $zdateh("7/21/2007",1,,,,,,, -1)

60832

SAMPLES>write $zdateh("21/7/2007",1,,,,,,, -1)

-1

SAMPLES>write $zdateh("21 Jul 2007",2,,,,,,, -1)

60832

SAMPLES>write $zdateh("Juk 21 2008",6,,,,,,, -1)

-1

SAMPLES>write $zdateh("Jul 21 2008",6,,,,,,, -1)

61198

SAMPLES>write $zdateh("21/07/2006",4,,,,,,, -1)

60467

SAMPLES>write $zdateh("21.07.2007",4,,,,,,, -1)

-1

SAMPLES>write $zdateh("T+12", 5,,,,,,, -1)

60878

SAMPLES>

2 番目の例は、$Horolog と$ZDate の記述方法です。

SAMPLES>write $horolog

60866,61670

SAMPLES>write $zdate($horolog)

08/24/2007

SAMPLES>write $zdate($horolog,2)

24 Aug 2007

SAMPLES>write $zdate($horolog,3)

2007-08-24

SAMPLES>

-54-

Page 55: Caché ObjectScript チュートリアルへようこそ。 このチュートリ … · チュートリアルへようこそ。 このチュートリアルでは、強力なオブジェクト型言語の基礎と、特有の機能について学習します。

Caché ObjectScript チュートリアル

第 2 章-Chapter16

ユーザ定義関数

第 1 章ではプロシージャについて、この章では ObjectScript が提供する内部関数について学習し

てきました。 内部関数は、ユーザ自身が記述するユーザ定義関数と区別する為、システム定義関

数と呼ばれます。 下記の例は結果を返す簡単なプロシージャです。この関数では、Quit コマンド

の引数として結果を返すように値を特定します。

ユーザ定義関数はシステム定義関数のように使用しますが、関数名の前に$$を使用する点が異な

ります。

SAMPLES>do ^funcexample

Enter a number: 4

The factorial of 4 is 24

SAMPLES>do ^funcexample

Enter a number: 5

The factorial of 5 is 120

SAMPLES>write $$fact^funcexample(6) ; call it directly

720

SAMPLES>

以下は、funcexample.mac コードです。

funcexample ; example of user-defined function

read !, "Enter a number: ", num

set fact = $$fact( num )

write !, "The factorial of ", num, " is ", fact

quit

fact(number) PUBLIC

; compute factorial

{

if number < 1 {quit "Error!"}

if (number = 1) || (number = 2) {quit number}

set x = number * $$fact( number - 1 )

quit x

}

-55-

Page 56: Caché ObjectScript チュートリアルへようこそ。 このチュートリ … · チュートリアルへようこそ。 このチュートリアルでは、強力なオブジェクト型言語の基礎と、特有の機能について学習します。

Caché ObjectScript チュートリアル

第 2 章-Chapter17

演習 3

次の演習では、mydatent ルーチンにエラー・チェック機能を追加します。

• パターン・マッチ演算子を使用したパブリックのユーザ定義関数を 2 つ記述し、Name

と Phone を検証します。 無効なデータには、エラー・メッセージを返します。 これまで、

名前を“First Last”と入力しましたが、ここでは、“Last,First”というコードで名前を検証

します。

• Phone プロンプトに既定のエリア・コードを追加し、またエリア・コードを持たない電話番

号には、この既定コードを割り当てる行を追加します。

• 誕生日を有効にするため、ユーザ定義関数$ZDateH で日付を内部形式に変換します。

無効な日付にはエラー・メッセージを表示します。 また日付は、必ず今日より前の日付

を指定してください。

• プロンプトから新しいユーザ定義関数を呼び出します。

• $ZDate 関数を使用して、ユーザの入力方法に関係なく、標準形式で日付を表示しま

す。

• ルーチンを保存、実行し、さまざまな入力に対して 3 つのプロンプトをテストします。

詳細は、[Appendix F: 演習 3 :データ入力ルーチンの更新] を参照してください。

-56-

Page 57: Caché ObjectScript チュートリアルへようこそ。 このチュートリ … · チュートリアルへようこそ。 このチュートリアルでは、強力なオブジェクト型言語の基礎と、特有の機能について学習します。

Caché ObjectScript チュートリアル

第 2 章-Chapter18

デバッグ

これまで ObjectScript のさまざまな機能について学習してきました。 ここでは ObjectScript ル

ーチンのデバッグについて学習します。 Caché では、プログラム実行中にルーチンを中断し、変

数の現在の値を見ることができます。 ルーチンが正常に動作するまで 1行ずつ(あるいは1 文ごと

に)ルーチンを実行できます。ObjectScript のルーチンを中断する方法は 3 つあります。

• ルーチンを編集し、実行を一時停止したい個所に Break コマンドを追加して、ブレーク

ポイントを設定。

• ZBreak コマンドを使用して Caché ターミナル・プロンプトからブレークポイントをセット。

ルーチンの編集は不要です。

• ZBreak コマンドを使用して Caché ターミナル・プロンプトから変数にウォッチポイント

をセット。 ルーチンの編集は不要です。

ブレークポイントとは、処理中のルーチンの実行を中断する場所のことです。 ウォッチポイントとは、

値が変化すると実行を中断する変数のことです。 Breakはルーチンで有効なコマンドですが、

ZBreakコマンドにもさまざまな利点があります。 このセクションでは、これらのコマンドについて

学習します。 デバッグについて、また、BreakコマンドとZBreakコマンドについての詳細は、

Cachéドキュメント:[Caché開発ガイド]-[CachéObjectScriptの使用法]-[コマンド行ルーチンの

デバッグ] を参照してください。

-57-

Page 58: Caché ObjectScript チュートリアルへようこそ。 このチュートリ … · チュートリアルへようこそ。 このチュートリアルでは、強力なオブジェクト型言語の基礎と、特有の機能について学習します。

Caché ObjectScript チュートリアル

第 2 章-Chapter19

ZBreak コマンド

ZBreak コマンドの構文は以下のとおりです。

ブレークポイント : zb <location>:<action>:<condition>:<execute code>

ウォッチポイント : zb <*variable>:<action>:<condition>:<execute code>

• location: 実行を中断する位置(タグ+オフセット^ルーチンの形式)。

• variable: 値が変化した際に実行を中断し、指定したアクションを起こす変数。 変数

の先頭にアスタリスク(*)を付けます。

• action: ブレークポイントやウォッチポイントに到達した後の、ブレークの“style”を指

定(次ページ参照)。

• condition: その条件が偽の場合、ブレークは起こりません。

• execute code: ブレークポイントやウォッチポイントのトリガが実行されたときに処理

されるコード。

ZBreak コマンドは現在のブレークポイント、もしくはウォッチポイントの情報を表示します。 ?つき

の ZBreak(ZBreak ?)では詳しい使用方法を表示します。

変数あるいはタグ位置の前に"-"か"+"を記述すると、ブレークポイントとウォッチポイントが使用可

能、もしくは不可能になります。 削除するには、変数あるいはタグの前に--を記述します。

-58-

Page 59: Caché ObjectScript チュートリアルへようこそ。 このチュートリ … · チュートリアルへようこそ。 このチュートリアルでは、強力なオブジェクト型言語の基礎と、特有の機能について学習します。

Caché ObjectScript チュートリアル

第 2 章-Chapter20

ZBreak コマンドのアクション・コード

実行が中断されると、ルーチンは変数値を記述(Write)できる Caché ターミナル・プロンプトを返し

ます。 ブレークポイントあるいはウォッチポイントで実行を中断した後、Goto コマンドで実行を再

開できます。

ZBreak コマンドのアクション・コードが、実行を継続するときに何が起こるかを制御します。 内容

は以下のとおりです。

Zbreak コマンドのアクション・コード

アクション 意味

L

行ごとの実行(スキップ)。 各行の開始地点で停止。 その行が別のルーチン、

あるいはプロシージャを呼び出す場合、呼び出されたコードは割り込みなしに実

行可能。

L+

行ごとの実行(ジャンプ)。 各行の開始地点で停止。 その行が別のルーチン、

あるいはプロシージャを呼び出す場合、呼び出されたコードも各行の開始地点

で停止。

S

文ごとの実行(スキップ)。 各行の文の開始地点で停止。 文が他のルーチン

やプロシージャを呼び出す場合、呼び出されたコードは割り込みなしに実行可

能。

S+

文ごとの実行(ジャンプ)。 各行の文の開始地点で停止。 文が他のルーチン

やプロシージャを呼び出す場合、呼び出されたコードも各文の開始地点で停

止。

N アクションなし。 ブレークポイント、あるいはウォッチポイントがトリガされたとき

に、実際に実行を中断することなくオプション・コードを実行。

以上のアクション・コード以外に、デバッグとしてアクションを変更する“C”アクション (キャンセル)も

使用できます。 アクション・コードは Break コマンドの引数として、ターミナル・プロンプトで使用し

ます。

-59-

Page 60: Caché ObjectScript チュートリアルへようこそ。 このチュートリ … · チュートリアルへようこそ。 このチュートリアルでは、強力なオブジェクト型言語の基礎と、特有の機能について学習します。

Caché ObjectScript チュートリアル

第 2 章-Chapter21

デバッグの例

以下の例では RightTriangle ルーチン(このチュートリアルの 初に紹介されています)の、

Compute プロシージャの前にブレークポイントを設定しています。 “L+” は、呼び出された

Compute プロシージャ内でも、ルーチンを 1 行ずつ停止します。

SAMPLES>zbreak RightTriangle+20^RightTriangle:"L+"

SAMPLES>do ^RightTriangle

Compute the area and hypotenuse of a right triangle

given the lengths of its two sides.

First, choose a unit of measurement.

(i)nches, (f)eet, (m)iles, (c)entimeters, m(e)ters, (k)ilometers: i

Length of side 1: 5 Accepted.

Length of side 2: 10 Accepted.

quit:(side2 = "") // exit the routine

^

<BREAK>RightTriangle+21^RightTriangle

SAMPLES 2d0>g ; continue execution

do Compute( units, side1, side2)

^

<BREAK>RightTriangle+22^RightTriangle

SAMPLES 2d0>write side2

10

SAMPLES 2d0>g ; continue into Compute

{ set area = ( A * B ) / 2,

^

area = $justify( area, 0, 2),

%X = ( A ** 2 ) + ( B ** 2 ) // set up %X, which INT%SQROOT requires

<BREAK>IsNegative+11^RightTriangle

SAMPLES 3d1>write B

10

SAMPLES 3d1>b "L" ; don't jump into %SQROOT

-60-

Page 61: Caché ObjectScript チュートリアルへようこそ。 このチュートリ … · チュートリアルへようこそ。 このチュートリアルでは、強力なオブジェクト型言語の基礎と、特有の機能について学習します。

Caché ObjectScript チュートリアル

SAMPLES 3d1>g

do INT^%SQROOT // INT^%SQROOT returns its result by settin

^

g %Y

<BREAK>IsNegative+14^RightTriangle

SAMPLES 3d1>g

set hypot = $justify( %Y, 0, 2) // now, round %Y to 2 places

^

<BREAK>IsNegative+15^RightTriangle

SAMPLES 3d1>b "C" ; cancel the breaking within Compute

SAMPLES 3d1>g

The area of this triangle is 25.00 square inches.

The hypotenuse is 11.18 inches.

quit

^

<BREAK>RightTriangle+23^RightTriangle

SAMPLES 2d0>g ; breaking continues upon return from Compute

SAMPLES>

-61-

Page 62: Caché ObjectScript チュートリアルへようこそ。 このチュートリ … · チュートリアルへようこそ。 このチュートリアルでは、強力なオブジェクト型言語の基礎と、特有の機能について学習します。

Caché ObjectScript チュートリアル

第 2 章-Chapter22

配列

他言語と同様、ObjectScript は添え字を使用した多次元配列を備えています。 しかし

ObjectScript の配列は他言語と異なり、より強力な機能を備えています。 添え字なしの変数と同

様に、サイズや次元にかかわらず配列を宣言する必要はありません。 配列はスパース構造(まば

らな構造=一部の要素がない)で、要素にデータが定義されていない場合、スペースは割り当てま

せん。 例えば、配列を使用して、チェッカーと呼ばれるゲームでのプレーヤの区画を追跡するとし

ます。 チェッカー・ボードには 8x8 のマスがあります。 他言語では、チェッカーが 24 のポジション

しか占めていない場合でも、配列 Board(8,8)には 64 のメモリ位置が必要です。

配列変数への値のセットの例:

SAMPLES>set a(3, 7) = 4 + 2

SAMPLES>write a(3, 7)

6

SAMPLES>

他言語と全く同様に、上記の3×3の配列Aの図のように、リストやテーブル形式で配列を表現する

ことができます。 しかしながら、ObjectScript の持つ強力な配列機能を理解するには、配列のツ

リー構造を学習する必要があります。 次ページでは、配列構造を図で示しています。 また、他の

配列機能も学習します。

-62-

Page 63: Caché ObjectScript チュートリアルへようこそ。 このチュートリ … · チュートリアルへようこそ。 このチュートリアルでは、強力なオブジェクト型言語の基礎と、特有の機能について学習します。

Caché ObjectScript チュートリアル

第 2 章-Chapter23

ツリー構造(1)

①set A = 4

②set A(5) = 4 ③set A(9) = 4 ④set A(7) = 4

⑤set A(-4) = 4 ⑥set A(-6) = 4

⑦set A(2.5) = 4 ⑧set A(2.54) = 4

⑨set A(“B”) = 4 ⑩set A(“F”) = 4 ⑪set A(“BOB”) = 4

⑫set A(3,3) = 4 ⑬set A(3,4) = 4 ⑭set A(5,”C”) = 4

⑮set A(5,”D”,-2.7) = 4

上記図では、 初に (添え字なしの) A=4 を設定しています<①>。 ObjectScript は A にメモ

リ位置を割り当て、4 を格納します。 この例では、すべてのロケーションに対して 4 を設定していま

すが、これは、任意です。 重要なのは 4 という数値ではなく、これらの文によって構築されたツリー

です。

次の 3 文は、複数の配列位置(5、9、7)に 4 を格納します<②~④>。 A は、スカラと配列の両方

に使用できます。 新規のレベルや新次元のツリーの配列は、文の順番に関係なく添え字値を元に

並べ替えられます。 この時点で、他言語では少なくとも 9 つのメモリ位置が必要ですが、A では 4

つしか使用しません。 次の 2 つの文では、負の整数添え字を使用します<⑤、⑥>。 他言語では

機能しませんが、ツリー構造の場合使用できます。 また、実数や小数の添え字も Set 文で設定で

きます<⑦、⑧>。 これもツリー構造でのみ使用可能な機能です。

-63-

Page 64: Caché ObjectScript チュートリアルへようこそ。 このチュートリ … · チュートリアルへようこそ。 このチュートリアルでは、強力なオブジェクト型言語の基礎と、特有の機能について学習します。

Caché ObjectScript チュートリアル

次に、非数値の添え字を使用した 3 つの配列を設定します<⑨~⑪>。 非数値の配列は数値配

列の右側に表示されていますが、非数値はアルファベット順に並べ替えられます。ここまでのところ、

A 配列は 1 次元です。 次の 3 つの文で 2 次元配列を生成、並べ替え<⑫~⑭>、 後に 3 次元

配列を生成します<⑮>。

-64-

Page 65: Caché ObjectScript チュートリアルへようこそ。 このチュートリ … · チュートリアルへようこそ。 このチュートリアルでは、強力なオブジェクト型言語の基礎と、特有の機能について学習します。

Caché ObjectScript チュートリアル

第 2 章-Chapter24

ツリー構造(2)

ここまで学習してきたように、正と負の整数、実数、非数値文字列を配列添え字として使用できます。

空文字のみ使用できません。 ここでは、ツリー構造の詳細について学習します。

配列に関連する用語を解説します。 全体構造はツリーと呼ばれ、家系図のように上から下に拡張

します。 ルート A が頂点です。 ルート、および他の添え字が付いた A をノードと呼びます。 下に

ノードを持たないノードは、葉と呼ばれます。 下にノードを持つノードは、親や先祖と呼ばれます。

親を持つノードは、子や子孫と呼ばれます。また、同じ親を持つ子は兄弟と呼ばれます。 すべての

兄弟がツリーに追加されると、数値順あるいはアルファベット順で自動的に並べ替えられます。

ツリー構造ではどのような深さの多次元配列も作成でき、現実的な問題を解決するための階層化

が簡単にできます。 他の方法で多次元配列を図示するのは困難です。

-65-

Page 66: Caché ObjectScript チュートリアルへようこそ。 このチュートリ … · チュートリアルへようこそ。 このチュートリアルでは、強力なオブジェクト型言語の基礎と、特有の機能について学習します。

Caché ObjectScript チュートリアル

第 2 章-Chapter25

変数値とノードの存在、および $Data 関数

ノードの値はいつでも変更できます。 しかし、値が割り当てられていないノードもあります。 A(3)

と A(5,"D")の 2 つには子があります。 Set 文で下位に子を生成しているため、A(3)と A(5,"D")

には値を割り当てないか、あるいは後で割り当てます。 また、ObjectScript 配列には別の機能も

備わっています。 つまり、メモリ位置は値を割り当てられていなくても存在します。 他の言語では、

変数が存在する場合は常に値が設定されています。

$Data 関数は、ツリーのノードを検査しステータスを調べる重要な関数です。 $Data がゼロ以外

の結果を返した場合、ノードが存在していることを示します。

SAMPLES>write $data(A) ; has value and descendants

11

SAMPLES>write $data( A(3) ) ; has descendants only

10

SAMPLES>write $data( A(3, 3) ) ; has value only

1

SAMPLES>write $data( A(3, 5) ) ; doesn't exist

0

Kill コマンドを思い出してください。 ツリー内のノードに Kill を使用すると、そのノードと子が削除さ

れます。 Kill A は全構造を削除します。 Kill A(5)はノードと 3 つ下位にあるノードを削除し

ます。

-66-

Page 67: Caché ObjectScript チュートリアルへようこそ。 このチュートリ … · チュートリアルへようこそ。 このチュートリアルでは、強力なオブジェクト型言語の基礎と、特有の機能について学習します。

Caché ObjectScript チュートリアル

第 2 章-Chapter26

グローバル

これまで、“変数”と“グローバル”について学習してきました。 以下はその概要です。

用語 意味 アクセス範囲 例

グローバル ディスク上の

永続配列

ディスクにアクセスできる全 ObjectScript 処理

と、全ルーチンはこの変数にアクセス可能 ^A

パブリック変数 処 理 に 必 要

な変数

プログラムの全ルーチンで、この変数にアクセス

可能 A

プライベート変数 処 理 に 必 要

な変数

変数が使用されているプロシージャで、この変数

にアクセス可能 A

ObjectScript グローバルを理解するのは大変容易です。 これまで学習してきた配列はすべてグ

ローバルです。 配列は宣言する必要がなく、ディスクに保存する場合、Set 文を使用してツリー構

造を構築します。 また、ディスク容量は値が割り当てられた場合にのみ必要です。 Kill コマンド

はグローバルのノード、もしくはグローバル全体を瞬時に削除します。 通常の変数で使用する関数

やコマンドのほとんどは、グローバルで同様に機能します。 唯一、サーカムフレックス“^”がグロー

バル名の先頭に表示される点が異なります。

-67-

Page 68: Caché ObjectScript チュートリアルへようこそ。 このチュートリ … · チュートリアルへようこそ。 このチュートリアルでは、強力なオブジェクト型言語の基礎と、特有の機能について学習します。

Caché ObjectScript チュートリアル

第 2 章-Chapter27

$Increment 関数

これまで学習してきた配列の構造や機能はユニークであるため、使用法に関して説明が必要でしょ

う。 これらを整理するため、例として mydatent ルーチンにストレージ・プロシージャを記述します。

ここでは$Increment 関数を使用します。$Increment 関数は変数を取得し、値をインクリメン

ト(変更)して返します。 インクリメントは正でも負の数でも可能です。 この例では、既定で 1 をイン

クリメントしています。

Note:

$Increment 関数は、その引数値を変更します。

SAMPLES>write a

WRITE a

^

<UNDEFINED> *a

SAMPLES>write $increment(a)

1

SAMPLES>write $increment(a)

2

SAMPLES>write $increment(a,2)

4

SAMPLES>write a

4

SAMPLES>

-68-

Page 69: Caché ObjectScript チュートリアルへようこそ。 このチュートリ … · チュートリアルへようこそ。 このチュートリアルでは、強力なオブジェクト型言語の基礎と、特有の機能について学習します。

Caché ObjectScript チュートリアル

第 2 章-Chapter28

ストレージ・プロシージャ(1)

myatent のストレージ・プロシージャについて学習します。 ユーザはプロンプトに応答し、データ

を確認し、また、データを保存することができます。 次のスライドで示しているように、グローバル

^PersonD にデータを格納します。

一人一人に新しい一意の ID 番号を生成して、^PersonD の添え字として使用します。

mydatent の初回実行時は^PersonD が存在しないため、$Increment()を使用して 初の

ID を必ず 1 にする必要があります。 これにより“通常”の配列と同様の概念構造を持つ配列(つま

り人のリスト)に^PersonD が配置されます(ただし、実際はまだツリー構造です)。 各個人のレコ

ードは、3 つの文字列データから成り立ちます。 store サブルーチンは以下のとおりです。

store() [name, phone, intdob]

; store the data

{

read !, "Store? (y/n): ", yn ; see if user wants to store

if ( yn '= "y" ) { ; only go on if user says yes

write "...not stored."

quit

}

set id = $increment( ^PersonD ) ; use $i to generate a new id

set rec = name _ "^" _ phone _ "^" _ intdob ; concatenate data into a record

set ^PersonD( id ) = rec ; store the record

; ...remainder of store subroutine continued on next page...

}

-69-

Page 70: Caché ObjectScript チュートリアルへようこそ。 このチュートリ … · チュートリアルへようこそ。 このチュートリアルでは、強力なオブジェクト型言語の基礎と、特有の機能について学習します。

Caché ObjectScript チュートリアル

第 2 章-Chapter29

ストレージ・プロシージャ(2)

ストレージ・プロシージャのこのセクションでは、 初に、インデックス化するため、名前を姓と名に分

割します。 次の 3 文は、他言語の文とはまったく異なります。 文のうち 2 つのデータは添え字に

格納されるため、イコール記号の右側には“何も”指定しません。 理由はツリー構造にあります。

例えば、姓、名、ID は添え字に格納されます。 名前はアルファベット順にソートされるため、データ

ベースには姓、名の順でインデックスを作成します。 電話番号と誕生日のインデックスも同様に作

成します。 グローバルの^PersonI は 3 つの大きな枝に分かれ、各枝にインデックスがあるツリー

になります。 電話番号インデックスを構築する行は異なるため、電話番号の固有データを利用でき

ます(ID は添え字に格納されません)。

複数のデータが入力されたと想定して配列のツリーを描画すると、配列のデータ構造が理解できま

す。 システム管理ポータル([データ管理]セクション)を使用して[[ホーム]→[グローバル]]に移

動し、2 つのグローバル(^PersonD と^PersonI)を確認してください。

※実際のデータは、ルーチンを作成後、実行して確認してください。

store() [name, phone, intdob]

{

; ...store procedure continued from previous page...

set ln = $piece(name, ",", 1),

fn = $piece(name, ",", 2) ; break name for storage in index

/* the next three statements store data in subscripts

because of the automatic sorting of subscripts,

this has the effect of building 3 indexes: name, phone, and DOB */

set ^PersonI( "Name", ln, fn, id) = "" ; store the name

set ^PersonI( "Phone", phone) = id ; store the UNIQUE phone

set ^PersonI( "DOB", intdob, id) = "" ; store the DOB

write "...stored" ; done

}

-70-

Page 71: Caché ObjectScript チュートリアルへようこそ。 このチュートリ … · チュートリアルへようこそ。 このチュートリアルでは、強力なオブジェクト型言語の基礎と、特有の機能について学習します。

Caché ObjectScript チュートリアル

第 2 章-Chapter30

グローバルの例(1)

下記は、mydatent ルーチンを使用して作成された 3 つのエントリの例です。 誕生日は内部形

式で格納されます。 グローバルを確認するには、システム管理ポータル ([データ管理]セクショ

ン)を使用して、SAMPLES ネームスペース内の[[ホーム]→[グローバル]]に移動します。

^PersonD と^PersonI のエントリを見つけ、それぞれ[[表示]]をクリックします。

^PersonI グローバルには、ソートされた 3 つのインデックスが含まれます。 各インデックスの葉

はソート順に並んでいます。 DOB と Name インデックスは次元を追加して、同じ誕生日や名前を

持つ個人データを複数格納できます。 Phone インデックスは構造上、一意のデータのみ持ちま

す。

-71-

Page 72: Caché ObjectScript チュートリアルへようこそ。 このチュートリ … · チュートリアルへようこそ。 このチュートリアルでは、強力なオブジェクト型言語の基礎と、特有の機能について学習します。

Caché ObjectScript チュートリアル

次のページは、これらのグローバルのツリー・ダイアグラムを示しています。

-72-

Page 73: Caché ObjectScript チュートリアルへようこそ。 このチュートリ … · チュートリアルへようこそ。 このチュートリアルでは、強力なオブジェクト型言語の基礎と、特有の機能について学習します。

Caché ObjectScript チュートリアル

第 2 章-Chapter31

グローバルの例(2)

以下の^PersonI の図では、図を簡略化するために新規次元やレベルには追加された添え字のみ

を表示しています。

^PersonI("DOB",37105,1)=

^PersonI("DOB",37110,2)=

^PersonI("DOB",37779,3)=

^PersonI("Name","Agee","Tommie",2)=

^PersonI("Name","Jones","Cleon",1)=

^PersonI("Name","Swoboda","Ron",3)=

^PersonI("Phone","111-111-1111")=1

^PersonI("Phone","222-222-2222")=3

^PersonI("Phone","617-333-3333")=2

-73-

Page 74: Caché ObjectScript チュートリアルへようこそ。 このチュートリ … · チュートリアルへようこそ。 このチュートリアルでは、強力なオブジェクト型言語の基礎と、特有の機能について学習します。

Caché ObjectScript チュートリアル

第 2 章-Chapter32

演習 4

グローバル^PersonD (データ)とグローバル^PersonI (インデックス)の作用を理解する 適な

方法は、各自が mydatent ルーチンを使用してみることです。

• main プロシージャに行を追加します。 display プロシージャの後に store プロシー

ジャを呼び出します。

• 電話番号が電話インデックスに既に存在するかどうかをチェックするために、

$$validPhone 関数を追加します。

• (Caché 演習ガイドから)ルーチンに store プロシージャをコピーします。

• コンパイル後、ルーチンを実行し、個人データを格納します。 システム管理ポータルを

使用してグローバルを表示します。 再度実行し、データをいくつか格納します。 グロー

バル、特に^PersonI を再度チェックします。

詳細は、[Appendix G: 演習 4 :ストレージ・プロシージャの追加] を参照してください。

-74-

Page 75: Caché ObjectScript チュートリアルへようこそ。 このチュートリ … · チュートリアルへようこそ。 このチュートリアルでは、強力なオブジェクト型言語の基礎と、特有の機能について学習します。

Caché ObjectScript チュートリアル

第 2 章-Chapter33

第 2 章の要約

第 2 章では、ObjectScript を強力にする以下の機能について学習しました。

• 文字列(数字やリストを含め、すべてのデータは文字列であること)

• パターン・マッチング演算子

• 多機能な文字列とリスト

• 日付の機能

• 特殊関数の記述法

• Caché デバッガの使用法

• 配列、ツリー構造、グローバル変数の存在のテスト法

• データベースとインデックスの簡単な作成方法

-75-

Page 76: Caché ObjectScript チュートリアルへようこそ。 このチュートリ … · チュートリアルへようこそ。 このチュートリアルでは、強力なオブジェクト型言語の基礎と、特有の機能について学習します。

Caché ObjectScript チュートリアル

第 3 章

データベースの使用法

第 3 章では、前章で構築したデータベースをどのように使用するかを、Caché ObjectScript の重

要な機能と併せて学習します。 検索/編集ルーチンをインタラクティブに作成したり、

ObjectScript の便利な機能について学習します。

• 関数 : $Order、$Translate、$Get.

• コマンド : Else(および$Test)、Lock、TStart、TCommit

• 参照渡しのパラメータ

• %New、%OpenIdと%Saveの標準メソッドを使用して、オブジェクトへアクセスするコ

ードの記述方法

-76-

Page 77: Caché ObjectScript チュートリアルへようこそ。 このチュートリ … · チュートリアルへようこそ。 このチュートリアルでは、強力なオブジェクト型言語の基礎と、特有の機能について学習します。

Caché ObjectScript チュートリアル

第 3 章 - Chapter1

$Order 関数(1)

第2章では、ほとんどのデータを添え字に格納する^PersonIインデックスを作成しました。 ここで

は、添え字に格納されたデータにどのようにしてアクセスするかを学習します。 配列にノードが存

在する場合、$Order 関数はその子ノードの添え字値を返します。 添え字は自動的にソートされ

るため、$Order 関数は子ノードを名前順に検索します。

このためには、$Order に 1 つ以上の添え字付き配列名を渡します。配列と 後の添え字以外の

添え字は、ノードを識別するものです。 後の添え字は、$Order 関数の対象となる添え字です。

x配列を使用した例では、$Order関数の対象となる添え字が唯一の添え字です。 空文字列("")

は配列の添え字には使用できませんが、$Order に渡される配列の添え字として使用できます。

$Order は、これにより、 初の有効な添え字値を返します。

この例ではまず、$Orderは有効な 初の添え字1を返します。 その後残りの添え字を順番に返

すので、1 を渡すと 4 を、4 を渡すと 9 を返します。 9 を渡すと$Order はそれ以上有効な添え字

がないことを示す空文字列を返します。

SAMPLES>write

x(1)=1

x(4)=2

x(9)=3

SAMPLES>write $order( x("") )

1

SAMPLES>write $order( x(1) )

4

SAMPLES>write $order( x(4) )

9

SAMPLES>write $order( x(9) )

SAMPLES>

-77-

Page 78: Caché ObjectScript チュートリアルへようこそ。 このチュートリ … · チュートリアルへようこそ。 このチュートリアルでは、強力なオブジェクト型言語の基礎と、特有の機能について学習します。

Caché ObjectScript チュートリアル

第 3 章 – Chapter2

$Order 関数(2)

$Order を使用して添え字値を取得する際に、同時に等式の右側の値も取得できます。

$Order の 3 番目の引数に変数名を割り当てると、1 ステップでこれらの値を取得できます。

例えば、次の添え字を取得し(a)、値をそこに格納します(b)。

SAMPLES>set a = $order( x(4) ), b = x(a) write a, " ", b

9 3

同じことを簡単で高速な方法で実行できます。

SAMPLES>set a = $order( x(4), 1, b) write a, " ", b

9 3

-78-

Page 79: Caché ObjectScript チュートリアルへようこそ。 このチュートリ … · チュートリアルへようこそ。 このチュートリアルでは、強力なオブジェクト型言語の基礎と、特有の機能について学習します。

Caché ObjectScript チュートリアル

第 3 章 – Chapter3

インデックスの機能

ここで、もう一度^PersonI と$Order を確認します。 ^PersonI には添え字を 4 つまで設定で

きますが、この例では、ルートの子、つまり第 1 次元を検索します。$Order 関数は 初の添え字

“DOB”を返します。 “DOB”を渡すと、次に存在する添え字“Name”を返します。 “Name”は

“Phone”を返し、“Phone”により $Order は空文字列を返します。

$Order でこのレベルを検索すると、各添え字の 1 つを返します。 ここに示すビューでは、“DOB”、

“Name”および“Phone”の値を 3 回ずつ繰り返します。 これはエラーではなく、ポータルでのグロ

ーバル表示方法によるものです。 配列ツリー上では、“DOB”、“Name”、“Phone”はそれぞれ 1

つのノードです。

SAMPLES>write $order( ^PersonI("") )

DOB

SAMPLES>write $order( ^PersonI("DOB") )

Name

SAMPLES>write $order( ^PersonI("Name") )

Phone

SAMPLES>write $order( ^PersonI("Phone") )

SAMPLES>

-79-

Page 80: Caché ObjectScript チュートリアルへようこそ。 このチュートリ … · チュートリアルへようこそ。 このチュートリアルでは、強力なオブジェクト型言語の基礎と、特有の機能について学習します。

Caché ObjectScript チュートリアル

第 3 章 – Chapter4

$Order ループ

前ページの例では、$Order を繰り返し使用して、ツリーを走査しました。 ループを使用すると、よ

り簡単に検索することができ、ツリーの他のレベルを走査することもできます。 以下は、

ObjectScript でよく使用されるループのコードです。

初に、変数 ln を初期化して空文字列にします。 その後 For ループを開始します。Set 文では、

$Order を使用して^PersonI("Name")ノードの 初の子(姓)の添え字値を生成します。 次に、

Quit コマンドは空文字と等しい姓を検索し、ループを終了させるかどうかを判断します。 後に、

値に対してどのような処理を実行するかを指定します。 ここでは値を表示します。 その後、ループ

は同じ処理を繰り返し、次の姓を検索します。 電話番号は姓とは兄弟でないため、姓の“隣に”電

話番号の添え字が存在してもその値は取得しません。

$Order を使用する Set 文は、典型的なプログラミング・コードSet i=i+1と類似しています。 こ

のコードは、変数値の現在の値を使用して新規の値を生成します。

SAMPLES>d ^simpleloop

Agee

Jones

Swoboda

SAMPLES>

-80-

Page 81: Caché ObjectScript チュートリアルへようこそ。 このチュートリ … · チュートリアルへようこそ。 このチュートリアルでは、強力なオブジェクト型言語の基礎と、特有の機能について学習します。

Caché ObjectScript チュートリアル

以下は、simpleloop.mac コードです。

simpleloop ; loop through last names

set ln = ""

for {

set ln = $order( ^PersonI("Name", ln) )

quit:(ln = "")

write !, ln

}

-81-

Page 82: Caché ObjectScript チュートリアルへようこそ。 このチュートリ … · チュートリアルへようこそ。 このチュートリアルでは、強力なオブジェクト型言語の基礎と、特有の機能について学習します。

Caché ObjectScript チュートリアル

これまで$Order ループの例として Do/While や While 文に対し、引数を持たない For 文を

参照しました。 引数を持たない For には他のループにはない、いくつかの利点があります。 詳細

は[第1章-Chapter25:For 文(2)]を参照してください。

For 文は、ループの終了を 初(While)や 後(Do/While)に置く文と異なり、繰り返しコード

内にループを終了させる条件を置くことができます。 これにより、For の条件チェックは 1 度のみ

です。 その他の条件チェックは 2 度あります。 以下は、コード・サンプルの例です。

compareloop ; different styles of looping

/* 最初の 3つのループ文はロジック的には同等の処理ですが、最初の for を使った

(usefor)が他の 2つよりも推奨されます。

4 番目のループ処理は、3番目とほぼ同じものですが、内部終了処理がありません。

これは、ロジック的にエラーです。*/

usefor write !, "Using For"

for

{

set x = $random(10)

quit:(x = 5) // this quit ends the code block AND terminates the loop

write !, x

}

usewhile write !!, "Using While"

set x = ""

while x '= 5 // this condition is evaluated each time, for no reason

{

set x = $random(10)

quit:(x = 5) // this quit ends the code block AND terminates the loop

write !, x

}

第 3 章 – Chapter5

For 文と Do/While 文と While 文

-82-

Page 83: Caché ObjectScript チュートリアルへようこそ。 このチュートリ … · チュートリアルへようこそ。 このチュートリアルでは、強力なオブジェクト型言語の基礎と、特有の機能について学習します。

Caché ObjectScript チュートリアル

usedo write !!, "Using Do/While"

do

{

set x = $random(10)

quit:(x = 5) // this quit ends the code block AND terminates the loop

write !, x

}

while x '= 5 // this condition is evaluated each time, for no reason

badusedo write !!, "Using Do/While, but it writes the terminating 5"

do

{

set x = $random(10)

write !, x

}

while x '= 5 // this condition terminates the loop (a little too late)

-83-

Page 84: Caché ObjectScript チュートリアルへようこそ。 このチュートリ … · チュートリアルへようこそ。 このチュートリアルでは、強力なオブジェクト型言語の基礎と、特有の機能について学習します。

Caché ObjectScript チュートリアル

第 3 章 – Chapter6

入れ子の$Order ループ

入れ子になった$Orderループ(ツリー構造の各レベルに1つ)を使用すると、ID番号を示すノード

に到達できます。 その後 ID 番号を使用してデータ配列に戻り、必要な情報を取得します。 下記

は、名前インデックスを使用した例です。 ここでは、各姓データに対応する名前すべてを検索する

ために、新規のループを呼んでいます。 また、そのフルネームに対し、新規ループで該当するすべ

ての ID 番号を検索します。ID を使用して、^PersonD の残りのデータを取得します。

SAMPLES>do ^nameloop

Agee,Tommie 617-333-3333 08/09/42 Jones,Cleon 111-111-1111 08/04/42

Swoboda,Ron 222-222-2222 06/08/44

SAMPLES>

以下は、simpleloop.mac コードです。

nameloop ; loop through the name index

set ln = ""

For {

set ln = $order( ^PersonI("Name", ln) )

quit:(ln = "")

set fn = ""

for {

set fn = $order( ^PersonI("Name", ln, fn) )

quit:(fn = "")

set id = ""

for {

set id = $order( ^PersonI("Name", ln, fn, id) )

quit:(id = "")

set rec = ^PersonD(id)

write !, $piece( rec, "^", 1), ?15, $piece( rec, "^", 2),

?30, $zdate( $piece( rec, "^", 3) )

}

}

}

-84-

Page 85: Caché ObjectScript チュートリアルへようこそ。 このチュートリ … · チュートリアルへようこそ。 このチュートリアルでは、強力なオブジェクト型言語の基礎と、特有の機能について学習します。

Caché ObjectScript チュートリアル

第 3 章 – Chapter7

$Order ループ

$Order ループでは、set ln = ""は、“姓の 初から開始”を意味します。 同様に、quit:(ln

= "")は、“姓の 後で停止” を意味します。 文を修正してループを使用することにより、生成され

る添え字を少なくします。 例えば、set ln="B"と記述すると、ループが “Agee” をスキップしま

す。

このループで名前のある部分文字列から開始する名前のみを生成する場合、変数 lnを開始する部

分文字列に設定します。 また、Quit 文を変更して、指定した部分文字列より後の文字で始まる名

前に到達する前に、ループを停止させる必要があります。これにはいくつか方法があります。 内容

については次ページで学習します。 以下は、simpleloop.mac コードです。

simpleloop ; loop through last names

set ln = ""

for {

set ln = $order( ^PersonI("Name", ln) )

quit:(ln = "")

write !, ln

}

-85-

Page 86: Caché ObjectScript チュートリアルへようこそ。 このチュートリ … · チュートリアルへようこそ。 このチュートリアルでは、強力なオブジェクト型言語の基礎と、特有の機能について学習します。

Caché ObjectScript チュートリアル

第 3 章 – Chapter8

$Order ループの開始

ここでは、ループの開始について学習します。 変数 sub は、空でない部分文字列を格納すると想

定します。 先述の例のとおり、ln を""に設定する代わりに、以下の文 (set ln=sub)を使用して、

部分文字列を基に$Order ループを開始します。 しかし、毎回 ln に部分文字列と等しい値を設定

すると、検出されないデータが発生します。sub がデータベース内の姓と等しい場合はどうなるでし

ょうか。 このように、インデックスに sub と完全に一致する名前が存在する場合でも、ループは次

の名前から開始されます。これは$Order 関数の仕様によるものです。

対処法として、$Order 文を For 文の 後に配置します。 次に$Data を使用して、sub がデー

タベースに存在する姓に一致するかどうかを検証します。 一致しない場合、$Order は sub に一

致する可能性のある 初の値に移動します。 その後ループは処理を継続し、sub に続く名前を生

成します。 しかし、 “Swoboda”(=”J”から始まらない名前)を取得しないようにするため、さらに、

ループの 後に注意する必要があります。

SAMPLES>do ^loopstart

Search for: J

Jones

Swoboda

SAMPLES>

以下は、loopstart.mac コードです。

loopstart ; loop through last names

read "Search for: ",sub

set ln = sub

if '$data( ^PersonI("Name", sub)) {

set ln = $order( ^PersonI("Name", sub)) }

for {

quit:(ln = "")

write !, ln

set ln = $order( ^PersonI("Name", ln) )

}

-86-

Page 87: Caché ObjectScript チュートリアルへようこそ。 このチュートリ … · チュートリアルへようこそ。 このチュートリアルでは、強力なオブジェクト型言語の基礎と、特有の機能について学習します。

Caché ObjectScript チュートリアル

第 3 章 – Chapter9

$Order ループの終了

ここでは、ループの終了方法について学習します。 ここで再度、変数 sub には空文字以外の部分

文字列が設定されているとします。 ここで、

(quit:$extract(ln,1,$length(sub))'=sub)と記述し、“ln の先頭が sub に一致しない

場合ループを Quit します”。 また、ln = ""がある名前の 後に $Order がアクセスする場合

も処理します。 つまり、ln が空文字列の場合は ln の $Extract が空文字列で、sub は空文字列

でないため、Quit が発生し、ループが終了します。 以下にいくつか例を挙げます。

SAMPLES>set sub = "J"

SAMPLES>set ln = "Jones"

SAMPLES>if $extract(ln, 1, $length(sub)) '= sub { write "No Match" }

SAMPLES>set sub = "J"

SAMPLES>set ln = "Swoboda"

SAMPLES>if $extract(ln, 1, $length(sub)) '= sub { write "No Match" }

No Match

SAMPLES>set sub = "J"

SAMPLES>set ln = ""

SAMPLES>if $extract(ln, 1, $length(sub)) '= sub { write "No Match" }

No Match

SAMPLES>do ^loopend

Search for: J

Jones

SAMPLES>

-87-

Page 88: Caché ObjectScript チュートリアルへようこそ。 このチュートリ … · チュートリアルへようこそ。 このチュートリアルでは、強力なオブジェクト型言語の基礎と、特有の機能について学習します。

Caché ObjectScript チュートリアル

loopend.mac のコードは以下のとおりです。

loopend ; loop through last names

read "Search for: ",sub

set ln = sub

if '$data( ^PersonI("Name", sub)) {

set ln = $order( ^PersonI("Name", sub)) }

for {

quit:( $extract(ln, 1, $length(sub)) '= sub )

write !, ln

set ln = $order( ^PersonI("Name", ln) )

}

-88-

Page 89: Caché ObjectScript チュートリアルへようこそ。 このチュートリ … · チュートリアルへようこそ。 このチュートリアルでは、強力なオブジェクト型言語の基礎と、特有の機能について学習します。

Caché ObjectScript チュートリアル

第 3 章 – Chapter10

演習 5

ここでは mylookup ルーチンを使用します。 このルーチンは、名前、電話番号、誕生日を検索し

ます。 以下に、記述が必要なプロシージャの名前と用途を示しています。

• 新規にルーチンを作成します。 初に main セクションがあり、他に 4 つのプロシージ

ャ、getsubmit、help、dob、display があります。

• main セクションには getsubmit を呼び出すループがあり、ユーザに文字入力を要

求します。 このバージョンでは、ユーザが?を入力するとヘルプが表示され、誕生日を

入力するか、あるいは Enter を押して終了します。 $$validDOB^mydatent()

を使用して誕生日を検証します。 ユーザが?を入力すると、help プロシージャにより、

検索項目の選択肢が表示されます。

• ユーザが有効な誕生日を入力すると、dob プロシージャは誕生日の内部形式が

^PersonI に存在するかどうかを検証し、インデックスをループして、同じ誕生日を持つ

個人 IDすべてを検索します。個人データはdisplayプロシージャで表示されます。 こ

のプロシージャはパラメータとして ID を受け入れ、個人データをすべて表示します。

詳細は、[Appendix H : 演習 5 :Lookup ルーチン、バージョン 1] を参照してください。

-89-

Page 90: Caché ObjectScript チュートリアルへようこそ。 このチュートリ … · チュートリアルへようこそ。 このチュートリアルでは、強力なオブジェクト型言語の基礎と、特有の機能について学習します。

Caché ObjectScript チュートリアル

第 3 章 – Chapter11

$Translate 関数

$Translate 関数は文字列の中の 1 つ以上の文字を、異なる文字に置換します。 また、文字列

から文字を削除します。 lookup ルーチンでは、小文字を大文字に、あるいは大文字を小文字に

置換します。

記述した mydatent ルーチンの name プロンプトは、“Agee,Tommie”の大文字/小文字を区別

します。 $Translate を使用すると、ユーザが入力した名前文字列の大文字/小文字を区別しま

せん(例 : “a”あるいは“AGEE”)。

SAMPLES>write $translate( "abcde", "ad", "yz" ) ; a->y, d->z

ybcze

SAMPLES>write $translate( "abcde", "ad", "zz" ) ; translate a and d->z

zbcze

SAMPLES>write $translate( "abcde", "ad", "z") ; translate a->z, and d->nothing

zbce

SAMPLES>read "String to translate: ", x

String to translate: the quick brown fox jumps over the lazy dog

SAMPLES>set lower = "abcdefghijklmnopqrstuvwxyz"

SAMPLES>set upper = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"

SAMPLES>write !, $translate( x, lower, upper )

THE QUICK BROWN FOX JUMPS OVER THE LAZY DOG

SAMPLES>

-90-

Page 91: Caché ObjectScript チュートリアルへようこそ。 このチュートリ … · チュートリアルへようこそ。 このチュートリアルでは、強力なオブジェクト型言語の基礎と、特有の機能について学習します。

Caché ObjectScript チュートリアル

第 3 章 – Chapter12

参照渡しのパラメータ(1)

プロシージャ(外部関数を含む)はパラメータを受け取ります。 既定値では、パラメータは値によっ

て渡されます。 つまりプロシージャは、渡された変数の値を使用できますが、変数の値自体を変更

することはできません。 例の 初の部分の $$dblbyval は変数 num を使用してそれを 2 倍に

しますが、プロシージャの外部の num 変数の値は変化しません。

他の言語と同様、ObjectScript はパラメータを参照によって渡すことができるため、その変数値を

プロシージャで変更できます。 プロシージャを呼び出す場合は、変数名の先頭にドットを付けます。

dblbyref1 プロシージャは num を 2 倍にしますが、これは単にドットが num の前に付いている

ためです。 参照によってプロシージャにパラメータを渡すことができるのは、正確にプロシージャを

呼び出し、パラメータの前にドットが付いている場合のみです。 dblbyref2 プロシージャは

result と呼ばれる新規の変数を作成することによって、num を 2 倍にして返します。

SAMPLES>do ^passbyref

Enter a number: 3

3 doubled is: 6

3 doubled is: 6

6 doubled again is: 12

SAMPLES>

-91-

Page 92: Caché ObjectScript チュートリアルへようこそ。 このチュートリ … · チュートリアルへようこそ。 このチュートリアルでは、強力なオブジェクト型言語の基礎と、特有の機能について学習します。

Caché ObjectScript チュートリアル

passbyref.mac のコードは以下のとおりです。

passbyref ; passing parameters by value and reference

; pass by value

read !, "Enter a number: ", num

set dblnum = $$dblbyval( num )

write !, num, " doubled is: ", dblnum

; num passed IN and OUT by reference

write !, num

do dblbyref1( .num )

write " doubled is: ", num

; num passed IN by value

; result passed OUT by reference

do dblbyref2(num, .result)

write !, num, " doubled again is: ", result

quit

dblbyval(anynum) PUBLIC

{ quit anynum * 2 }

dblbyref1(anynum) PUBLIC

{ set anynum = anynum * 2

quit }

dblbyref2(anynum, double) PUBLIC

{ set double = anynum * 2

quit }

-92-

Page 93: Caché ObjectScript チュートリアルへようこそ。 このチュートリ … · チュートリアルへようこそ。 このチュートリアルでは、強力なオブジェクト型言語の基礎と、特有の機能について学習します。

Caché ObjectScript チュートリアル

第 3 章 – Chapter13

参照渡しのパラメータ(2)

下記の例は、パラメータを必ずしも参照によって渡す必要のないことを示しています。 例えば、プロ

シージャで複数の結果を返したい場合は、以下が可能です。

• 参照渡し:参照によって複数の変数を渡し、プロシージャで、それぞれが特定の結果を

持つ変数を作成します。

• 値渡し:区切り文字列や結果リストを返す関数としてのプロシージャを記述します。

他の例としては、num を 2 倍にする場合、dblbyref1 プロシージャで参照渡しを使用します。 あ

るいは、dblbyval プロシージャを使用して

snum=$$dblbyval(num)と記述しても同じ結果を取得できます。

後に、プロシージャに配列を渡す場合は、必ず参照渡しする必要があります。

passbyref.mac のコードは以下のとおりです。

passbyref ; passing parameters by value and reference

; pass by value

read !, "Enter a number: ", num

set dblnum = $$dblbyval( num )

write !, num, " doubled is: ", dblnum

; num passed IN and OUT by reference

write !, num

do dblbyref1( .num )

write " doubled is: ", num

; num passed IN by value

; result passed OUT by reference

do dblbyref2(num, .result)

write !, num, " doubled again is: ", result

quit

dblbyval(anynum) PUBLIC

{ quit anynum * 2 }

dblbyref1(anynum) PUBLIC

{ set anynum = anynum * 2

quit }

dblbyref2(anynum, double) PUBLIC

{ set double = anynum * 2

quit }

-93-

Page 94: Caché ObjectScript チュートリアルへようこそ。 このチュートリ … · チュートリアルへようこそ。 このチュートリアルでは、強力なオブジェクト型言語の基礎と、特有の機能について学習します。

Caché ObjectScript チュートリアル

第 3 章 – Chapter14

$Get 関数

$Get 関数を使用すると、変数の有無にかかわらず、確実に変数にアクセスします。変数が存在す

る場合、$Get は値を返します。 変数が存在しない場合、$Get は空文字列か$Get の 2 番目の

引数として指定した文字列を返します。

SAMPLES>write $get(fred)

SAMPLES>write $get(fred, 2)

2

SAMPLES>set fred = 1

SAMPLES>write $get(fred, 2)

1

SAMPLES>

定義の有無が不確かな配列にアクセスしたい場合、If 文と $Data 関数を使用してコードを記述

することもできますが(下記コード前半)、$Get 関数を使用する方が簡単です。

SAMPLES>set a(3) = "yes"

SAMPLES>set x = "no" if $data(a(3)) { set x = a(3) }

SAMPLES>write x

yes

SAMPLES>kill x

SAMPLES>set x = $get(a(3), "no")

SAMPLES>write x

yes

SAMPLES>

-94-

Page 95: Caché ObjectScript チュートリアルへようこそ。 このチュートリ … · チュートリアルへようこそ。 このチュートリアルでは、強力なオブジェクト型言語の基礎と、特有の機能について学習します。

Caché ObjectScript チュートリアル

第 3 章 – Chapter15

演習 6

mylookup ルーチンに以下のセクションを追加します。

• getsubmit にコードを追加して、電話番号のすべて、あるいは一部(617、617-621、

または 617-621-0600)を処理します。 一致する値を表示する phone プロシージャ

を記述します。$Order の 3 つの引数を指定します。 メモ : phone を記述していると

きに、バグが偶然発生する可能性があります。 解決方法は、演習ガイドを参照してくだ

さい。

• getsubmit にコードを追加して、名前のすべて、あるいは一部 (Smith,John、

Smith, J、Sm, John、Sm, J)を処理します。 一致する値を表示するには name プ

ロシージャを記述します。 ユーザ定義関数$$NameFormat は、$$up と$$low

関数を使用して、ユーザがどのように入力するかには関係なく、姓と名を適切な名前の

形式(1u.l)に変換します。

• オプション機能を使用して、help プロシージャを更新します。

• ローカル配列を使用して一致する値を追跡し、表示された一致番号に連結する ID 番号

を取得します。 select プロシージャを記述し、一致する値の選択もユーザが行えるよ

うにします。 display を変更し、“line”あるいは“table”の引数も受け入れを可能にし

ます。 display^mydatent()を使用して、“line”を選択した場合は一致した値を

横並びのリスト形式で表示し、“table”を選択した場合はユーザの選択を縦に表示しま

す。 データを縦に表示する前に、画面をクリアします。

詳細は、[Appendix I : 演習 6 :Lookup ルーチン、バージョン 2] を参照してください。

-95-

Page 96: Caché ObjectScript チュートリアルへようこそ。 このチュートリ … · チュートリアルへようこそ。 このチュートリアルでは、強力なオブジェクト型言語の基礎と、特有の機能について学習します。

Caché ObjectScript チュートリアル

第 3 章 – Chapter16

データベースの整合性

ObjectScript には、データベースの整合性を維持するためのコマンド、Lock、TStart と

TCommit があります。 lookup ルーチンに編集機能の追加準備の段階で、これらのコマンドを

学習します。 この 3 つのコマンドは、通常組み合わせて使用されます。 以下はコマンドの一般的

な使用方法です。

1. 修正するレコードを選択

2. レコードを Lock

3. 更新データを取得

4. TStart を実行

5. 新規データを格納

6. トランザクションに TCommit を指定

7. レコードの Lock を解除

Lock コマンドを使用すると、複数のユーザが同じレコードを同時に更新しようとする競合プロセス

を防ぐことができます。 ただし、規約に従った場合にのみ機能します。任意のグローバルを更新す

るアプリケーションのコードはすべて、更新されるレコードを必ず Lock するよう試みる必要があり、

終了後はロックを解除する必要があります。一つのルーチンが Lock を使用し、他方のルーチンが

使用していない場合、前者のルーチンがあるレコードをロックしていたとしても、後者のルーチンが

そのレコードを更新するのを妨げることはできません。(両者で、Lock-Lock 解除を使用する必要

があります。)

TStart コマンドと TCommit コマンドを使用すると、データベース・トランザクションを保護できま

す。 トランザクションとは、Set コマンド、あるいは Kill コマンドによるデータベースでの一連の処

理のことです。 すべてのトランザクションを完了させるか、あるいはまったく実行しないかのどちら

かにする必要があります。 これにより、トランザクションのグローバルすべて(例えばデータとイン

デックスの両方)が同期の状態を保ちます。

-96-

Page 97: Caché ObjectScript チュートリアルへようこそ。 このチュートリ … · チュートリアルへようこそ。 このチュートリアルでは、強力なオブジェクト型言語の基礎と、特有の機能について学習します。

Caché ObjectScript チュートリアル

第 3 章 – Chapter17

Lock コマンド(1)

ここでは Lock コマンドの機能とその使用法について学習します。 ロックをかける場合、システム

がロック・テーブルに Lock コマンドの引数を追加します。 別のプロセスで同じレコードをロックしよ

うとすると、 初のロックが解除されるまでそのプロセスを待機します。 2 つ目のプロセスが異なる

レコードを編集し、レコードに Lock をかけると、システムはロック・テーブルにもそのレコードを追加

します。 システム管理ポータル([運用]セクション)で、[[ホーム]→[ロック]]に移動し、ロック・テ

ーブルを表示します。

通常 Lock コマンドは、新規エントリを追加する前に、ロック・テーブル内ですべてのエントリをクリア

します。 他のロックをクリアせずにロック・テーブルにエントリを追加するには、Lock +を使用しま

す。 エントリを削除するには、Lock -を使用します。 Caché ターミナル・セッションを使用して、レ

コードをロックし、その後別のセッションを開始して同じレコードあるいは異なるレコードをロックして、

結果をロック・テーブルで参照できます。

SAMPLES>lock ^x(1) ; clear all locks for this process, and add ^x(1)

SAMPLES>lock ; clear all locks for this process

SAMPLES>lock +^x(1) ; add ^x(1) without clearing anything

SAMPLES>lock -^x(1) ; just clear ^x(1)

-97-

Page 98: Caché ObjectScript チュートリアルへようこそ。 このチュートリ … · チュートリアルへようこそ。 このチュートリアルでは、強力なオブジェクト型言語の基礎と、特有の機能について学習します。

Caché ObjectScript チュートリアル

lookup ルーチンの次の段階では、ユーザが個人データを修正できるコードを記述します。 つまり、

^PersonD グローバルと^PersonI グローバルを更新します。 この場合、ユーザが編集するレコ

ードと特定の ID を選択すると、これをルーチン lock +^PersonD(id)に追加します。 新規デー

タが格納された後に lock -^PersonD(id)を使用して、レコードのロックを解除します。

-98-

Page 99: Caché ObjectScript チュートリアルへようこそ。 このチュートリ … · チュートリアルへようこそ。 このチュートリアルでは、強力なオブジェクト型言語の基礎と、特有の機能について学習します。

Caché ObjectScript チュートリアル

第 3 章 – Chapter18

Lock コマンド(2)

通常の Lock は排他ロックです。 これまで見てきたように、排他ロックは他のロックを妨げます。

また、Caché は lock +^PersonD(id)#"s"構文を使用して、共有ロックをサポートします。 複

数の処理は同じ共有ロックを取る場合もあります。 しかし、共有ロックは排他ロックを妨げ、排他ロ

ックは共有ロックを妨げます。

Lock コマンドは、ロック・テーブルのエントリを確認、追加、削除するだけなので、Lock の対象は

既存のグローバルである必要はありません。例えば、^PersonD を編集中に、たとえ^Person と

いうグローバルが存在しなくても、(lock +^PersonD(id)ではなく) lock +^Person(id) を

実行することができます。 この場合は ^Person がロック・テーブルに追加され、^PersonD 配列

を編集するすべてのコードが^Person をロックしようと試みます。

^PersonI は、person データを含みますが、データを編集する際に、^PersonI をロックする必要

はありません。 これは、実際に配列を“ロックしている” わけではなく、単にエントリをロック・テーブ

ルに追加し、、グローバルの編集を許可するコードをロックしているだけだからです。 アプリケーシ

ョンでは、^PersonD を更新するすべてのコードが、同じ規約を使用します。 ^PersonD を更新

するコードはすべて必ず同時に^PersonI も更新するため、lock +^PersonD(id)だけで十分で

す。

^Person(1)がロック・テーブルにある場合は、別のプロセスで^Person(1)をロックすることはで

きません。 ただし、^Person(2)はロックできます。 つまり、ロック・テーブルには別のプロセスで

あれば兄弟のエントリを追加できます。 しかし、別のプロセスはロック・テーブル内のエントリの祖

先をロックすることはできません(この場合は ^Person)。これは、下位層のノードがロックされた場

合は、その上位層の配列にもアクセスさせないためです。 同様に、別のプロセスではロック・テー

ブルのエントリの子孫もロックできません(例 :^Person(1,2))。 ノード自身がロックされた場合

は、そのノードの子孫にもアクセスさせないためです。

-99-

Page 100: Caché ObjectScript チュートリアルへようこそ。 このチュートリ … · チュートリアルへようこそ。 このチュートリアルでは、強力なオブジェクト型言語の基礎と、特有の機能について学習します。

Caché ObjectScript チュートリアル

第 3 章 – Chapter19

Lock コマンドと Else コマンド

ObjectScript には、If 文の一部分ではない、完全に独立した Else コマンドがあります。 Else

の機能を理解するために、まずシステム変数$Test について学習します。 この変数の値は 0(偽)、

もしくは 1(真)で、システムが Lock のような特定のコマンドを評価する場合に設定されます。

Else には引数がないため、その直後には必ずスペースを 2 つ入れます。

Lock コマンドでタイムアウトを指定して、ロックの解除を永久に待つことがないようにします。 割り

当てた時間内に Lock できなかった場合、システムは$Test 変数に 0 を設定し、Else の後に続く

コードを実行します。

例:(別セッションで^x(1)をロック後実行。)

SAMPLES>lock +^x(1):5 else write "Try again later."

Try again later.

SAMPLES>

-100-

Page 101: Caché ObjectScript チュートリアルへようこそ。 このチュートリ … · チュートリアルへようこそ。 このチュートリアルでは、強力なオブジェクト型言語の基礎と、特有の機能について学習します。

Caché ObjectScript チュートリアル

第 3 章 – Chapter20

トランザクション処理

データの保存/削除をする場合、TStartコマンドをSet/Kill文の前に置き、その後にTCommit

コマンドを置きます。 これにより、Set/Kill 文はトランザクションとして処理を開始します。 システ

ムがトランザクション中にクラッシュした場合、(操作に戻った際に) 不完全なトランザクションをロー

ルバック (キャンセル) します。 すべてのトランザクションは完了しているか何も実行されていない

かのどちらかになります。

次のセクションで学習しますが、Caché オブジェクトや SQL テーブルでのオペレーションの保存や

削除は、トランザクション内で自動的に実行されます。

-101-

Page 102: Caché ObjectScript チュートリアルへようこそ。 このチュートリ … · チュートリアルへようこそ。 このチュートリアルでは、強力なオブジェクト型言語の基礎と、特有の機能について学習します。

Caché ObjectScript チュートリアル

第 3 章 – Chapter21

演習 7

mylookup ルーチンに編集機能を追加します。 • ユーザがリストから項目を選択すると、新規プロシージャ edit を呼び出すよう、main

にコードを追加します。

• edit プロシージャは、編集のために選択されたレコードをロックします。 その後、新規

のプロシージャ、load、reprompt、update を呼び出します。 更新終了後、レコー

ドのロックを解除します。

• load プロシージャは person データをロードします。 display プロシージャを更新し

て、この新規プロシージャを呼び出します。reprompt プロシージャはプロンプトに類

似しており、データ入力ルーチンから“$$valid”関数を使用し、現在のデータも表示しま

す。

• 値が変更された場合、update プロシージャがトランザクションを開始し、^PersonD

に新規データを保存します。 次に、^PersonI を更新します。 インデックスの更新と

は、インデックスの古いエントリに対して Kill を使用して、新規のエントリを追加すること

です。

詳細は、[Appendix J : 演習 7 :Lookup ルーチン、 終バージョン] を参照してください。

-102-

Page 103: Caché ObjectScript チュートリアルへようこそ。 このチュートリ … · チュートリアルへようこそ。 このチュートリアルでは、強力なオブジェクト型言語の基礎と、特有の機能について学習します。

Caché ObjectScript チュートリアル

第 3 章 – Chapter22

Caché オブジェクトと SQL

ObjectScript は、その名のとおり、objects にアクセスするコードを記述することもできますが、レ

コードにアクセスする SQL クエリも記述することができます。 このチュートリアルでは、クラス、オブ

ジェクト、プロパティ、メソッド、クエリについての説明は省略しますが、これらのトピックに関して学ぶ

には、他のチュートリアルを試してください。 ここでは、Persons データベースを使用して学習して

います。^PersonD グローバルのエントリは、1)Person クラスの永続オブジェクトや、2) Person

リレーショナル・テーブルの行と考えることができます。 ここでは、Caché オブジェクトを簡単に説

明します。

Caché スタジオを使用して、SAMPLES から COS プロジェクトをリロードします。[Classes]フォル

ダの[CosTutorial]パッケージにある Person クラスには、3 つのプロパティ、Name、Phone、

DOB があります。 このクラスによって、より簡単な文法(シンタックス)を使用しての Person オブ

ジェクトの利用が可能となります。 区切り文字を考慮する必要はありません。

-103-

Page 104: Caché ObjectScript チュートリアルへようこそ。 このチュートリ … · チュートリアルへようこそ。 このチュートリアルでは、強力なオブジェクト型言語の基礎と、特有の機能について学習します。

Caché ObjectScript チュートリアル

第 3 章 – Chapter23

Caché メソッド

Person クラスは組み込みのメソッドも提供しています。 メソッドとはオブジェクトで実行する

ObjectScript のプロシージャのことです。 使用できるメソッドは以下のとおりです。

• %New はローカル・メモリで新規の Person オブジェクトを作成します。

• %OpenId は永続 Person オブジェクトをローカル・メモリにロードします。

%OpenId は排他的ロックと共有ロックの両方をサポートします。

• %Save はローカル・メモリでの Person オブジェクトのデータを確認します。 正しく確

認された場合は、そのデータを保存します。 オブジェクトの%Save は、トランザクショ

ンとして自動的に作動します。

新規にPersonオブジェクトを作成する場合は、%Newを使用してデータの設定を行い(以下に示

している“ドット・シンタックス”を使用します)、%Save を使用します。 既存オブジェクトを編集する

には、%OpenId を使用してデータの更新を行い(ここでもドット・シンタックスを使用しま

す)、%Save を使用します。

Person オブジェクトのプロパティを参照するには、ドット構文(<オブジェクト>.<プロパティ>)を使

用します。 下記 1 行目は ID が 2 の既存の Person オブジェクトを開きます。次に、データの保存

方法に関係なく、per を使用して person オブジェクトのプロパティを参照できます。 per を””に設

定して、person オブジェクトのローカル・コピーを削除します。

SAMPLES>set per = ##class(CosTutorial.Person).%OpenId(2)

SAMPLES>write per.Name

Agee,Tommie

SAMPLES>write per.Phone

617-333-3333

SAMPLES>write per.DOB

37110

SAMPLES>set per = ""

SAMPLES>

-104-

Page 105: Caché ObjectScript チュートリアルへようこそ。 このチュートリ … · チュートリアルへようこそ。 このチュートリアルでは、強力なオブジェクト型言語の基礎と、特有の機能について学習します。

Caché ObjectScript チュートリアル

第 3 章 – Chapter24

Caché オブジェクト・ストレージ

Cachéクラスは、既定では区切り文字列の代わりにListを使用して構築したグローバルを使用しま

す。 チュートリアルを続けるにあたり、^PersonD をこの配列構造を使用するように変換し、また

^PersonI の“Phone”セクションに小規模な変更を加えます。 dbconvert と呼ばれる、既に記

述されたルーチンがあります。 Caché ターミナル・セッションを開始し、do ̂ dbconvert() を実

行します。

変換後は、mydatent と mylookup ルーチンは作動しません(次の演習では、新規のバージョ

ンを作成します)。 システム管理ポータルで変換の結果を参照できます。ここで各レコードは、3 つ

の要素をリスト表示($ListBuild 関数により)しています。また、^PersonI の“Phone”セクション

が若干変更され、ID が添え字になっています。

データを元の形式に変換する場合は、do goback^dbconvert()を実行してください。 そうする

と、mydatent と mylookup を再び使用することができます。

-105-

Page 106: Caché ObjectScript チュートリアルへようこそ。 このチュートリ … · チュートリアルへようこそ。 このチュートリアルでは、強力なオブジェクト型言語の基礎と、特有の機能について学習します。

Caché ObjectScript チュートリアル

第 3 章 – Chapter25

演習 8

この演習では、mydatent ルーチンと mylookup ルーチンを変更し、新規に mydatentobj

と mylookupobj を作成します。

• Cachéスタジオを使用し mydatentルーチンをロードして、mydatentobjとして保

存します。 データを格納するオブジェクト構文を使用するため store プロシージャを編

集します。

• mylookup ルーチンをロードし、mylookupobj として保存します。 load プロシー

ジャを編集し、オブジェクト構文で ^PersonD から選択した person データがロードさ

れるようにします。update プロシージャを編集して、オブジェクト構文で ^PersonD

にデータを格納するようにします。 ^PersonI の新規構造が反映されるように phone

プロシージャを編集します。

詳細は、[Appendix K : 演習 8 :データ入力と検索のオブジェクト・バージョン] を参照してくださ

い。

-106-

Page 107: Caché ObjectScript チュートリアルへようこそ。 このチュートリ … · チュートリアルへようこそ。 このチュートリアルでは、強力なオブジェクト型言語の基礎と、特有の機能について学習します。

Caché ObjectScript チュートリアル

第 3 章 – Chapter26

第 3 章の要約

第 3 章では ObjectScript の便利な機能について学習しました。

• 関数 : $Order、$Translate、$Get

• コマンド : Else (および $Test)、Lock、TStart、TCommit

• 参照渡しのパラメータ

• %New、%OpenIdと%Saveの標準メソッドを使用して、オブジェクトへアクセスするコ

ードの記述方法

このチュートリアルをご利用いただき、ありがとうございました。 Caché ObjectScriptについてさ

らに学習するには、Cachéドキュメント:[Caché開発リファレンス]-[ Caché ObjectScript リファ

レンス]を参照してください。

プロジェクトのすべてを 1 つのポータブル・ファイルに保存する方法は以下のとおりです。

1. [スタジオ]を起動します。

2. [ファイル]→[ネームスペース変更]をクリックして、[SAMPLES] ネームスペースに

接続します。

3. [ツール]→[エクスポート]をクリックします。

4. [現プロジェクトのエクスポート]と[ローカル・ファイルにエクスポート]オプションを選択

します。

5. フォルダを調べ、mycos.xml を指定して、[保存]をクリックします。

6. [OK]をクリックします。

-107-

Page 108: Caché ObjectScript チュートリアルへようこそ。 このチュートリ … · チュートリアルへようこそ。 このチュートリアルでは、強力なオブジェクト型言語の基礎と、特有の機能について学習します。

Caché ObjectScript チュートリアル

Appendix B:

サンプル・アプリケーション

Caché をインストールすると、SAMPLES ネームスペースで、チュートリアル・アプリケーションの開

発や実行に必要なすべてのファイルもインストールされます。 CosTutorial.xml ファイルは 既定では、C:¥program files¥cachesys¥dev¥tutorials にイン

ストールされます。

アプリケーションを SAMPLES に再ロードしたり、他のネームスペースにロードする場合は、以下の

作業を行います。

1. [スタジオ]を起動します。

2. [ファイル]→[ネームスペース変更]をクリックし、アプリケーションをロードするネーム

スペースに接続します。

3. [ツール]→[ローカルからインポート]をクリックし、[XML]を選択します。

c:¥program files¥cachesys¥dev¥tutorials を検索します。

4. [CosTutorial.xml]ファイルを選択し、[開く]をクリックします。

-108-

Page 109: Caché ObjectScript チュートリアルへようこそ。 このチュートリ … · チュートリアルへようこそ。 このチュートリアルでは、強力なオブジェクト型言語の基礎と、特有の機能について学習します。

Caché ObjectScript チュートリアル

RightTriangle /* compute area and hypotenuse of a right triangle

this routine contains examples of

new ObjectScript features */

Write !, "Compute the area and hypotenuse of a right triangle",

!, "given the lengths of its two sides."

Read !!, "First, choose a unit of measurement. ",

!, "(i)nches, (f)eet, (m)iles, ",

"(c)entimeters, m(e)ters, (k)ilometers: ", units

// translate units to a full word

Set units = $case( $extract( units, 1),

"i":"inches",

"f":"feet",

"m":"miles",

"c":"centimeters",

"e":"meters",

"k":"kilometers",

:"units" )

Do {

Read !!,

"Length of side 1: ", side1

Quit:(side1 = "")

// exit the do loop

}

While $$IsNegative( side1 )

Quit:(side1 = "") // exit the routine

Do {

Read !,

"Length of side 2: ", side2

Quit:(side2 = "")

// exit the do loop

}

While $$IsNegative( side2 )

Quit:(side2 = "") // exit the routine

Do Compute( units, side1, side2)

Quit

Appendix C:

Right Triangle ルーチン

-109-

Page 110: Caché ObjectScript チュートリアルへようこそ。 このチュートリ … · チュートリアルへようこそ。 このチュートリアルでは、強力なオブジェクト型言語の基礎と、特有の機能について学習します。

Caché ObjectScript チュートリアル

IsNegative(num) PUBLIC // is num negative?

{

If (num '> 0) {

Write " Enter a positive number."

Quit 1 // return "true"

}

Else {

Write " Accepted."

Quit 0 // return "false"

}

}

Compute(units,A,B) // compute and display area and hypotenuse

{

Set area = ( A * B ) / 2,

area = $justify( area, 0, 2),

// set up %X, which INT%SQROOT requires

%X = ( A ** 2 ) + ( B ** 2 )

// INT^%SQROOT returns its result by setting %Y

Do INT^%SQROOT

// now, round %Y to 2 places

Set hypot = $justify( %Y, 0, 2)

Write !!, "The area of this triangle is ", area, " square ", units, ".",

!!, "The hypotenuse is ", hypot, " ", units, "."

}

-110-

Page 111: Caché ObjectScript チュートリアルへようこそ。 このチュートリ … · チュートリアルへようこそ。 このチュートリアルでは、強力なオブジェクト型言語の基礎と、特有の機能について学習します。

Caché ObjectScript チュートリアル

Appendix D:

演習 1 : 初のデータ入力ルーチン

1. Caché スタジオを開始し、[SAMPLES] ネームスペースで新規のルーチンを作成し

ます。

2. 以下の ObjectScript を入力します。

mydatent ; first data entry routine

read !, "Name: " , name

if name="" {quit } ; user entered nothing

read !, "Phone: ", phone

read !, "DOB: ", dob

write !!

display ; display the data

write !, "Name:", ?20, name

write !, "Phone:", ?20, phone

write !, "DOB:", ?20, dob

quit

3. [ファイル]→[保存] をクリックします。

4. ファイル名に mydatent を指定し、[ファイルの種類] フィールドで “マクロルーチ

ン” を指定します。[名前を付けて保存] をクリックします。それによってルーチンを自

動的にコンパイルします。

5. Caché ターミナルを開始し、SAMPLES ネームスペースで do ^mydatent と入

力してルーチンを起動します。

-111-

Page 112: Caché ObjectScript チュートリアルへようこそ。 このチュートリ … · チュートリアルへようこそ。 このチュートリアルでは、強力なオブジェクト型言語の基礎と、特有の機能について学習します。

Caché ObjectScript チュートリアル

Appendix E:

演習 2 : 2番目のデータ入力ルーチン

1. Caché スタジオを開始し、mydatent ルーチンを開きます。

2. 以下の ObjectScript を入力します。

mydatent ; second data entry routine

main ; main loop section

do {

do prompt()

quit:(name = "")

do display()

}

while name'=""

quit

prompt() [name, phone, dob]

{

; procedure for prompting

read !, "Name: ", name

quit:(name="") ; user entered nothing

read !, "Phone: ", phone

read !, "DOB: ", dob

write !!

}

display() [name, phone, dob]

{

; display the data

write !, "Name:", ?20, name

write !, "Phone:", ?20, phone

write !, "DOB:", ?20, dob

}

-112-

Page 113: Caché ObjectScript チュートリアルへようこそ。 このチュートリ … · チュートリアルへようこそ。 このチュートリアルでは、強力なオブジェクト型言語の基礎と、特有の機能について学習します。

Caché ObjectScript チュートリアル

Appendix F:

演習 3 : データ入力ルーチンの更新

1. Caché スタジオを開始し、mydatent ルーチンを開きます。

2. ユーザ定義関数 $$validName を入力します。

validName(name) PUBLIC ; validate a Name

/* returns 0 for an invalid name and writes error message

returns the unchanged name otherwise */

{

if (name?1u.l1","1u.l) {

quit name }

else {

write !,"Last,First"

quit 0

}

}

3. ユーザ定義関数 $$validPhone を入力します。電話番号の検証後、必要な場合

は既定のエリア・コードを追加します。

validPhone(phone) PUBLIC ; validate a phone number

/* returns 0 for invalid phone numbers and writes error message

returns the valid phone number with default area code added

if necessary */

{

if (phone?.1(3n1"-")3n1"-"4n) {

set:(phone?3n1"-"4n) phone = "617-" _ phone ; add default area code

quit phone

}

else {

write !, "###-###-#### or ###-####"

quit 0

}

}

-113-

Page 114: Caché ObjectScript チュートリアルへようこそ。 このチュートリ … · チュートリアルへようこそ。 このチュートリアルでは、強力なオブジェクト型言語の基礎と、特有の機能について学習します。

Caché ObjectScript チュートリアル

4. ユーザ定義関数 $$validDOB を入力します。未来の日付を許可しないようにしま

す。

validDOB(date) PUBLIC ; validate a Date of Birth

/* returns 0 for invalid dates and writes error message

returns internal format for valid dates */

{

set convdate = $zdateh( date, 5,,,,,,, -1)

if (convdate = -1) {

write !,"Date in the past"

quit 0 ; invalid date

}

elseif (convdate > $piece( $horolog, ",", 1)) {

write !,"Date in the past"

quit 0 ; invalid because it's in the future

}

else {

quit convdate ; valid date

}

}

5. prompt プロシージャを編集します。Do/While 文で、新しい、3 つのユーザ定義

関数 “$$valid~~~” を使用し、データが正しく入力されるまでプロンプトを繰り返

します。

prompt() [name, phone, intdob]

{

do {

read !, "Name: ", name

quit:(name = "") ; user entered nothing

set name = $$validName( name )

}

while name = 0

quit:(name = "") ; exit procedure

do {

read !, "Phone (617): ", phone

set phone = $$validPhone( phone )

}

while phone = 0

-114-

Page 115: Caché ObjectScript チュートリアルへようこそ。 このチュートリ … · チュートリアルへようこそ。 このチュートリアルでは、強力なオブジェクト型言語の基礎と、特有の機能について学習します。

Caché ObjectScript チュートリアル

do {

read !, "DOB: ", dob

set intdob = $$validDOB( dob )

}

while intdob = 0

write !!

}

6. display プロシージャを編集します。希望の外部形式でデータの変換コードを追加し

ます。

display() [name, phone, intdob]

; display the data

{

write !, "Name:", ?20, name

write !, "Phone:", ?20, phone

write !, "DOB:", ?20, $zdate( intdob, 2)

write !!

}

-115-

Page 116: Caché ObjectScript チュートリアルへようこそ。 このチュートリ … · チュートリアルへようこそ。 このチュートリアルでは、強力なオブジェクト型言語の基礎と、特有の機能について学習します。

Caché ObjectScript チュートリアル

1. Caché スタジオを開始し、mydatent ルーチンを開きます。完成したルーチンも、

datent.mac として SAMPLES ネームスペースで確認できます。

2. main ルーチンを編集します。display プロシージャの後、store プロシージャを呼

び出します。

do display()

do store()

3. 電話番号がインデックスに既に存在するかどうかをチェックするため、$$validPhone

関数の、既定のエリア・コードを追加する行の後に、If 文を追加します。

set:(phone?3n1"-"4n) phone = "617-" _ phone ; add default area code

if $data( ^PersonI( "Phone", phone)) {

write !, "Phone number in use"

quit 0

}

else {

quit phone

}

4. 新規の store プロシージャを追加します。

store() [name, phone, intdob]

; store the data

{

read !, "Store? (y/n): ", yn ; see if user wants to store

if ( yn '= "y" ) { ; only go on if user says yes

write "...not stored."

quit

}

set id = $increment( ^PersonD ) ; use $i to generate a new id

set rec = name _ "^" _ phone _ "^" _ intdob ; concatenate data into a

record

set ^PersonD( id ) = rec ; store the record

set ln = $piece(name, ",", 1),

fn = $piece(name, ",", 2) ; break name for storage in index

-116-

Appendix G:

演習 4 : ストレージ・プロシージャの追加

Page 117: Caché ObjectScript チュートリアルへようこそ。 このチュートリ … · チュートリアルへようこそ。 このチュートリアルでは、強力なオブジェクト型言語の基礎と、特有の機能について学習します。

Caché ObjectScript チュートリアル

/* the next three statements store data in subscripts

because of the automatic sorting of subscripts,

this has the effect of building 3 indexes: name, phone, and DOB */

set ^PersonI( "Name", ln, fn, id) = "" ; store the name

set ^PersonI( "Phone", phone) = id ; store the UNIQUE phone

set ^PersonI( "DOB", intdob, id) = "" ; store the DOB

write "...stored" ; done

}

5. ルーチンを保存して、実行し、データを複数格納します。システム管理ポータルでグロ

ーバルを表示します。

-117-

Page 118: Caché ObjectScript チュートリアルへようこそ。 このチュートリ … · チュートリアルへようこそ。 このチュートリアルでは、強力なオブジェクト型言語の基礎と、特有の機能について学習します。

Caché ObjectScript チュートリアル

1. Cachéスタジオを開始し、新規ルーチンを作成します。 このルーチンの完成したバー

ジョンも、lookup1.mac として、SAMPLES ネームスペースで利用できます。

2. 以下のコードを入力します。

mylookup ; display an ordered list of matches

; user can enter a valid date of birth

main ; main section

; start looping

for {

do getsubmit() ; let user submit a string for lookup

quit:(submit = "")

}

quit

getsubmit() [submit] ; ask user what to search for, and take appropriate

action

{

read !, "Lookup: ", submit

quit:(submit = "") ; user entered nothing

; figure out what user entered

if (submit = "?") { ; display help

do help()

quit

}

if $$validDOB^mydatent( submit ) { ; use validDOB^datent to verify the

DOB

write "...finding birthday"

do dob()

quit

}

}

help() ; display different types of lookups

{ write !, "You can enter:", !?10, "* date of birth", !! }

Appendix H:

演習 5 : Lookup ルーチン、バージョン 1

-118-

Page 119: Caché ObjectScript チュートリアルへようこそ。 このチュートリ … · チュートリアルへようこそ。 このチュートリアルでは、強力なオブジェクト型言語の基礎と、特有の機能について学習します。

Caché ObjectScript チュートリアル

dob() [submit] ; perform dob lookup

; no partial matches

{

set intdob = $$validDOB^mydatent( submit ) ; convert dob

; is the date of birth in the index?

if '$data( ^PersonI("DOB", intdob) ) { ; determine if there are any

matches

write "...no matches"

quit

}

set loopid = ""

; loop through ids, and number them

for count = 1 : 1 {

set loopid = $order( ^PersonI("DOB", intdob, loopid) )

quit:(loopid = "")

write !, count, ") "

do display( loopid )

}

}

display(id) ; given an id, get data and write it

{

set rec = ^PersonD( id )

set name = $piece(rec, "^", 1)

set phone = $piece(rec, "^", 2)

set intdob = $piece(rec, "^", 3)

write name, ?20, phone, ?35, $zdate(intdob, 2)

}

3. [ファイル]→[保存] をクリックします。

4. ファイル名に mylookup を指定し、[ファイルの種類]フィールドで “マクロルーチン”

を指定します。 [名前を付けて保存]をクリックします。

5. Caché ターミナルを開始し、SAMPLES ネームスペースで do ^mylookup と入力し

てルーチンを起動します。

-119-

Page 120: Caché ObjectScript チュートリアルへようこそ。 このチュートリ … · チュートリアルへようこそ。 このチュートリアルでは、強力なオブジェクト型言語の基礎と、特有の機能について学習します。

Caché ObjectScript チュートリアル

Appendix I :

演習 6 : Lookup ルーチン、バージョン 2

1. 以下は新規でより長い lookup ルーチンです。 わかりやすいようにセクションを分

割して表示しています。 この完成したルーチンも lookup2.mac として、SAMPLES

ネームスペースで利用可能です。

2. getsubmit プロシージャを修正します。$$validDOB^datent はエラー・メッセ

ージを記述するため、If 文の 後にもってきます。 そうすることによって、あまり早い

段階からメッセージを記述することもありません。

getsubmit() [submit, id] ; ask user what to search for, and take appropriate action

{

set id = 0

read !, "Lookup: ", submit

quit:(submit = "") ; user entered nothing

; figure out what user entered

if (submit = "?") { ; display help

do help()

quit

}

elseif submit?3n.1(1"-"3n.1(1"-"4n)) { ; allow full or partial phone numbers

write "...finding phone number"

do phone( .id ) quit:(id = 0)

do display(id, "table") ; display the chosen person

}

elseif $$NameFormat( .submit )?1u.l.1(1","1u.l) { ; verify the name

write "...finding name"

do name( .id ) quit:(id = 0)

do display(id, "table") ; display the chosen person

}

elseif $$validDOB^datent( submit ) { ; use validDOB^datent to verify the DOB

write "...finding birthday"

do dob( .id ) quit:(id = 0)

do display(id, "table") ; display the chosen person

quit

}

else { ; else it's an error; add this to what $$validDOB writes

write ", name, or phone" }

}

-120-

Page 121: Caché ObjectScript チュートリアルへようこそ。 このチュートリ … · チュートリアルへようこそ。 このチュートリアルでは、強力なオブジェクト型言語の基礎と、特有の機能について学習します。

Caché ObjectScript チュートリアル

3. dob プロシージャを変更します。

dob(id) [submit, list] ; perform dob lookup

; no partial matches

; if user picks a name from the list, id is returned to the caller

{

kill list

set intdob = $$validDOB^datent( submit ) ; convert dob

; is the date of birth in the index?

if '$data( ^PersonI("DOB", intdob) ) { ; determine if there are any

matches

write "...no matches"

quit

}

set loopid = ""

; loop through ids, and number them

for count = 1 : 1 {

set loopid = $order( ^PersonI("DOB", intdob, loopid) )

quit:(loopid = "")

set list( count ) = loopid

write !, count, ") "

do display(loopid, "line")

}

do select( .id )

}

4. 以下は phone プロシージャです。 検索のために 3 桁のエリア・コードを指定すると、

演習で述べたバグが発生します。 $Order は、“-”文字ではなく、数としてこれを解

釈するので、以下の 初の$Order は正しい結果を返しません。 回避策として、 初

の $Order の前の行で、エリア・コードに“-”を追加します。

phone(id) [submit, list] ; perform phone lookup

; if user picks a name from the list, id is returned to the caller

{

kill list

set count = 0 ; assume no matches

set origph = submit

set:(origph?3n) origph = origph _ "-"

; change to a string instead of a number

-121-

Page 122: Caché ObjectScript チュートリアルへようこそ。 このチュートリ … · チュートリアルへようこそ。 このチュートリアルでは、強力なオブジェクト型言語の基礎と、特有の機能について学習します。

Caché ObjectScript チュートリアル

; origph may be an exact match, if not, advance using $order

set ph = origph

if '$data( ^PersonI("Phone", origph)) {

set ph = $order( ^PersonI("Phone", origph), 1, loopid) }

else {

set loopid = ^PersonI("Phone", origph) }

/* loop through phone numbers, and number them,

quit as soon as phone doesn't match original

loopid holds the ONE id per phone number */

for count = 1 : 1 {

quit:( $extract(ph, 1, $length(origph)) '= origph )

set list( count ) = loopid

write !, count, ") "

do display(loopid, "line")

set ph = $order( ^PersonI("Phone", ph), 1, loopid)

}

if '$data( list ) { ; were there matches?

write "...no matches"

quit

}

do select( .id )

}

5. 以下は name プロシージャです。

name(id) [submit, list] ; perform name lookup

; if user picks a name from the list, id is returned to the caller

{

kill list

set count = 0 ; assume no matches

set origln = $piece(submit, ",", 1), origfn = $piece(submit, ",", 2)

; origln may be an exact match, if not, advance using $order

set ln = origln

if '$data( ^PersonI("Name", origln))

{

set ln = $order( ^PersonI("Name", origln))

}

; loop through last names,

; quit as soon as last name doesn't match original

-122-

Page 123: Caché ObjectScript チュートリアルへようこそ。 このチュートリ … · チュートリアルへようこそ。 このチュートリアルでは、強力なオブジェクト型言語の基礎と、特有の機能について学習します。

Caché ObjectScript チュートリアル

for

{

quit:($extract(ln, 1, $length(origln)) '= origln)

; origfn may be an exact match, if not, advance using $order

set fn = origfn

if (origfn = "") || '$data( ^PersonI("Name", ln, origfn))

{

set fn = $order( ^PersonI("Name", ln, origfn))

}

; loop through first names,

; quit as soon as first name doesn't match original, or is ""

for

{

quit:(($extract(fn, 1, $length(origfn)) '= origfn) || (fn = ""))

set loopid = ""

; loop through ids

for

{

set loopid = $order( ^PersonI("Name", ln, fn, loopid))

quit:( loopid = "" )

set count = count + 1

set list( count ) = loopid

write !, count, ") "

do display(loopid, "line")

}

set fn = $order( ^PersonI("Name", ln, fn))

}

set ln = $order( ^PersonI("Name", ln))

}

if '$data( list )

{ ; were there matches?

write "...no matches"

quit

}

do select( .id )

}

-123-

Page 124: Caché ObjectScript チュートリアルへようこそ。 このチュートリ … · チュートリアルへようこそ。 このチュートリアルでは、強力なオブジェクト型言語の基礎と、特有の機能について学習します。

Caché ObjectScript チュートリアル

6. 以下は、$$NameFormat、$$up、$$low 関数です。

NameFormat(name) ; change user's entry into proper name format

; SMITH,JOHN and smith,john -> Smith,John

; if name is passed-by-reference, it will be changed

{

set ln = $piece(name, ",", 1), fn = $piece(name, ",", 2)

set ln = $$up($extract(ln)) _ $$low($extract(ln, 2, $length(ln)))

if fn = "" { ; return last name only

set name = ln

quit name

}

set fn = $$up($extract(fn)) _ $$low($extract(fn, 2, $length(fn)))

set name=ln _ "," _ fn ; return full name

quit name

}

up(text) ; translate text to upper case

{ quit $translate(text,

"abcdefghijklmnopqrstuvwxyz",

"ABCDEFGHIJKLMNOPQRSTUVWXYZ") }

low(text) ; translate text to lower case

{ quit $translate(text,

"ABCDEFGHIJKLMNOPQRSTUVWXYZ",

"abcdefghijklmnopqrstuvwxyz") }

7. help プロシージャを変更します。

help() ; display different types of lookups

{

write !, "You can enter:"

write !?10, "* full name: Smith,John", !?10, "* last name: Smith"

write !?10, "* partial name: Sm,J or Smith,J or Sm,John"

write !?10, "* phone number with area code: 617-621-0600"

write !?10, "* partial phone numbers: 617 or 617-621"

write !?10, "* date of birth", !!

}

-124-

Page 125: Caché ObjectScript チュートリアルへようこそ。 このチュートリ … · チュートリアルへようこそ。 このチュートリアルでは、強力なオブジェクト型言語の基礎と、特有の機能について学習します。

Caché ObjectScript チュートリアル

8. display プロシージャを変更します。

display(id, style) [name, phone, intdob] ; given an id, get data and write

it

{

set rec = ^PersonD( id )

set name = $piece(rec, "^", 1)

set phone = $piece(rec, "^", 2)

set intdob = $piece(rec, "^", 3)

if style = "line" {

write name, ?20, phone, ?35, $zdate(intdob, 2) }

else {

write # ; clear screen

do display^datent()

}

}

9. 以下は select プロシージャです。

select(id) [list] ; choose from the displayed items, and set up id

; id is 0 if no choice is made, id is >0 when user makes a choice

{

for {

read !!, "Choose by number: ", choice

quit:( choice = "" )

set id = $get(list( choice ), 0)

quit:(id '= 0) ; valid choice

write !, "Invalid choice"

}

}

-125-

Page 126: Caché ObjectScript チュートリアルへようこそ。 このチュートリ … · チュートリアルへようこそ。 このチュートリアルでは、強力なオブジェクト型言語の基礎と、特有の機能について学習します。

Caché ObjectScript チュートリアル

Appendix J :

演習 7 : Lookup ルーチン、 終バージョン

1. 以下は、 終 mylookup ルーチンです。 わかりやすいように、セクションを分割し

て表示しています。 このルーチンも lookup.mac として、SAMPLES ネームスペー

スで利用可能です。

2. do getsubmit ; let user submit a string for lookup 行の後の main セクショ

ンにこのコードを追加します。

quit:(submit = "")

do:(id '= 0) edit( id ) ; edit the chosen person

3. 以下は新規の edit プロシージャです。

edit(id) ; allow user to choose, and edit their choice

{

for {

read !, "Edit? (y/n): " ,yn

if yn '= "y" {

write "...no changes."

quit

}

; try to lock the record

lock +^PersonD( id ):5

if $test { ; the lock was successful

quit

}

else {

write "...someone else is editing this person"

}

}

quit:(yn '= "y")

do load( id )

do reprompt()

read !, "Store? (y/n): ", yn

if yn '= "y" {

write "...no changes."

lock -^PersonD( id ) ; unlock the record

quit

}

do update( id )

lock -^PersonD( id ) ; unlock the record

}

-126-

Page 127: Caché ObjectScript チュートリアルへようこそ。 このチュートリ … · チュートリアルへようこそ。 このチュートリアルでは、強力なオブジェクト型言語の基礎と、特有の機能について学習します。

Caché ObjectScript チュートリアル

4. 以下は新規の load プロシージャです。

load(id) [rec, name, phone, intdob] ; load a person into local variables

{

set rec = ^PersonD(id)

set name = $piece(rec, "^", 1)

set phone = $piece(rec, "^", 2)

set intdob = $piece(rec, "^", 3)

}

5. 以下は更新した display プロシージャで、load プロシージャを呼び出しています。

display(id, style) [name, phone, intdob] ; given an id, get data and write

it

{

do load( id )

if style = "line" {

write name, ?20, phone, ?35, $zdate(intdob, 2) }

else {

write # ; clear screen

do display^datent()

}

}

6. 以下は新規の reprompt プロシージャです。

reprompt() [name, phone, intdob, newname, newphone, newintdob]

; show current data and allow user to update it

{

do {

write !, "Name: ", name, "=> " read newname

set:(newname = "") newname = name ; default

set newname = $$validName^datent( newname )

}

while newname = 0

do {

write !, "Phone (617): ", phone, "=> " read newphone

set:(newphone = "") newphone = phone ; default

set newphone = $$validPhone^datent( newphone )

}

while newphone = 0

-127-

Page 128: Caché ObjectScript チュートリアルへようこそ。 このチュートリ … · チュートリアルへようこそ。 このチュートリアルでは、強力なオブジェクト型言語の基礎と、特有の機能について学習します。

Caché ObjectScript チュートリアル

do {

write !, "DOB: ", $zdate(intdob, 2), "=> " read newdob

set:(newdob = "") newdob = $zdate(intdob, 2) ; default

set newintdob = $$validDOB^datent( newdob )

}

while newintdob = 0

write !! }

7. 以下は新規の update プロシージャです。

update(id) [rec, name, phone, intdob, newname, newphone, newintdob]

; update ^PersonD and ^PersonI

{

; concatenate the data into a record

set newrec = newname _ "^" _ newphone _ "^" _ newintdob

if rec = newrec {

write "...no changes made."

quit

}

tstart ; start a transaction

set ^PersonD( id ) = newrec ; store the record

if newname '= name { ; kill old name and add new name to index

set ln = $piece(name, ",", 1), fn = $piece(name, ",", 2)

set nln = $piece(newname, ",", 1), nfn = $piece(newname, ",", 2)

kill ^PersonI("Name", ln, fn, id)

set ^PersonI("Name", nln, nfn, id) = ""

}

if newphone '= phone { ; kill old phone and add new phone to index

kill ^PersonI("Phone", phone)

set ^PersonI("Phone", newphone) = id

}

if newintdob '= intdob { ; kill old dob and add new dob to index

kill ^PersonI("DOB", intdob, id)

set ^PersonI("DOB", newintdob, id) = ""

}

tcommit ; commit the transaction

write "...updated." }

-128-

Page 129: Caché ObjectScript チュートリアルへようこそ。 このチュートリ … · チュートリアルへようこそ。 このチュートリアルでは、強力なオブジェクト型言語の基礎と、特有の機能について学習します。

Caché ObjectScript チュートリアル

Appendix K :

演習 8 : データ入力と検索のオブジェクト・バージョン

1. 以下は mydatentobj の新しい store プロシージャです。

store() [name, phone, intdob]

; store the data

{

read !, "Store? (y/n): ", yn ; see if user wants to store

if ( yn '= "y" ) { ; only go on if user says yes

write "...not stored."

quit

}

set per = ##class(CosTutorial.Person).%New() ; create a new person

set per.Name = name

set per.Phone = phone

set per.DOB = intdob

do per.%Save() ; store the record, in a transaction,

; including storage in indexes!

set per = "" ; release the person

write "...stored" ; done

}

2. 以下は mylookupobj の新しい load プロシージャです。

load(id) [name, phone, intdob] ; load a person into local variables

{

set per = ##class(CosTutorial.Person).%OpenId(id)

set name = per.Name

set phone = per.Phone

set intdob = per.DOB

set per = ""

}

-129-

Page 130: Caché ObjectScript チュートリアルへようこそ。 このチュートリ … · チュートリアルへようこそ。 このチュートリアルでは、強力なオブジェクト型言語の基礎と、特有の機能について学習します。

Caché ObjectScript チュートリアル

-130-

3. 以下は mylookupobj の新しい update プロシージャです。

update(id) ; update ^PersonD and ^PersonI

{

set per = ##class(CosTutorial.Person).%OpenId(id)

set per.Name = newname

set per.Phone = newphone

set per.DOB = newintdob

do per.%Save() ; this updates indexes too,

; all within a transaction!

set per = ""

write "...updated."

}

4. この行を変更して、mylookupobj の phone プロシージャを更新します。

set ph = $order( ^PersonI("Phone", origph), 1, loopid)

以下のとおり変更します。

set ph = $order( ^PersonI("Phone", origph))

set:( ph '= "") loopid = $order( ^PersonI("Phone", ph, ""))

5. 次にこの行を変更します。

set loopid = ^PersonI("Phone", origph)

以下のとおり変更します。

set loopid = $order( ^PersonI("Phone", origph, ""))

6. 次にこの行を変更します。

set ph = $order( ^PersonI("Phone", ph), 1, loopid)

以下のとおり変更します。

set ph = $order( ^PersonI("Phone", ph))

set:( ph '= "") loopid = $order( ^PersonI("Phone", ph, ""))