The Crystal Programming Language Forum

Test environment for crystal functions

Hello,
I found some time to write an interactive test environment for crystal functions.
It has a CLI which can be used to manage vars and start functions and procs stored in a hash table.

>ls functions
functions: run,split_run,list,typeof,print,load,eval,ceval,after,+,-,inc,dec,<,>,if,while,every,ls,let,delete,clear,p,!,now,date,help,debug,singlestep,test,sleep,pass,end,cls,exit

While it is a sort of text interpreter its not that slow:

Example test script:
Welcome to tree

load counter2.txt
Loaded: counter2.txt Number of lines: 11
run
23:43:57.337687
0
1000000
23:44:00.273736
reached end of file

# ~ 5 sec with scripter
now
counter = 0
p counter
while counter < 1000000
 counter+= 1
 #p counter
end 
p counter
now

Best Regards,
Peter

1 Like

I’d checkout https://github.com/crystal-community/icr.

I am using icr about a year now and its really a good tool.
Here i wrote a small description what can be done with my small scripting environment called tree.

Its more about real time testing of already working functions and not about evaluating single crystal commands. I wanted to have an environment a bit like the Python shell where i can set vars and inspect functions at runtime.

ls
builtin vars: {“started” => false, “debug” => false, “filename” => “”, “lines” => 0}
user vars:
vars_int32: {“num” => 1, “size” => 99}
vars_string: {“weather” => “cold”, “day” => “monday”}
functions:
{“run”, #<Proc(String, Int32, Int32):0x56148908bbd0>}
{“list”, #<Proc(String, Int32, Int32):0x56148908ccb0>}
{“print”, #<Proc(String, Int32, Int32):0x561489070540>}
{“load”, #<Proc(String, Int32, Int32):0x5614890705e0>}
{“eval”, #<Proc(String, Int32, Int32):0x5614890716e0>}
{“after”, #<Proc(String, Int32, Int32):0x5614890751a0>}
{"+", #<Proc(String, Int32, Int32):0x561489075900>}
{"<", #<Proc(String, Int32, Int32):0x561489076c60>}
{“while”, #<Proc(String, Int32, Int32):0x561489076d60>}
{“every”, #<Proc(String, Int32, Int32):0x561489077100>}
{“split”, #<Proc(String, Int32, Int32):0x5614890778f0>}
{“ls”, #<Proc(String, Int32, Int32):0x56148908b560>}
{“let”, #<Proc(String, Int32, Int32):0x561489078580>}
{“p”, #<Proc(String, Int32, Int32):0x561489079410>}
{"!", #<Proc(String, Int32, Int32):0x561489079cb0>}
{“now”, #<Proc(String, Int32, Int32):0x56148907e8b0>}
{“help”, #<Proc(String, Int32, Int32):0x56148908b310>}
{“debug”, #<Proc(String, Int32, Int32):0x56148908b810>}
{“test”, #<Proc(String, Int32, Int32):0x56148908ba00>}
{“pass”, #<Proc(String, Int32, Int32):0x56148908bb50>}
{“end”, #<Proc(String, Int32, Int32):0x56148908bb60>}
{“exit”, #<Proc(String, Int32, Int32):0x56148908bbc0>}

The first idea was to use procs to build a fast as possible text interpreter environment and see how it performs.

def procloop
  puts(Time.local.to_s("%H:%M:%S.%6N"))
  10.times {
    procs = {->foo, ->pass, ->bar}
    procs.each do |p|
      p.call
    end
  }
  puts(Time.local.to_s("%H:%M:%S.%6N"))
end

ICR is the best tool i now for inspecting single crystal commands.
tree and some other small scripts can be checked out here:
git clone https://github.com/pebauer68/crystal.git

Ah gotcha. Are you always aware of crystal play command? I think it does something like what you’re wanting.

I guess I’m just curious where something like this would fit in both with icr and/or just having some file and doing crystal test.cr on it?

Crystal play is also a good tool, but i prefer a CLI interface.
From the tree prompt you can always start icr with:

! icr # exit and back to tree with ^D

Adding functions to tree is easy:
example: -add a clear console(aka cls) command
{“cls”, ->(x : String, y : Int32) { print “\33c\e[3J”; return 0 }},

I have added a ceval function which evalutes expressions via
the crystal binary - a bit like icr.

example:
ceval puts 1+2
The result is stored in a user(public) var as string:
{“ceval.result” => “3”}

I have extend my test environment with a sort of
lexer/token function which splits operators from vars e.g. “a+=1” -> “a + = 1”
but keeps quoted string in codelines as they are e.g. print “123±=7”
The quoted check is in quoted.cr, hope it is useful.

useful function:
def inside_quotes?(char,line,pos)
returns true if a char inside line is inside single or double quotes.
I have updated my first post, you can find tree on crstalshards now.

I have added a small demo video

1 Like

I have added interpreted functions to tree. It needed to have a local namespace for each function. For this i am using the hash datatype. Each functions does a name lookup in his namespace before reading/writing to a var.

functions = { } of String => Hash(String,(String|Int32)) 
p! functions

functions["hello"] = {  "line" => 1,
                    "args" => "test",
                 }

functions["goodbye"] =  {  "line" => 27,
                       "args" => "aha",
                    }                    

p! functions         
p! functions["hello"]["line"]
p! functions["hello"]["args"]
p! functions["goodbye"]["line"]
p! functions["goodbye"]["args"]

I added code injection to this test environment.
-this allows to inject a line of code from a file called “line.txt” in the current working dir into a running interpreter script when the inject flag is set to true.
-the file is automatically deleted after running this line

Example - How to use:
start tree with a while loop
code:

inject  #toggle code injection flag to true
counter=0
while true
  sleep 1
  inc counter
end

inject a print statement for counter from the command line:
$echo p counter > file.txt