├── 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 | --------------------------------------------------------------------------------