Four short lines of Objectscript code


ClassMethod Ping(host)
{
	set cmd="ping "_host
	open cmd:"QR":10
	for {use cmd read ans quit:$zeof  use 0 write ans,!}
	close cmd
}

// some test
do ##class(your.class).Ping("google.com")

Pinging google.com [142.250.185.110] with 32 bytes of data:
Reply from 142.250.185.110: bytes=32 time=25ms TTL=114
Reply from 142.250.185.110: bytes=32 time=26ms TTL=114
Reply from 142.250.185.110: bytes=32 time=19ms TTL=114
Reply from 142.250.185.110: bytes=32 time=19ms TTL=114

Ping statistics for 142.250.185.110:
    Packets: Sent = 4, Received = 4, Lost = 0 (0% loss),
Approximate round trip times in milli-seconds:
    Minimum = 19ms, Maximum = 26ms, Average = 22ms

As others already wrote,

write $order(^$GLOBAL(""))

gives you the first global name accessible from a given namespace. Usually, this will be a percent-global (^%...) but if you want to get the first (or all) global, which resides in a given database, the do the same as above but with extended global access

set dir = "^^c:\databases\mydb\"  // "^^" and "the path to your CACHE/IRIS.dat file"
write $order(^$|dir|GLOBAL(""))

There are several possibilities, using WinSCP  from Windows, Linux and Samba, etc. But if "using Cache codes" (Objectscript) is a  requirement, then the simplest way is: open a TCP-(server)port on the one end and a TCP-(client)port on the other end, write and read the data, close the connections. Voila. The job is done. I do not see any problem there. OK, maybe you need to open those ports. And do not forget, USB-Sticks exists too ;-))

I'm not aware of any $ISJSON() or similar named function but you can easily make your own

ClassMethod IsJSON(str)
{
	try { ret:{}.%FromJSON(str) 1 } catch e { ret:e.Code=3 0 throw e }
}

set a="{name:""John Doe"" "
set b="{""name"":""John Doe"" }"

write ##class(some.class).IsJSON(a) --> 0
write ##class(some.class).IsJSON(b) --> 1
write ##class(some.class).IsJSON()  --> <UNDEFINED>zIsJSON+1^...  *str

As an addition to the above possibilities, you can  ALWAYS use (assumed, you have the rights to access the database where the global lives - this is true for both of the above too) extended global access.

Just one remark, this kind of access is possible but not the recommended way for creating regular classes (databases) rather to occasionally (on demand) access data from other namespace and/or namespaces.

set nsp = "USER"
set myvar = ^|nsp|MyGlobal(1,2,3)

If there is no namespace associated with the database (where the global lives) just use the implicit namespace

set dir = "^^C:\mydatabases\myfolder\"    // win-world, "^^pathToTheDatabase"
set dir = "^^/opt/mydatabases/myfolder/"  // unix-world, 
write ^|dir|myglobal(1,2,3)

// and, of course all other commands and functions
kill ^|dir|myglobal(1)
write $order(^|dir|myglobal(1,2))
set isDef = $data(^|dir|myglobal)

Indirection is your friend, which of course, works for globals, locals and other things too.

set ^myglobal="This is the root node"
set ^myglobal(12)="A node on level 1"
set ^myglobal(17)="More level 1 node"
set ^myglobal(17,1)="Data on the second level"
set ^myglobal(19,3)="More data on the second level"

; now start to play indirection
set someVariable="^myglobal" // the better way were: set someVariable=$name(^myglobal)

; and get the content of the above global
write @someVariable // --> This is the root node
write @someVariable@(12) // --> A node on level 1
write @someVariable@(17,1) // --> Data on the second level

; the same as above
set myVariable="^myglobal(17)" // Better: set myVariable=$name(^myglobal(17))
write @myVariable // --> More level 1 node
write @myVariable@(1) // Data on second level

; a bit overcomplicated
set string1="^"
set string2="myglobal"

write @(string1_string2_"("_(15+4_","_(1+2))_")") // --> More data on second level

So just (re)read the docu about indirection...

The error message <METHOD NOT SUPPORTED> says everything.

USER>s obj={"name":"john", "value":65}

USER>w obj.%ToJSON() // --> {"name":"john","value":65}

USER>s obj={"name":"john", "value":65, "dynObj":{"info":"something"} }

USER>w obj.%ToJSON() // --> {"name":"john","value":65,"dynObj":{"info":"something"}}

