savage
Joined: 02 Jul 2004 Posts: 206
|
Posted: Thu Jul 03, 2008 4:12 am Post subject: embedded ruby for ahk |
|
|
I've wanted to be able to embed a ruby interpreter in AHK for ages and I finally got it working a bit ago.
| Code: |
;Internal definitions
rb_handle = 0
rb_Eval(code)
{
local ret
ret := DllCall("msvcrt-ruby18\rb_eval_string","str",code,"cdecl uint")
if( ErrorLevel != 0 )
{
Msgbox, Error running: `n %code% `n Possible syntax error?
exit
}
;Msgbox, %code% `n %ret% : %errorlevel%
return ret
}
rb_ToString(val)
{
local v, str
v := val
str := DllCall("msvcrt-ruby18\rb_string_value_cstr","Uint *",v,"cdecl str")
;Msgbox, tostring %str% : %errorlevel%
return str
}
rb_EvalStr(code)
{
return rb_ToString(rb_Eval(code))
}
;Load the library and setup the interpreter
rb_handle := DllCall("LoadLibrary","str","msvcrt-ruby18.dll","Uint")
DllCall("msvcrt-ruby18\ruby_init")
DllCall("msvcrt-ruby18\ruby_init_loadpath","cdecl")
DllCall("msvcrt-ruby18\ruby_script","str","embedded","cdecl")
;Some internal code for a cleaner callin
code =
(
module AHK
@last_error = nil
@env = Object.new
def AHK.run(&block)
@last_error = nil
@env.instance_eval(&block).to_s
rescue Exception => e
@last_error = e
end
def AHK.load(path)
@last_error = nil
Kernel.load(path).to_s
rescue Exception => e
@last_error = e
end
def AHK.require(lib)
@last_error = nil
Kernel.require(lib).to_s
rescue Exception => e
@last_error = e
end
def AHK.error?
(!@last_error.nil?).to_s
end
def AHK.pretty_error
"#{@last_error.class}: #{@last_error.message}\n#{@last_error.backtrace.join("\n")}"
end
end
)
rb_Eval(code)
;Evaluate a string of code, and return the results as a string
RubyEval(code)
{
c := "AHK.run {" . code . "}"
;Msgbox, %c%
ret := rb_EvalStr(c)
if( rb_EvalStr("AHK.error?") == "true" )
{
error := rb_EvalStr("begin; AHK.pretty_error; rescue => e; e.message; end")
MsgBox, %error%
exit
}
return ret
}
;Load a ruby file
RubyLoad(path)
{
ret := rb_EvalStr("AHK.load('" . path . "')")
if( rb_EvalStr("AHK.error?") == "true" )
{
error := rb_EvalStr("begin; AHK.pretty_error; rescue => e; e.message; end")
MsgBox, %error%
exit
}
return ret
}
;Require a ruby library
RubyRequire(lib)
{
ret := rb_EvalStr("AHK.require('" . path . "')")
if( rb_EvalStr("AHK.error?") == "true" )
{
error := rb_EvalStr("begin; AHK.pretty_error; rescue => e; e.message; end")
MsgBox, %error%
exit
}
return ret
}
;Finalize the interpreter and drop the library
RubyFinalize()
{
DllCall("msvcrt-ruby18\ruby_finalize")
DllCall("FreeLibrary","UInt",rb_handle)
}
|
Usage is quite simple. Just #include the file and use RubyEval, RubyLoad, and RubyRequire to your hearts content. Just remember to call RubyFinalize() on exit so that the interpreter can be cleaned up. It RubyEval uses instance_eval on a persistent object so you can use instance variables between invocations of RubyEval.
Pointless Example!
| Code: |
RubyEval("@a = '" . A_ScriptDir . "'")
ret := RubyEval("@a.scan(/./).join(""\n""))
Msgbox, %ret%
|
You of course need to have ruby installed and on your PATH. Also, as you can see from that short example, quotes can be a bit of a pain to deal with. I'd recommend writing most code in a seperate file and loading it, then using RubyEval to interact with it. _________________ <enormous animated gif> |
|