Replies

Chris, 

Great tutorial.  Was able to get this all working fairly easy against an InterSystems IRIS for Health environment.  Looking forward to the next section.

Ken

Okay, looked at the docs more and my eyes were playing tricks on me.

Looks like you cant call a routine at a tag in another namespace, but can call a routine at the top in another namespace.

The syntax is:

do ^|"namespace"|routine

so:

do ^|"SAMPLES"|YJM

Interesting, I dont see anywhere in the docs where it would indicate that D ["SAMPLES"]YJM^YJM will work

The docs would indicate that you can do this:

DO ^["SAMPLES"]Y2K

However, that throws a SYNTX error too

Yes, that is true, however, that doesnt allow you to execute a class method from namespace A in namespace B.

When you :

do ["b"]tag^routine

Cache actually executes tag^routine in namespace b vs the namespace you are currently in.

Creating a package map for namespace a that maps a particular package from namespace b only makes that class available to namespace a.  When I execute methods within the mapped class those methods are executed in namespace a and not b.

Im pretty sure that class methods cant be called in another namespace without wrapping the method call in a call that actually switches namespaces, calls them method and then switches back.

do ["namespace"]obj.method 

isn't supported where

do ["namespace"]tag+offset^routine

is

I added an export of the ISC.JSONGlobalProcessor class which contains the Export method to the original post

So a customer asked me a question about this and I decided to actually implement a mechanism to encode a global as JSON.  I haven't done the opposite which would be to take the encoded json and turn it back into a global, but the reverse is pretty simple

Here's the way I encode the Global as json  There is a top-level object with two properties, globalName and nodes.  globalName is a string and represents the actual global name, nodes is an array and contains an object for each node of the global which contains data.  To ensure that non-printable characters are handled properly,  I am using HTML Escaping to escape both the data and the subscript values

{

     "globalName":"^ISCSOAP",
     "nodes":[{
               "data":"io",
               "subscripts":[
                             ""Log""
                            ]
              },
              {
               "data":"c:\\temp\\SOAP.log",
               "subscripts":[
                             ""Log"",
                             ""LogFile""
                            ]
              }]
} 

Here is an example of the class method that generates this output

Class ISC.JSONGlobalProcessor [ Not ProcedureBlock ]
{

ClassMethod Export(GlobalRoot As %String, Output JSON As %DynamicObject) As %Status [ ProcedureBlock = 0 ]
{
    if '$d(@GlobalRoot) quit $System.Status.Error(5001, "Nothing to export; "_GlobalRoot_" <undefined>")
    set root=$p(GlobalRoot,")",1,$l(GlobalRoot,")")-1),node=GlobalRoot s:root="" root=GlobalRoot
    set JSON=##class(%DynamicObject).%New()
    set JSON.globalName=$p(GlobalRoot,"(",1)
    set JSON.nodes=##class(%DynamicArray).%New()
    while $e(node,1,$l(root))=root {
        if $d(@node)#10 do ..addNode(node,.JSON)
        set node=$q(@node)
    }
    quit 1
}

ClassMethod addNode(node As %String, ByRef JSON As %DynamicObject) As %Status
{
    set nodeJSON=##class(%DynamicObject).%New()
    set data=@node,nodeJSON.data=##class(%CSP.Page).EscapeHTML(data)
    set subscripts=$p(node,"(",2,999),subscripts=$p(subscripts,")",1,$l(subscripts,")")-1)
    if ""'=subscripts {
        set nodeJSON.subscripts=##class(%DynamicArray).%New()
        set cp=1
        for {
            q:cp>$l(subscripts,",")
            set subscript=$p(subscripts,",",cp)
            f  {
                q:$l(subscript,"""")#2
                set cp=cp+1,subscript=subscript_","_$p(subscripts,",",cp)
            }
            set subArray=$i(subArray),subArray(subArray)=subscript
            set cp=cp+1
        }
        for i=1:1:subArray do nodeJSON.subscripts.%Push(##class(%CSP.Page).EscapeHTML(subArray(i)))
    }    
    do JSON.nodes.%Push(nodeJSON)
}

}

To call this code you can do the following

set sc=##class(ISC.JSONGlobalProcessor).Export($na(^SAMPLE.PersonD),.json)

Once you have the global encoded in a JSON object, you can output that JSON by:

do json.%ToJSON()

There are extra commands executed in order to call the class method, however the impact is negligible and the ultimate code executed is really identical assuming the method and routine code is the same 

Yes, Not extending %RegisteredObject will produce less code however the code you are executing will be identical.

Another reason to opt for Objects over Routines is that Objects provide an automated documentation mechanism that Routines dont.  All elements of a class are documented in the class documentation and the developer can add their own text documentation as well