USER>s obj={"name":"john", "value":65, "dynObj":{"info":"something"}, "cosObj":(##class(%Net.HttpRequest).%New()) }

USER>w obj.%ToJSON() // --> <METHOD NOT SUPPORTED> *%ToJSON,%Net.HttpRequest

So the problem is, you try to "stringify" (JS-speech) a dynamic object, where one of the properties contains a non-dynamic object (%Net.HttpRequest in the above example).

Class DC.Samples Extends %RegisteredObject
{

/// partition an array into two subarrays
/// return [[even], [odd]]
ClassMethod Task1a(x As %DynamicArray) As %DynamicArray
{
	set t(0)=[],t(1)=[]
	for i=0:1:x.%Size()-1 do t(x.%Get(i)#2).%Push(x.%Get(i))
	quit [(t(0)),(t(1))]
}

/// partition an array into two subarrays
/// return [[even], [odd]]
ClassMethod Task1b(x As %DynamicArray) As %DynamicArray
{
	set t(0)=[], t(1)=[], i=x.%GetIterator()
	while i.%GetNext(,.v) {  do t(v#2).%Push(v) }
	quit [(t(0)),(t(1))]
}

/// hamming distance of two strings
ClassMethod Task2(x As %String, y As %String) As %Integer
{
	if $l(x)-$l(y) quit "<Error>"	// strings have to be the same length
	set r=0
	for i=1:1:$l(x) set r=$e(x,i)'=$e(y,i)+r
	quit r
}

/// encrypt an string
ClassMethod Task3(x As %String) As %String
{
	quit $tr($re(x),"aeiou","01223")_"aca"
}

/// check a string for identical chars
ClassMethod Task4(x As %String) As %Boolean
{
	quit $tr(x,$e(x))=""
}

/// double chars
ClassMethod Task5(x As %String) As %String
{
	f i=$l(x):-1:1 s $e(x,i)=$e(x,i)_$e(x,i)
	q x
}

}

For a handful of methods the manual method is likely the fastest... in case, you have a real big bunch of methods to copy put this "short" method into a class and let it run...

/// Transfer all or selected methods from a class into
/// individual classes
/// cls : the donor class
/// list: list of methods to be transfered: "method1,method2,..."
///       or empty to transfer all methods
ClassMethod Transfer(cls, list = "")
{
    s old=##class(%Dictionary.ClassDefinition).%OpenId(cls)
    s:list]"" list=$lfs(list)
    
    i old {
        f i=old.Methods.Count():-1:1 {
            s met=old.Methods.GetAt(i)				// grab the next method
            i list]"",'$lf(list,met.Name) continue	// skip if not to copy
            
            s new=old.%ConstructClone()				// duplicate old class
            s tmp=old.Name							// grab the old classname
            s $p(tmp,".",*)="Parts."_met.Name		// create a new classname
            s new.Name=tmp
            s new.Abstract=1						// make the class abstract
            s new.Super=""							// remove all superclasses
            
            s dup=met.%ConstructClone()				// duplicate the old method
            s dup.Name=met.Name						// but keep the old name
            d new.Properties.Clear()					// remove all properties
            d new.Parameters.Clear()				// remove all parameters			
            d new.Methods.Clear()					// remove all methods
            d new.Methods.Insert(dup)				// insert the copied method only
            d old.Methods.RemoveAt(i)				// Remove this method from old class
            i old.Super="" { s d="" } else { s d="," }
            s old.Super=old.Super_d_new.Name		// add the new class to extends-list
            s st=new.%Save()						// save the new class
            
            w new.Name,"-->",$s(st:"OK",1:$system.Status.GetOneErrorText(st)),!
            // Possibly compile the class: do $system.OBJ.Compile(...)
            
        }
        s st=old.%Save()							// save the old class
        w old.Name,"-->",$s(st:"OK",1:$system.Status.GetOneErrorText(st)),!
        // Possibly compile...
    }

If you want to reorder JSON properties (alphabetically or just put some of them at the beginning) then use a utility method, like this, especially if you have several object(types) to reorder

Class DC.Utility Extends %RegisteredObject
{
/// Reorder a JSON Object or Array
/// 
/// obj:  JSON-Object
/// 	  ord: prop1, prop2, ...	Desired order for (some) properties
/// 	       (Properties not listed are copied in the order in which they were created)
/// 	       If ord not present, properties will be reordered in aplphabetical order
/// 	       
/// obj: JSON-Array
/// 	 ord: pos1, pos2, ...	Desired order for (some) array items
/// 	      (Items not listed are copied in ascending order)
/// 	      
ClassMethod ReOrder(obj As %DynamicAbstractObject, ord... As %String)
{
	i obj.%Extends("%DynamicObject") {
		s new={}, itr=obj.%GetIterator()
		i '$g(ord) {
			while itr.%GetNext(.k) { s done(k)=0 }
			s k="" f  s k=$o(done(k)) q:k=""  d new.%Set(k,obj.%Get(k))
		} else {
			f i=1:1:$g(ord) { s k=ord(i),done(k)=1 d:$e(obj.%GetTypeOf(k),1,2)'="un" new.%Set(k,obj.%Get(k)) }
			while itr.%GetNext(.k,.v) { d:'$d(done(k)) new.%Set(k,v) }
		}
		
	} elseif obj.%Extends("%DynamicArray") {
		s new=[], itr=obj.%GetIterator(), max=obj.%Size(), done=""
		f i=1:1:$g(ord) { s k=ord(i) i k,k<=max d new.%Push(obj.%Get(k-1)) s $bit(done,k)=1 }
		while itr.%GetNext(.k,.v) { d:'$bit(done,k+1) new.%Push(v) }
		
	} else { s new=obj }
	
	q new
}
}

Some examples

s car={"color":"red", "fuel":"diesel", "maxspeed":150, "maker":"Audi", "model":"Quattro Q5", "power":300, "available":true, "rating":8, "allWheel":true }
s car1=##class(DC.Utility).ReOrder(car) // order all props alphabetically
s car2=##class(DC.Utility).ReOrder(car,"maker","model","available") // start with maker, model, etc.

w car.%ToJSON(),!,car1.%ToJSON(),!,car2.%ToJSON() --->
{"color":"red","fuel":"diesel","maxspeed":150,"maker":"Audi","model":"Quattro Q5","power":300,"available":true,"rating":8,"allWheel":true}
{"allWheel":"1","available":"1","color":"red","fuel":"diesel","maker":"Audi","maxspeed":150,"model":"Quattro Q5","power":300,"rating":8}
{"maker":"Audi","model":"Quattro Q5","available":"1","color":"red","fuel":"diesel","maxspeed":150,"power":300,"rating":8,"allWheel":"1"}