Created
August 18, 2015 12:45
-
-
Save evshvarov/9490a93154395e5dc6d7 to your computer and use it in GitHub Desktop.
ForEach case in Caché Object Script
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/// Класс-итератор для коллекций. | |
Class test.ForEach Extends %RegisteredObject [ Final ] | |
{ | |
/// Коллекция-список <s>почти</s> любого типа. | |
Property collection As %Collection.AbstractList [ Internal, Private, ReadOnly, Transient ]; | |
/// Инициализация свойства <property>collection</property>. | |
/// <br><br> Допустимые аргументы <var>val</var>: | |
/// <br> <li>объект класса-наследника от %Collection.AbstractList; | |
/// <br> <li>список простых элементов в формате $List; | |
/// <br> <li>список простых элементов в формате строки. В этом случае <var>sep</var> - разделитель элементов в строке; | |
Method %OnNew(val, sep = ",") As %Status [ Private, ServerOnly = 1 ] | |
{ | |
if $IsObject(val) { | |
quit:'val.%Extends("%Collection.AbstractList") $$$ERROR($$$OrefInvalid,val) | |
set r%collection=val | |
}else{ | |
set r%collection=##class(%ListOfDataTypes).%New() | |
do ..collection.InsertList($select($listvalid(val):val,1:$listfromstring(val,sep))) | |
} | |
quit $$$OK | |
} | |
/// Основной метод-обработчик. | |
/// <br> | |
/// <br>Аргументы: | |
/// <br> | |
/// <br><var>func</var>:<ol><li>имя метода экземпляра класса</li><li>имя метода класса (любого)</li><li>код в формате команды <link href=/DocBook.UI.Page.cls?KEY=RCOS_cxecute>xecute</link></li><li>некоторые сокращённые команды</li></ol> | |
/// Примеры вызова:<example> | |
/// s obj=##class(test.ForEach).%New("2,3,5") | |
/// ; для каждого элемента коллекции будет вызван соответствующий метод класса с передачей аргументов. | |
/// ; Первый аргумент выходной/входной, остальные - входные, но это лишь способ соглашения. | |
/// ; При желании можно поменять их местами, сделать несколько выходных и т.д. | |
/// d obj.Do("className:methodName",.result,param1,param2,paramN) | |
/// ; сумма элементов (имеет смысл лишь для коллекции чисел) | |
/// d obj.Do("+",.result) | |
/// ; произведение (имеет смысл лишь для коллекции чисел) | |
/// d obj.Do("*",.result) | |
/// ; конкатенация с разделителем (имеет смысл лишь для коллекции простых типов) | |
/// d obj.Do("_",.result,separator) | |
/// ; минимум (имеет смысл лишь для коллекции простых типов) | |
/// d obj.Do("min",.result) | |
/// ; максимум (имеет смысл лишь для коллекции простых типов) | |
/// d obj.Do("max",.result) | |
/// ; среднее (имеет смысл лишь для коллекции чисел) | |
/// d obj.Do("avg",.result) | |
/// ; любой код, где el=элемент коллекции, args=переданные аргументы | |
/// d obj.Do($lb("s args(1,1)=args(1,1)+el"),.result) ; эквивалент "+" | |
/// ; вызов подпрограммы sub^prog с передачей аргументов | |
/// d obj.Do($lb("d sub^prog(el,args...)"),.result,param1,param2,paramN) | |
/// </example> | |
/// | |
Method Do(func = "+", Args...) As %Status | |
{ | |
#define ReturnOnError(%expr) s sc=%expr ret:$$$ISERR(sc) sc | |
quit:'..collection.Count() $$$OK | |
if func="+" { | |
set func=$listbuild("s args(1,1)=args(1,1)+el") | |
}elseif func="*" { | |
set func=$listbuild("s args(1,1)=args(1,1)*el") | |
}elseif func="_" { | |
set func=$listbuild("s args(1,1)=args(1,1)_args(1,2)_el") | |
}elseif func="min" { | |
set func=$listbuild("s:el<args(1,1) args(1,1)=el"),Args(1)=999999999999999 | |
}elseif func="max" { | |
set func=$listbuild("s:el>args(1,1) args(1,1)=el"),Args(1)=-999999999999999 | |
}elseif func="avg" { | |
set func=$listbuild("s args(1,1)=el/args(1,2)+args(1,1)"),Args=2,Args(2)=..collection.Count() kill Args(1) | |
} | |
if $listvalid(func) { | |
set cmd=$list(func) | |
$$$ReturnOnError(##class(%Routine).CheckSyntax(" "_cmd)) | |
set cmd="(el,args...){"_cmd_"}" | |
set key = "" | |
for { | |
set el = ..collection.GetNext(.key) | |
quit:key="" | |
xecute (cmd,el,.Args) | |
} | |
}else{ | |
if func[":" { | |
set className=$piece(func,":",1) | |
set methodName=$piece(func,":",2) | |
quit:'##class(%Dictionary.MethodDefinition).IDKEYExists(className,methodName) $$$ERROR($$$MethodDoesNotExist,func) | |
quit:'$$$defMemberKeyGet(className,"m",methodName,23) $$$ERROR($$$GeneralError,$$$FormatText("Метод %1 не является методом класса %2",methodName,className)) | |
set key = "" | |
for { | |
set el = ..collection.GetNext(.key) | |
quit:key="" | |
$$$ReturnOnError($classmethod(className,methodName,el,.Args)) | |
} | |
}else{ | |
set methodName=func | |
set key = "" | |
for { | |
set el = ..collection.GetNext(.key) | |
quit:key="" | |
set className=$classname(el) | |
return:'##class(%Dictionary.MethodDefinition).IDKEYExists(className,methodName) $$$ERROR($$$MethodDoesNotExist,className_":"_methodName) | |
return:$$$defMemberKeyGet(className,"m",methodName,23) $$$ERROR($$$GeneralError,$$$FormatText("Метод %1 не является методом экземпляра класса %2",methodName,className)) | |
$$$ReturnOnError($method(el,methodName,.Args)) | |
} | |
} | |
} | |
quit $$$OK | |
} | |
/// <example>d ##class(test.ForEach).Test()</example> | |
ClassMethod Test() [ Internal ] | |
{ | |
set old=$system.Process.Undefined(2) | |
try{ | |
;============================== КОЛЛЛЕКЦИЯ ПРОСТЫХ ТИПОВ ДАННЫХ ============================= | |
set t=##class(test.ForEach).%New("2,3,5") | |
;s t=##class(test.ForEach).%New("2,3,5,asd") | |
;s t=##class(test.ForEach).%New(##class(test.ForEach).%New()) ;раскомментируйте, чтобы увидеть ошибку | |
if '$IsObject(t) $$$ThrowStatus(%objlasterror) | |
write !,"==========",!,"test.myclass:Dump",!! | |
$$$ThrowOnError(t.Do("test.myclass:Dump")) | |
; или $$$ThrowOnError(t.Do("test.myclass:Dump",.result)) | |
write !,"==========",!,"test.myclass:Dump(.r=""result"",""p1"",""p2"")",!! | |
set r="result" $$$ThrowOnError(t.Do("test.myclass:Dump",.r,"p1","p2")) | |
write !,"==========",!,"test.myclass:Sum(.r)",!! | |
$$$ThrowOnError(t.Do("test.myclass:Sum",.r)) write "Результат = ",r,! | |
;$$$ThrowOnError(t.Do("test.myclass:Sum",.r,5)) ;раскомментируйте, чтобы увидеть ошибку | |
write !,"==========",!,"+10",!! set r=10 | |
$$$ThrowOnError(t.Do(,.r)) write "Результат = ",r,! | |
write !,"==========",!,"+",!! kill r | |
$$$ThrowOnError(t.Do(,.r)) write "Результат = ",r,! | |
write !,"==========",!,"*",!! set r=1 | |
$$$ThrowOnError(t.Do("*",.r)) write "Результат = ",r,! | |
write !,"==========",!,"_ + разделитель=""^""",!! kill r | |
$$$ThrowOnError(t.Do("_",.r,"^")) write "Результат = ",r,! | |
write !,"==========",!,"min (входной аргумент не учитывается)",!! | |
set r="asd" $$$ThrowOnError(t.Do("min",.r)) write "Результат = ",r,! | |
write !,"==========",!,"max (входной аргумент не учитывается)",!! | |
set r="asd" $$$ThrowOnError(t.Do("max",.r)) write "Результат = ",r,! | |
write !,"==========",!,"avg (входной аргумент не учитывается)",!! | |
set r="asd" $$$ThrowOnError(t.Do("avg",.r)) write "Результат = ",r,! | |
write !,"==========",!,"s args(1,1)=args(1,1)+el",!! | |
kill r $$$ThrowOnError(t.Do($listbuild("s args(1,1)=args(1,1)+el"),.r)) write r,! | |
write !,"==========",!,"d sub^prog(el,args...) [.r=""r"",""p1"",""p2""]",!! | |
set r="r" $$$ThrowOnError(t.Do($listbuild("d sub^prog(el,args...)"),.r,"p1","p2")) | |
;============================== КОЛЛЛЕКЦИЯ СЛОЖНЫХ ТИПОВ ДАННЫХ ============================= | |
set list=##class(%ListOfObjects).%New() | |
for i="f1","f2","f3" do list.Insert(##class(test.myclass).%New(i)) | |
;f i="f1","f2","f3",7 d list.Insert(##class(test.myclass).%New(i)) | |
set t=##class(test.ForEach).%New(list) | |
if '$IsObject(t) $$$ThrowStatus(%objlasterror) | |
write !,"++++++++++",!,"test.myclass:Dump",!! | |
$$$ThrowOnError(t.Do("test.myclass:Dump")) | |
write !,"++++++++++",!,"PrintLn",!! | |
$$$ThrowOnError(t.Do("PrintLn")) | |
write !,"++++++++++",!,"PrintLn(,""Элемент = "")",!! | |
$$$ThrowOnError(t.Do("PrintLn",,"Элемент = ")) | |
write !,"++++++++++",!,"Concat(.r)",!! kill r | |
$$$ThrowOnError(t.Do("Concat",.r)) write "Результат = ",r,! | |
;$$$ThrowOnError(t.Do("Concat",.r,"f3")) w "Результат = ",r,! ;раскомментируйте, чтобы увидеть ошибку | |
write !,"++++++++++",!,"SetField(,""blablabla"") + PrintLn(,""Элемент = "")",!! | |
$$$ThrowOnError(t.Do("SetField",,"blablabla")) $$$ThrowOnError(t.Do("PrintLn",,"Элемент = ")) | |
write !,"++++++++++",!,"d el.PrintLn(.args)",!! | |
$$$ThrowOnError(t.Do($listbuild("d el.PrintLn(.args)"))) | |
write !,"++++++++++",!,"w ""field="",el.field,!",!! | |
$$$ThrowOnError(t.Do($listbuild("w ""field="",el.field,!"))) | |
}catch(ex){ | |
#dim ex As %Exception.AbstractException | |
write ex.DisplayString() | |
} | |
do $system.Process.Undefined(old) | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Class test.myclass Extends %RegisteredObject | |
{ | |
/// Строковое поле. | |
Property field; | |
/// Инициализация свойства <property>field</property>. | |
Method %OnNew(field) As %Status [ Internal, Private, ServerOnly = 1 ] | |
{ | |
set ..field=field | |
quit $$$OK | |
} | |
/// Заполнение <property>field</property> первым <u>входным</u> аргументом. | |
Method SetField(Args...) As %Status | |
{ | |
set ..field=Args(1,2) | |
quit $$$OK | |
} | |
/// Вывод <property>field</property> и первого <u>входного</u> аргумента. | |
Method PrintLn(Args...) As %Status | |
{ | |
write Args(1,2),$$$quote(..field),! | |
quit $$$OK | |
} | |
/// Конкатенация <property>field</property> с разделителем (<span style="color:green;">метод <b>экземпляра</b> класса</span>). | |
/// <br>Если первый входной аргумент совпадает с <var>field</var>, генерируем ошибку (<span style="color:red;">для демонстрационных целей!</span>) | |
Method Concat(Args...) As %Status | |
{ | |
set Args(1,1)=Args(1,1)_Args(1,2)_..field | |
quit $select(..field=Args(1,2):$$$ERROR($$$GeneralError,$$$FormatText("Возникла ошибка на элементе: %1",..field)),1:$$$OK) | |
} | |
/// Сумма <var>elem</var> (<span style="color:green;">метод класса</span>). | |
/// <br>Если первый <u>входной</u> аргумент совпадает с <var>elem</var> (он же <property>field</property>), генерируем ошибку (<span style="color:red;">для демонстрационных целей!</span>) | |
ClassMethod Sum(elem, Args...) As %Status | |
{ | |
set Args(1,1)=Args(1,1)+elem | |
quit $select(elem=Args(1,2):$$$ERROR($$$GeneralError,$$$FormatText("Возникла ошибка на элементе: %1",elem)),1:$$$OK) | |
} | |
/// Вывод всех аргументов. | |
/// <br><br> <var>elem</var> = элемент коллекции | |
/// <br> <var>Args</var>(1) = кол-во переданных аргументов кроме первого, т.е. <var>elem</var> | |
/// <br> <var>Args</var>(1,1) = аргумент 1 (<span style="color:red;">у нас это входной/выходной аргумент</span>) | |
/// <br> <var>Args</var>(1,2) = аргумент 2 | |
/// <br> ... | |
/// <br> <var>Args</var>(1,n) = аргумент n | |
ClassMethod Dump(elem, Args...) As %Status | |
{ | |
set params="" | |
for i=2:1:Args(1) set params=params_$listbuild(Args(1,i)) | |
if '$IsObject(elem) { | |
set el=elem | |
}elseif elem.%Extends("test.myclass"){ | |
set el=elem.field | |
}else{ | |
set el=elem.%ClassName($$$YES) | |
} | |
write "Элемент = ",$$$quote(el),", Выходной аргумент = ",$$$quote(Args(1,1)),", Дополнительные аргументы = ",$$$quote($listtostring(params)),! | |
quit $$$OK | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment