├── dev.md
├── test
└── cls
│ └── DeclarativeCOS
│ ├── JoinerTests.cls
│ └── BinderTests.cls
├── src
├── cls
│ └── DeclarativeCOS
│ │ ├── IO.cls
│ │ ├── DeclarativesManager.cls
│ │ ├── Utils.cls
│ │ ├── Joiner.cls
│ │ ├── Examples.cls
│ │ ├── DeclarativeProvider.cls
│ │ └── Binder.cls
└── mac
│ ├── %ZLANGC00.ro
│ └── %ZLANGF00.ro
├── LICENSE
└── README.md
/dev.md:
--------------------------------------------------------------------------------
1 | [Related Skype](https://join.skype.com/NNXbVHzSpgKg)
2 |
3 | [Dev server](198.211.126.144)
4 |
--------------------------------------------------------------------------------
/test/cls/DeclarativeCOS/JoinerTests.cls:
--------------------------------------------------------------------------------
1 | Class DeclarativeCOS.JoinerTests Extends %UnitTest.TestCase
2 | {
3 |
4 | Method TestJoin()
5 | {
6 | set words = ##class(%ListOfDataTypes).%New()
7 | do words.Insert("DeclarativeCOS")
8 | do words.Insert("is")
9 | do words.Insert("awesome!")
10 |
11 | do $$$AssertEquals("DeclarativeCOS is awesome!", $zjoin(words, " "), "$zjoin works!")
12 | }
13 |
14 | }
15 |
16 |
--------------------------------------------------------------------------------
/src/cls/DeclarativeCOS/IO.cls:
--------------------------------------------------------------------------------
1 | /// The class provides IO declaratives.
2 | /// io:print <-> w value
3 | /// io:println <-> w value, !
4 | Class DeclarativeCOS.IO Extends DeclarativeCOS.DeclarativeProvider
5 | {
6 |
7 | /// Output passed value.
8 | ///
9 | /// @Declarative("io:print")
10 | ClassMethod print(value As %Library.DataType)
11 | {
12 | w value
13 | }
14 |
15 | /// Output passed value. Add newline symbol.
16 | ///
17 | /// @Declarative("io:println")
18 | ClassMethod println(value As %Library.DataType)
19 | {
20 | w value, !
21 | }
22 |
23 | }
24 |
25 |
--------------------------------------------------------------------------------
/src/mac/%ZLANGC00.ro:
--------------------------------------------------------------------------------
1 | QUIT
2 | .
3 | //
4 | // "zforeach" command.
5 | //
6 | // Applies the certain function to each element of the collection.
7 | //
8 | // Example:
9 | // NAMESPACE> set collection = ##class(%ListOfDataTypes).%New()
10 | // NAMESPACE> do collection.Insert("Hello ")
11 | // NAMESPACE> do collection.Insert("World!")
12 | // NAMESPACE>
13 | // NAMESPACE> zforeach $zbind(collection, "io:print")
14 | //
15 | // See also:
16 | // DeclarativeCOS.Binder
17 | // DeclarativeCOS.Binder#ForEach
18 | // DeclarativeCOS.IO
19 | //
20 | ZFOREACH(binder) public {
21 | do binder.ForEach()
22 | Quit
23 | }
24 |
25 |
--------------------------------------------------------------------------------
/src/cls/DeclarativeCOS/DeclarativesManager.cls:
--------------------------------------------------------------------------------
1 | /// Manager for declaratives.
2 | /// The class contains methods for saving and retrieving declaratives from ^DeclarativeCOS global.
3 | Class DeclarativeCOS.DeclarativesManager
4 | {
5 |
6 | /// Stores declarative to the ^DeclarativeCOS global.
7 | ClassMethod saveDeclarative(declarativeName As %String, className As %String, functionName As %String)
8 | {
9 | set ^DeclarativeCOS("functions", declarativeName) = $lb(className, functionName)
10 | }
11 |
12 | /// Loads declarative from the ^DeclarativeCOS global.
13 | ClassMethod loadDeclarative(declarativeName As %String)
14 | {
15 | return $get(^DeclarativeCOS("functions", declarativeName))
16 | }
17 |
18 | }
19 |
20 |
--------------------------------------------------------------------------------
/src/cls/DeclarativeCOS/Utils.cls:
--------------------------------------------------------------------------------
1 | /// Some utils for DeclarativeCOS implementation.
2 | Class DeclarativeCOS.Utils
3 | {
4 |
5 | /// Declarative name regular expression.
6 | /// The pattern is "namespace:function"
7 | Parameter DECLARATIVENAMEREGEX [ Internal ] = "[a-zA-Z0-9]+(.[a-zA-Z0-9]+)*\s*:\s*[a-zA-Z0-9]+([a-zA-Z0-9_]+)*";
8 |
9 | /// Returns $$$YES if specified name is satisfied by the DECLARATIVENAMEREGEX regex.
10 | /// Otherwise, returns $$$NO.
11 | ClassMethod isValidName(name As %String) As %Boolean
12 | {
13 | return ##class(%Regex.Matcher).%New("^" _ ..#DECLARATIVENAMEREGEX _ "$", name).Locate()
14 | }
15 |
16 | /// Returns declarative name without any space characters.
17 | ClassMethod normalizeName(name As %String) As %String
18 | {
19 | if (..isValidName(name)) {
20 | return $replace(name, " ", "")
21 | }
22 |
23 | return name
24 | }
25 |
26 | }
27 |
28 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2017 InterSystems Corporation
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/src/cls/DeclarativeCOS/Joiner.cls:
--------------------------------------------------------------------------------
1 | /// Joiner is a kind of text utils class.
2 | /// The main point of the class is join elemenet of collection using separator.
3 | Class DeclarativeCOS.Joiner
4 | {
5 |
6 | /// Returns string from elements of the specified collection usin the certain separator.
7 | /// Example:
8 | /// NAMESPACE> set words = ##class(%ListOfDataTypes).%New()
9 | /// NAMESPACE> do words.Insert("DeclarativeCOS")
10 | /// NAMESPACE> do words.Insert("is")
11 | /// NAMESPACE> do words.Insert("awesome!")
12 | /// NAMESPACE>
13 | /// NAMESPACE> write $jzoin(words, " ")
14 | /// NAMESPACE> DeclarativeCOS is awesome!
15 | ClassMethod join(collection As %Collection.AbstractList, separator As %String = "") As %String
16 | {
17 | if (collection = "") {
18 | return ""
19 | }
20 |
21 | set string = ""
22 |
23 | set index = ""
24 |
25 | for {
26 | set index = collection.Next(index)
27 |
28 | quit:index=""
29 |
30 | set item = collection.GetAt(index)
31 |
32 | if (string = "") {
33 | set string = "" _ item
34 | }
35 | else {
36 | set string = string _ separator _ item
37 | }
38 | }
39 |
40 | return string
41 | }
42 |
43 | }
44 |
45 |
--------------------------------------------------------------------------------
/src/cls/DeclarativeCOS/Examples.cls:
--------------------------------------------------------------------------------
1 | /// Set of DeclarativeCOS examples.
2 | Class DeclarativeCOS.Examples Extends DeclarativeCOS.DeclarativeProvider
3 | {
4 |
5 | /// Returns hex value of the passed value.
6 | ///
7 | /// @Declarative("examples:toHex")
8 | ClassMethod toHex(value As %Numeric)
9 | {
10 | return $zhex(value)
11 | }
12 |
13 | /// Returns $$$YES if passed value is prime number.
14 | /// Otherwise, returns $$$NO.
15 | ///
16 | /// @Declarative("examples:isPrime")
17 | ClassMethod isPrime(value As %Numeric)
18 | {
19 | for i=2:1:$zsqr(value) {
20 | if (value # i = 0) {
21 | return $$$NO
22 | }
23 | }
24 |
25 | return $$$YES
26 | }
27 |
28 | /// Returns $$$YES if passed value is odd number.
29 | /// Otherwise, returns $$$NO.
30 | ///
31 | /// @Declarative("examples:isOdd")
32 | ClassMethod isOdd(value As %Numeric)
33 | {
34 | return value # 2 '= 0
35 | }
36 |
37 | /// Returns $$$YES if passed value is even number.
38 | /// Otherwise, returns $$$NO.
39 | ///
40 | /// @Declarative("examples:isEven")
41 | ClassMethod isEven(value As %Numeric)
42 | {
43 | return value # 2 = 0
44 | }
45 |
46 | /// Returns $$$YES if passed value is palindromic number.
47 | /// Otherwise, returns $$$NO.
48 | ///
49 | /// @Declarative("examples:isPalindromic")
50 | ClassMethod isPalindromic(value As %Numeric)
51 | {
52 | return $reverse(value) = value
53 | }
54 |
55 | }
56 |
57 |
--------------------------------------------------------------------------------
/src/cls/DeclarativeCOS/DeclarativeProvider.cls:
--------------------------------------------------------------------------------
1 | /// The heart of DeclarativeCOS!
2 | /// All declarative providers must extend the class.
3 | Class DeclarativeCOS.DeclarativeProvider
4 | {
5 |
6 | /// The DeclarativeCOS magic.
7 | /// Code generator for registration declaratives in
8 | /// special global: ^DeclarativeCOS
9 | ClassMethod register() [ CodeMode = objectgenerator ]
10 | {
11 | if (%compiledclass.Name = "DeclarativeCOS.DeclarativeProvider") {
12 | kill ^DeclarativeCOS
13 | }
14 |
15 | set methods = %compiledclass.Methods
16 |
17 | set i = ""
18 |
19 | for {
20 | set i = methods.Next(i)
21 |
22 | quit:i=""
23 |
24 | set method = methods.GetAt(i)
25 |
26 | set methodName = method.Name
27 |
28 | set methodDescription = method.Description
29 |
30 | continue:methodName="register"
31 |
32 | continue:$extract(methodName)="%"
33 |
34 | set declarativeNameRegex = ##class(DeclarativeCOS.Utils).#DECLARATIVENAMEREGEX
35 |
36 | set annotationRegexp = "@Declarative\(""(" _ declarativeNameRegex _ ")""\)"
37 |
38 | set annotationMatcher = ##class(%Regex.Matcher).%New(annotationRegexp, methodDescription)
39 |
40 | if (annotationMatcher.Locate()) {
41 | set annotationValue = $replace(annotationMatcher.Group(1), " ", "")
42 |
43 | do ##class(DeclarativeCOS.DeclarativesManager).saveDeclarative(annotationValue, %compiledclass.Name, methodName)
44 | }
45 | }
46 |
47 | d %code.WriteLine(" q")
48 |
49 | q $$$OK
50 | }
51 |
52 | }
53 |
54 |
--------------------------------------------------------------------------------
/test/cls/DeclarativeCOS/BinderTests.cls:
--------------------------------------------------------------------------------
1 | Class DeclarativeCOS.BinderTests Extends (%UnitTest.TestCase, DeclarativeCOS.DeclarativeProvider)
2 | {
3 |
4 | Parameter TESTGLOBALNAME As %String = "^DeclarativeCOSTests";
5 |
6 | /// @Declarative("test.forEach:toGlobal")
7 | ClassMethod toGlobal(word As %String)
8 | {
9 | set global = $name(@..#TESTGLOBALNAME@("forEach"))
10 |
11 | if ('$data(@global@("word1"))) { set @global@("word1") = word }
12 |
13 | elseif ('$data(@global@("word2"))) { set @global@("word2") = word }
14 |
15 | elseif ('$data(@global@("word3"))) { set @global@("word3") = word }
16 | }
17 |
18 | Method TestForEach()
19 | {
20 | set global = $name(@..#TESTGLOBALNAME@("forEach"))
21 |
22 | kill @global
23 |
24 | set $lb(word1, word2, word3) = $lb("ForEach", "is", "available")
25 |
26 | set words = ##class(%ListOfDataTypes).%New()
27 | do words.Insert(word1)
28 | do words.Insert(word2)
29 | do words.Insert(word3)
30 |
31 | zforeach $zbind(words, "test.forEach:toGlobal")
32 |
33 | do $$$AssertEquals(word1, $get(@global@("word1")), "Word #1 is equal")
34 | do $$$AssertEquals(word2, $get(@global@("word2")), "Word #2 is equal")
35 | do $$$AssertEquals(word3, $get(@global@("word3")), "Word #3 is equal")
36 |
37 | kill @global
38 | }
39 |
40 | Method TestMap()
41 | {
42 | set numbers = ##class(%ListOfDataTypes).%New()
43 |
44 | for i=1:1:10 { do numbers.Insert($random(1000)) }
45 |
46 | set hexNumbers = $zmap(numbers, "examples:toHex")
47 |
48 | for i=1:1:numbers.Count() { do numbers.SetAt($zhex(numbers.GetAt(i)), i) }
49 |
50 | do $$$AssertEquals($zjoin(numbers, ","), $zjoin(hexNumbers, ","), "$zmap works!")
51 | }
52 |
53 | Method TestFind()
54 | {
55 | set numbers = ##class(%ListOfDataTypes).%New()
56 |
57 | for i=1:1:10 { do numbers.Insert($random(1000)) }
58 |
59 | set expectedPrimeNumber = ""
60 |
61 | for i=1:1:numbers.Count() {
62 | set number = numbers.GetAt(i)
63 |
64 | if (##class(DeclarativeCOS.Examples).isPrime(number)) {
65 | set expectedPrimeNumber = number
66 | }
67 |
68 | quit:expectedPrimeNumber'=""
69 | }
70 |
71 | set actualPrimeNumber = $zfind(numbers, "examples:isPrime")
72 |
73 | do $$$AssertEquals(expectedPrimeNumber, actualPrimeNumber, "$zfind works!")
74 | }
75 |
76 | Method TestFilter()
77 | {
78 | set numbers = ##class(%ListOfDataTypes).%New()
79 |
80 | for i=1:1:10 { do numbers.Insert($random(1000)) }
81 |
82 | set expectedFilteredNumbers = ##class(%ListOfDataTypes).%New()
83 |
84 | for i=1:1:numbers.Count() {
85 | set number = numbers.GetAt(i)
86 |
87 | if (##class(DeclarativeCOS.Examples).isOdd(number)) {
88 | do expectedFilteredNumbers.Insert(number)
89 | }
90 | }
91 |
92 | set actualFilteredNumbers = $zfilter(numbers, "examples:isOdd")
93 |
94 | do $$$AssertEquals($zjoin(expectedFilteredNumbers, ","), $zjoin(actualFilteredNumbers, ","), "$zfilter works!")
95 | }
96 |
97 | Method TestExists()
98 | {
99 | set numbers = ##class(%ListOfDataTypes).%New()
100 |
101 | for i=1:1:10 { do numbers.Insert($random(1000)) }
102 |
103 | set expectedHasEvenNumber = $$$NO
104 |
105 | for i=1:1:numbers.Count() {
106 | set number = numbers.GetAt(i)
107 |
108 | if (##class(DeclarativeCOS.Examples).isEven(number)) {
109 | set expectedHasEvenNumber = $$$YES
110 | }
111 |
112 | quit:expectedHasEvenNumber'=""
113 | }
114 |
115 | set actualHasEvenNumber = $zexists(numbers, "examples:isEven")
116 |
117 | do $$$AssertEquals(expectedHasEvenNumber, actualHasEvenNumber, "$zexists works!")
118 | }
119 |
120 | Method TestCount()
121 | {
122 | set numbers = ##class(%ListOfDataTypes).%New()
123 |
124 | for i=1:1:10 { do numbers.Insert($random(1000)) }
125 |
126 | set expectedPalindromicNumbersCount = 0
127 |
128 | for i=1:1:numbers.Count() {
129 | set number = numbers.GetAt(i)
130 |
131 | if (##class(DeclarativeCOS.Examples).isPalindromic(number)) {
132 | set expectedPalindromicNumbersCount = $increment(expectedPalindromicNumbersCount)
133 | }
134 | }
135 |
136 | set actualPalindromicNumbersCount = $zcount(numbers, "examples:isPalindromic")
137 |
138 | do $$$AssertEquals(expectedPalindromicNumbersCount, actualPalindromicNumbersCount, "$zcount works!")
139 | }
140 |
141 | }
142 |
143 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Welcome to the DeclarativeCOS!
2 | ## (available for Caché 2015.1+)
3 |
4 |
5 |
6 | # What is DeclarativeCOS?
7 |
8 | DeclarativeCOS - is another view to programming on the Caché ObjectScript language. It allows you to write the code in declarative style.
9 |
10 |
11 | # What is declarative style in COS?
12 |
13 | Declarative style in COS means that you write the code as a statement which describes what you need to do.
14 |
15 |
16 | # What is the difference from my one-liners code?
17 |
18 | The main point is not to add one-liners features to COS. The main point is to bring another kind of mind when you do your task. DeclarativeCOS allows to remove regular loops from your code, because you really don't need it.
19 |
20 |
21 | # What is the problem with my regular loops in COS?
22 |
23 | Loop is just an instrument to solve the problem. In common, the problem is to traverse by collection and do some action with every element. Do you really need a loop for it? No. You choose a loop because COS supports loops only. DeclarativeCOS allows to write the code in declarative style. Just declare what you want to do and DeclarativeCOS will do all the rest for you.
24 |
25 |
26 | # OK. Examples, please.
27 |
28 | **What is about output collection?**
29 | ```
30 | /// Usual way
31 |
32 | set i = collection.Next("")
33 |
34 | while (i '= "") {
35 | set item = collection.GetAt(i)
36 |
37 | w item,!
38 |
39 | set i = collection.Next(i)
40 | }
41 | ```
42 | ```
43 | /// New way
44 |
45 | d ##class(DeclarativeCOS.Binder).%New(collection, "io:println").ForEach()
46 |
47 | /// or
48 |
49 | zforeach $zbind(collection, "io:println")
50 | ```
51 |
52 | **What is about output collection? (one more)**
53 | ```
54 | /// Usual way
55 |
56 | set i = collection.Next("")
57 |
58 | while (i '= "") {
59 | set item = collection.GetAt(i)
60 |
61 | w item _ " "
62 |
63 | set i = collection.Next(i)
64 | }
65 | ```
66 | ```
67 | /// New way
68 |
69 | w ##class(DeclarativeCOS.Joiner).join(collection, " ")
70 |
71 | /// or
72 |
73 | w $zjoin(collection, " ")
74 | ```
75 |
76 |
77 | # How to install it?
78 |
79 | In releases of the repo you can find two xml files:
80 | **install.base.xml**,
81 | **install.advanced.xml**.
82 |
83 | The first file installs all needed classes to perform any examples above.
84 |
85 | The second file installs short functions and commands: zforeach, $zmap, $zfind, $zfilter, $zexists, $zcount, $zjoin.
86 |
87 |
88 | # OK. How does it work?
89 |
90 | **5 steps:**
91 | - Extends from DeclarativeCOS.DeclarativeProvider.
92 | - Implement class method.
93 | - Mark the method.
94 | - Use one of provided DeclarativeCOS statements.
95 | - Enjoy the result.
96 |
97 |
98 |
99 | # Any example, please.
100 |
101 | Suppose, we need to output all items of the list (for example, list is instance of [%ListOfDataTypes](http://docs.intersystems.com/latest/csp/documatic/%25CSP.Documatic.cls?PAGE=CLASS&LIBRARY=%25SYS&CLASSNAME=%25Library.ListOfDataTypes)).
102 |
103 | **Step 1. Extends from DeclarativeCOS.DeclarativeProvider.**
104 | ```
105 | Class MyPackage.IO extens DeclarativeProvider
106 | {
107 | }
108 | ```
109 |
110 | **Step 2. Implement class method.**
111 | ```
112 | Class MyPackage.IO extens DeclarativeProvider
113 | {
114 |
115 | ClassMethod print(value As %String)
116 | {
117 | w value
118 | }
119 |
120 | }
121 | ```
122 |
123 | **Step 3. Mark the method.**
124 | ```
125 | Class MyPackage.IO extens DeclarativeProvider
126 | {
127 |
128 | /// @Declarative("io:print")
129 | ClassMethod print(value As %String)
130 | {
131 | w value
132 | }
133 |
134 | }
135 | ```
136 |
137 | **Step 4. Use one of provided DeclarativeCOS statements.**
138 | ```
139 | s words = ##class(%Library.ListOfDataTypes).%New()
140 | d words.Insert("Hello ")
141 | d words.Insert("World!")
142 |
143 | zforeach $zbind(words, "io:print")
144 | ```
145 |
146 | **Step 5. Enjoy the result.**
147 | ```
148 | Hello World!
149 | ```
150 |
151 | # What is about LICENCE?
152 |
153 | MIT License
154 |
155 | Copyright (c) 2017 InterSystems Corporation
156 |
157 | Permission is hereby granted, free of charge, to any person obtaining a copy
158 | of this software and associated documentation files (the "Software"), to deal
159 | in the Software without restriction, including without limitation the rights
160 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
161 | copies of the Software, and to permit persons to whom the Software is
162 | furnished to do so, subject to the following conditions:
163 |
164 | The above copyright notice and this permission notice shall be included in all
165 | copies or substantial portions of the Software.
166 |
167 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
168 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
169 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
170 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
171 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
172 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
173 | SOFTWARE.
174 |
175 | # Discuss?
176 | [here](https://community.intersystems.com/post/declarativecos-%E2%80%94-declarative-programming-cach%C3%A9)
177 |
--------------------------------------------------------------------------------
/src/mac/%ZLANGF00.ro:
--------------------------------------------------------------------------------
1 | QUIT
2 | .
3 | //
4 | // "$zbind" function.
5 | //
6 | // Returns new instance of DeclarativeCOS.Binder with specified collection and function.
7 | //
8 | // Example:
9 | // NAMESPACE> set collection = ##class(%ListOfDataTypes).%New()
10 | // NAMESPACE> do collection.Insert("Hello ")
11 | // NAMESPACE> do collection.Insert("World!")
12 | // NAMESPACE>
13 | // NAMESPACE> zforeach $zbind(collection, "io:print")
14 | // NAMESPACE> Hello World!
15 | //
16 | // See also:
17 | // DeclarativeCOS.Binder
18 | // DeclarativeCOS.Binder#%New
19 | // DeclarativeCOS.Binder#ForEach
20 | // DeclarativeCOS.IO
21 | //
22 | ZBIND(collection, function) public {
23 | Quit ##class(DeclarativeCOS.Binder).%New(collection, function)
24 | }
25 | .
26 | //
27 | // "$zmap" function.
28 | //
29 | // Returns new collection where each item is result of apply the certain function to source item of the specified collection.
30 | //
31 | // Example:
32 | // NAMESPACE> set numbers = ##class(%ListOfDataTypes).%New()
33 | // NAMESPACE> do numbers.Insert($random(100))
34 | // NAMESPACE> do numbers.Insert($random(100))
35 | // NAMESPACE> do numbers.Insert($random(100))
36 | // NAMESPACE>
37 | // NAMESPACE> write "[" _ $zjoin(numbers, ",") _ "]"
38 | // NAMESPACE> [82,12,27]
39 | // NAMESPACE>
40 | // NAMESPACE> set hexNumbers = $zmap(numbers, "examples:toHex")
41 | // NAMESPACE>
42 | // NAMESPACE> for i=1:1:numbers.Count() { do numbers.SetAt($zhex(numbers.GetAt(i)), i) }
43 | // NAMESPACE>
44 | // NAMESPACE> write "[" _ $zjoin(numbers, ",") _ "]"
45 | // NAMESPACE> [52,C,1B]
46 | // NAMESPACE>
47 | // NAMESPACE> write $zjoin(hexNumbers, ",")
48 | // NAMESPACE> [52,C,1B]
49 | //
50 | // See also:
51 | // DeclarativeCOS.Binder#Map
52 | // DeclarativeCOS.Examples#toHex
53 | // DeclarativeCOS.Joiner#join ($zjoin)
54 | //
55 | ZMAP(collection, function) public {
56 | Quit $zbind(collection, function).Map()
57 | }
58 | .
59 | //
60 | // "$zfind" function.
61 | //
62 | // Returns the first found element from the specified collection by the certain criteria (function).
63 | // Otherwise, returns null string.
64 | //
65 | // Example:
66 | // NAMESPACE> set numbers = ##class(%ListOfDataTypes).%New()
67 | // NAMESPACE> do numbers.Insert($random(100))
68 | // NAMESPACE> do numbers.Insert($random(100))
69 | // NAMESPACE> do numbers.Insert($random(100))
70 | // NAMESPACE>
71 | // NAMESPACE> set primeNumber = $zfind(numbers, "examples:isPrime")
72 | // NAMESPACE>
73 | // NAMESPACE> write "[" _ $zjoin(numbers, ",") _ "]"
74 | // NAMESPACE> [69,41,68]
75 | // NAMESPACE>
76 | // NAMESPACE> write "Prime number: " _ $select(primeNumber="":"", 1:primeNumber)
77 | // NAMESPACE> Prime number: 41
78 | //
79 | // See also:
80 | // DeclarativeCOS.Binder#Find
81 | // DeclarativeCOS.Examples#isPrime
82 | // DeclarativeCOS.Joiner#join ($zjoin)
83 | //
84 | ZFIND(collection, function) public {
85 | Quit $zbind(collection, function).Find()
86 | }
87 | .
88 | //
89 | // "$zfilter" function.
90 | //
91 | // Returns new collection which contains filtered elements by the certain criteria (function) of the specified collection.
92 | //
93 | // Example:
94 | // NAMESPACE> set numbers = ##class(%ListOfDataTypes).%New()
95 | // NAMESPACE> do numbers.Insert($random(100))
96 | // NAMESPACE> do numbers.Insert($random(100))
97 | // NAMESPACE> do numbers.Insert($random(100))
98 | // NAMESPACE>
99 | // NAMESPACE> set filteredNumbers = $zfilter(numbers, "examples:isOdd")
100 | // NAMESPACE>
101 | // NAMESPACE> write "[" _ $zjoin(numbers, ",") _ "]"
102 | // NAMESPACE> [22,71,31]
103 | // NAMESPACE>
104 | // NAMESPACE> write "[" _ $zjoin(filteredNumbers, ",") _ "]"
105 | // NAMESPACE> [71,31]
106 | //
107 | // See also:
108 | // DeclarativeCOS.Binder#Filter
109 | // DeclarativeCOS.Examples#isOdd
110 | // DeclarativeCOS.Joiner#join ($zjoin)
111 | //
112 | ZFILTER(collection, function) public {
113 | Quit $zbind(collection, function).Filter()
114 | }
115 | .
116 | //
117 | // "$zexists" function.
118 | //
119 | // Returns $$$YES if collection contains element which is satisfied by by the certain criteria (function).
120 | // Otherwise, returns $$$NO.
121 | //
122 | // Example:
123 | // NAMESPACE> set numbers = ##class(%ListOfDataTypes).%New()
124 | // NAMESPACE> do numbers.Insert($random(100))
125 | // NAMESPACE> do numbers.Insert($random(100))
126 | // NAMESPACE> do numbers.Insert($random(100))
127 | // NAMESPACE>
128 | // NAMESPACE> set hasEvenNumbers = $zexists(numbers, "examples:isEven")
129 | // NAMESPACE>
130 | // NAMESPACE> write "[" _ $zjoin(numbers, ",") _ "]"
131 | // NAMESPACE> [51,56,53]
132 | // NAMESPACE>
133 | // NAMESPACE> write "Collection has" _ $case(hasEvenNumbers, 1:" ", 0:" no ") _ "even numbers"
134 | // NAMESPACE> Collection has even numbers
135 | //
136 | // See also:
137 | // DeclarativeCOS.Binder#Exists
138 | // DeclarativeCOS.Examples#isEven
139 | // DeclarativeCOS.Joiner#join ($zjoin)
140 | //
141 | ZEXISTS(collection, function) public {
142 | Quit $zbind(collection, function).Exists()
143 | }
144 | .
145 | //
146 | // "$zcount" function.
147 | //
148 | // Returns $$$YES if collection contains element which is satisfied by the certain criteria (function).
149 | // Otherwise, returns $$$NO.
150 | //
151 | // Example:
152 | // NAMESPACE> set numbers = ##class(%ListOfDataTypes).%New()
153 | // NAMESPACE> do numbers.Insert($random(1000))
154 | // NAMESPACE> do numbers.Insert($random(1000))
155 | // NAMESPACE> do numbers.Insert($random(1000))
156 | // NAMESPACE>
157 | // NAMESPACE> set palindromicNumbersCount = $zcount(numbers, "examples:isPalindromic")
158 | // NAMESPACE>
159 | // NAMESPACE> write "[" _ $zjoin(numbers, ",") _ "]"
160 | // NAMESPACE> [715,202,898]
161 | // NAMESPACE>
162 | // NAMESPACE> write "Count of palindromic numbers: " _ palindromicNumbersCount
163 | // NAMESPACE> Count of palindromic numbers: 2
164 | //
165 | // See also:
166 | // DeclarativeCOS.Binder#Count
167 | // DeclarativeCOS.Examples#isPalindromic
168 | // DeclarativeCOS.Joiner#join ($zjoin)
169 | //
170 | ZCOUNT(collection, function) public {
171 | Quit $zbind(collection, function).Count()
172 | }
173 | .
174 | //
175 | // "$zjoin" function.
176 | //
177 | // Returns string from elements of the specified collection usin the certain separator.
178 | //
179 | // Example:
180 | // NAMESPACE> set words = ##class(%ListOfDataTypes).%New()
181 | // NAMESPACE> do words.Insert("DeclarativeCOS")
182 | // NAMESPACE> do words.Insert("is")
183 | // NAMESPACE> do words.Insert("awesome!")
184 | // NAMESPACE>
185 | // NAMESPACE> write $jzoin(words, " ")
186 | // NAMESPACE> DeclarativeCOS is awesome!
187 | //
188 | // See also:
189 | // DeclarativeCOS.Joiner#join
190 | //
191 | ZJOIN(collection, separator = "") public {
192 | Quit ##class(DeclarativeCOS.Joiner).join(collection, separator)
193 | }
194 |
--------------------------------------------------------------------------------
/src/cls/DeclarativeCOS/Binder.cls:
--------------------------------------------------------------------------------
1 | /// Binder collection with function.
2 | /// Also, class provides implementation of all DeclarativeCOS commands and functions.
3 | Class DeclarativeCOS.Binder Extends %RegisteredObject
4 | {
5 |
6 | /// Source collection for processing in DeclarativeCOS commands and functions.
7 | Property collection As %Collection.AbstractList [ Private ];
8 |
9 | /// Source function for processing in DeclarativeCOS commands and functions.
10 | Property function As %String [ Private ];
11 |
12 | /// Overrides "constructor" for the class.
13 | Method %OnNew(collection As %Collection.AbstractList, function As %String) As %Status [ Private, ServerOnly = 1 ]
14 | {
15 | if ('##class(DeclarativeCOS.Utils).isValidName(function)) {
16 | set exception = ##class(%Exception.General).%New("Declarative name is invalid", "1",,"Declarative name pattern must be ""namespace:function"".")
17 |
18 | throw exception
19 | }
20 |
21 | set ..collection = collection
22 |
23 | set ..function = ##class(DeclarativeCOS.Utils).normalizeName(function)
24 |
25 | return $$$OK
26 | }
27 |
28 | /// Returns source collection of the binder.
29 | Method GetCollection()
30 | {
31 | return ..collection
32 | }
33 |
34 | /// Returns source function of the binder.
35 | Method GetFunction()
36 | {
37 | return ..function
38 | }
39 |
40 | ///
41 | /// Implementation of "zforeach" command.
42 | ///
43 | /// Applies the certain function to each element of the collection.
44 | ///
45 | /// Example:
46 | /// NAMESPACE> set collection = ##class(%ListOfDataTypes).%New()
47 | /// NAMESPACE> do collection.Insert("Hello ")
48 | /// NAMESPACE> do collection.Insert("World!")
49 | /// NAMESPACE>
50 | /// NAMESPACE> zforeach $zbind(collection, "io:print")
51 | ///
52 | /// See also:
53 | /// DeclarativeCOS.Binder
54 | /// DeclarativeCOS.IO#print
55 | ///
56 | Method ForEach()
57 | {
58 | quit:..collection=""
59 |
60 | set index = ""
61 |
62 | for {
63 | set index = ..collection.Next(index)
64 |
65 | quit:index=""
66 |
67 | set item = ..collection.GetAt(index)
68 |
69 | set $lb(className, methodName) = ..loadDeclarative(..function)
70 |
71 | do $classmethod(className, methodName, item)
72 | }
73 | }
74 |
75 | ///
76 | /// Implementation of "$zmap" function.
77 | ///
78 | /// Returns new collection where each item is result of apply the certain function to source item of the specified collection.
79 | ///
80 | /// Example:
81 | /// NAMESPACE> set numbers = ##class(%ListOfDataTypes).%New()
82 | /// NAMESPACE> do numbers.Insert($random(100))
83 | /// NAMESPACE> do numbers.Insert($random(100))
84 | /// NAMESPACE> do numbers.Insert($random(100))
85 | /// NAMESPACE>
86 | /// NAMESPACE> write "[" _ $zjoin(numbers, ",") _ "]"
87 | /// NAMESPACE> [82,12,27]
88 | /// NAMESPACE>
89 | /// NAMESPACE> set hexNumbers = $zmap(numbers, "examples:toHex")
90 | /// NAMESPACE>
91 | /// NAMESPACE> for i=1:1:numbers.Count() { do numbers.SetAt($zhex(numbers.GetAt(i)), i) }
92 | /// NAMESPACE>
93 | /// NAMESPACE> write "[" _ $zjoin(numbers, ",") _ "]"
94 | /// NAMESPACE> [52,C,1B]
95 | /// NAMESPACE>
96 | /// NAMESPACE> write $zjoin(hexNumbers, ",")
97 | /// NAMESPACE> [52,C,1B]
98 | ///
99 | /// See also:
100 | /// DeclarativeCOS.Examples#toHex
101 | /// DeclarativeCOS.Joiner#join ($zjoin)
102 | ///
103 | Method Map()
104 | {
105 | set collection = $classmethod(..collection.%ClassName(), "%New")
106 |
107 | set index = ""
108 |
109 | for {
110 | set index = ..collection.Next(index)
111 |
112 | quit:index=""
113 |
114 | set item = ..collection.GetAt(index)
115 |
116 | set $lb(className, methodName) = ..loadDeclarative(..function)
117 |
118 | set mappedItem = $classmethod(className, methodName, item)
119 |
120 | do collection.Insert(mappedItem)
121 | }
122 |
123 | return collection
124 | }
125 |
126 | ///
127 | /// Implementation of "$zfind" function.
128 | ///
129 | /// Returns the first found element from the specified collection by the certain criteria (function).
130 | /// Otherwise, returns null string.
131 | ///
132 | /// Example:
133 | /// NAMESPACE> set numbers = ##class(%ListOfDataTypes).%New()
134 | /// NAMESPACE> do numbers.Insert($random(100))
135 | /// NAMESPACE> do numbers.Insert($random(100))
136 | /// NAMESPACE> do numbers.Insert($random(100))
137 | /// NAMESPACE>
138 | /// NAMESPACE> set primeNumber = $zfind(numbers, "examples:isPrime")
139 | /// NAMESPACE>
140 | /// NAMESPACE> write "[" _ $zjoin(numbers, ",") _ "]"
141 | /// NAMESPACE> [69,41,68]
142 | /// NAMESPACE>
143 | /// NAMESPACE> write "Prime number: " _ $select(primeNumber="":"", 1:primeNumber)
144 | /// NAMESPACE> Prime number: 41
145 | ///
146 | /// See also:
147 | /// DeclarativeCOS.Examples#isPrime
148 | /// DeclarativeCOS.Joiner#join ($zjoin)
149 | ///
150 | Method Find()
151 | {
152 | set index = ""
153 |
154 | for {
155 | set index = ..collection.Next(index)
156 |
157 | quit:index=""
158 |
159 | set item = ..collection.GetAt(index)
160 |
161 | set $lb(className, methodName) = ..loadDeclarative(..function)
162 |
163 | if ($classmethod(className, methodName, item)) {
164 | return item
165 | }
166 | }
167 |
168 | return ""
169 | }
170 |
171 | ///
172 | /// Implementation of "$zfilter" function.
173 | ///
174 | /// Returns new collection which contains filtered elements by the certain criteria (function) of the specified collection.
175 | ///
176 | /// Example:
177 | /// NAMESPACE> set numbers = ##class(%ListOfDataTypes).%New()
178 | /// NAMESPACE> do numbers.Insert($random(100))
179 | /// NAMESPACE> do numbers.Insert($random(100))
180 | /// NAMESPACE> do numbers.Insert($random(100))
181 | /// NAMESPACE>
182 | /// NAMESPACE> set filteredNumbers = $zfilter(numbers, "examples:isOdd")
183 | /// NAMESPACE>
184 | /// NAMESPACE> write "[" _ $zjoin(numbers, ",") _ "]"
185 | /// NAMESPACE> [22,71,31]
186 | /// NAMESPACE>
187 | /// NAMESPACE> write "[" _ $zjoin(filteredNumbers, ",") _ "]"
188 | /// NAMESPACE> [71,31]
189 | ///
190 | /// See also:
191 | /// DeclarativeCOS.Examples#isOdd
192 | /// DeclarativeCOS.Joiner#join ($zjoin)
193 | ///
194 | Method Filter()
195 | {
196 | set collection = $classmethod(..collection.%ClassName(), "%New")
197 |
198 | set index = ""
199 |
200 | for {
201 | set index = ..collection.Next(index)
202 |
203 | quit:index=""
204 |
205 | set item = ..collection.GetAt(index)
206 |
207 | set $lb(className, methodName) = ..loadDeclarative(..function)
208 |
209 | if ($classmethod(className, methodName, item)) {
210 | do collection.Insert(item)
211 | }
212 | }
213 |
214 | return collection
215 | }
216 |
217 | ///
218 | /// Implementation of "$zexists" function.
219 | ///
220 | /// Returns $$$YES if collection contains element which is satisfied by by the certain criteria (function).
221 | /// Otherwise, returns $$$NO.
222 | ///
223 | /// Example:
224 | /// NAMESPACE> set numbers = ##class(%ListOfDataTypes).%New()
225 | /// NAMESPACE> do numbers.Insert($random(100))
226 | /// NAMESPACE> do numbers.Insert($random(100))
227 | /// NAMESPACE> do numbers.Insert($random(100))
228 | /// NAMESPACE>
229 | /// NAMESPACE> set hasEvenNumbers = $zexists(numbers, "examples:isEven")
230 | /// NAMESPACE>
231 | /// NAMESPACE> write "[" _ $zjoin(numbers, ",") _ "]"
232 | /// NAMESPACE> [51,56,53]
233 | /// NAMESPACE>
234 | /// NAMESPACE> write "Collection has" _ $case(hasEvenNumbers, 1:" ", 0:" no ") _ "even numbers"
235 | /// NAMESPACE> Collection has even numbers
236 | ///
237 | /// See also:
238 | /// DeclarativeCOS.Examples#isEven
239 | /// DeclarativeCOS.Joiner#join ($zjoin)
240 | ///
241 | Method Exists()
242 | {
243 | return ..Find() '= ""
244 | }
245 |
246 | ///
247 | /// Implementation of "$zcount" function.
248 | ///
249 | /// Returns $$$YES if collection contains element which is satisfied by the certain criteria (function).
250 | /// Otherwise, returns $$$NO.
251 | ///
252 | /// Example:
253 | /// NAMESPACE> set numbers = ##class(%ListOfDataTypes).%New()
254 | /// NAMESPACE> do numbers.Insert($random(1000))
255 | /// NAMESPACE> do numbers.Insert($random(1000))
256 | /// NAMESPACE> do numbers.Insert($random(1000))
257 | /// NAMESPACE>
258 | /// NAMESPACE> set palindromicNumbersCount = $zcount(numbers, "examples:isPalindromic")
259 | /// NAMESPACE>
260 | /// NAMESPACE> write "[" _ $zjoin(numbers, ",") _ "]"
261 | /// NAMESPACE> [715,202,898]
262 | /// NAMESPACE>
263 | /// NAMESPACE> write "Count of palindromic numbers: " _ palindromicNumbersCount
264 | /// NAMESPACE> Count of palindromic numbers: 2
265 | ///
266 | /// See also:
267 | /// DeclarativeCOS.Examples#isPalindromic
268 | /// DeclarativeCOS.Joiner#join ($zjoin)
269 | ///
270 | Method Count()
271 | {
272 | set count = 0
273 |
274 | set index = ""
275 |
276 | for {
277 | set index = ..collection.Next(index)
278 |
279 | quit:index=""
280 |
281 | set item = ..collection.GetAt(index)
282 |
283 | set $lb(className, methodName) = ..loadDeclarative(..function)
284 |
285 | if ($classmethod(className, methodName, item)) {
286 | set count = count + 1
287 | }
288 | }
289 |
290 | return count
291 | }
292 |
293 | /// Delegates call to DeclarativesManager#loadDeclarative
294 | ///
295 | /// See also:
296 | /// DeclarativeCOS.DeclarativesManager#loadDeclarative
297 | ///
298 | ClassMethod loadDeclarative(function As %String) [ Private ]
299 | {
300 | return ##class(DeclarativeCOS.DeclarativesManager).loadDeclarative(function)
301 | }
302 |
303 | }
304 |
305 |
--------------------------------------------------------------------------------