summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Sluift/Examples/EchoBot_With.lua32
-rw-r--r--Sluift/core.lua110
-rw-r--r--Sluift/main.cpp10
-rw-r--r--Sluift/sluift.cpp4
4 files changed, 151 insertions, 5 deletions
diff --git a/Sluift/Examples/EchoBot_With.lua b/Sluift/Examples/EchoBot_With.lua
new file mode 100644
index 0000000..1f7d0bb
--- /dev/null
+++ b/Sluift/Examples/EchoBot_With.lua
@@ -0,0 +1,32 @@
+--[[
+ Copyright (c) 2010-2013 Remko Tronçon
+ Licensed under the GNU General Public License v3.
+ See Documentation/Licenses/GPLv3.txt for more information.
+--]]
+
+--[[
+
+ Alternative version of EchoBot that uses with()
+
+ This script logs into an XMPP server, sends initial presence,
+ and then waits for incoming messages, and echoes them back.
+
+ The following environment variables are used:
+ * SLUIFT_JID, SWIFT_PASS: JID and password to log in with
+ * SLUIFT_DEBUG: Sets whether debugging should be turned on
+
+--]]
+
+require "sluift"
+
+sluift.debug = os.getenv("SLUIFT_DEBUG") or false
+
+client = sluift.new_client(os.getenv("SLUIFT_JID"), os.getenv("SLUIFT_PASS"))
+sluift.with(client, function ()
+ connect()
+ set_version{name = "EchoBot", version = "0.1"}
+ send_presence("Send me a message")
+ for message in messages() do
+ send_message{to = message["from"], body = message["body"]}
+ end
+end)
diff --git a/Sluift/core.lua b/Sluift/core.lua
index aeb3286..f387354 100644
--- a/Sluift/core.lua
+++ b/Sluift/core.lua
@@ -97,10 +97,31 @@ local function copy(object)
end
end
+local function clear(table)
+ setmetatable(table, nil)
+ for key, value in pairs(table) do
+ rawset(table, key, nil)
+ end
+end
+
local function trim(string)
return string:gsub("^%s*(.-)%s*$", "%1")
end
+local function keys(table)
+ local result = {}
+ for key in pairs(table) do
+ result[#result+1] = key
+ end
+ return result
+end
+
+local function insert_all(table, values)
+ for _, value in pairs(values) do
+ table[#table+1] = value
+ end
+end
+
--------------------------------------------------------------------------------
-- Help
--------------------------------------------------------------------------------
@@ -405,7 +426,9 @@ end
_H = {
[[ Client interface ]]
}
-local Client = {}
+local Client = {
+ _with_prompt = function(client) return client:jid() end
+}
Client.__index = Client
register_class_table_help(Client, "Client")
@@ -424,6 +447,90 @@ local PubSubNode = {}
PubSubNode.__index = PubSubNode
register_class_table_help(PubSubNode, "PubSubNode")
+
+--------------------------------------------------------------------------------
+-- with
+--------------------------------------------------------------------------------
+
+local original_G
+
+local function with (target, f)
+ -- Dynamic scope
+ if f then
+ with(target)
+ return call{f, finally = function() with() end}
+ end
+
+ -- No scope
+ if target then
+ if not original_G then
+ original_G = copy(_G)
+ setmetatable(original_G, getmetatable(_G))
+ clear(_G)
+ end
+
+ setmetatable(_G, {
+ __index = function(_, key)
+ local value = target[key]
+ if value then
+ if type(value) == 'function' then
+ -- Add 'self' argument to all functions
+ return function(...) return value(target, ...) end
+ else
+ return value
+ end
+ else
+ return original_G[key]
+ end
+ end,
+ __newindex = original_G,
+ _completions = function ()
+ local result = {}
+ if type(target) == "table" then
+ insert_all(result, keys(target))
+ end
+ local mt = getmetatable(target)
+ if mt and type(mt.__index) == 'table' then
+ insert_all(result, keys(mt.__index))
+ end
+ insert_all(result, keys(original_G))
+ return result
+ end
+ })
+
+ -- Set prompt
+ local prompt = nil
+
+ -- Try '_with_prompt' in metatable
+ local target_metatable = getmetatable(target)
+ if target_metatable then
+ if type(target_metatable._with_prompt) == "function" then
+ prompt = target_metatable._with_prompt(target)
+ else
+ prompt = target_metatable._with_prompt
+ end
+ end
+
+ if not prompt then
+ -- Use tostring()
+ local target_string = tostring(target)
+ if string.len(target_string) > 25 then
+ prompt = string.sub(target_string, 0, 22) .. "..."
+ else
+ prompt = target_string
+ end
+ end
+ rawset(_G, "_PROMPT", prompt .. '> ')
+ else
+ -- Reset _G
+ clear(_G)
+ for key, value in pairs(original_G) do
+ _G[key] = value
+ end
+ setmetatable(_G, original_G)
+ end
+end
+
--------------------------------------------------------------------------------
-- Client
--------------------------------------------------------------------------------
@@ -884,4 +991,5 @@ return {
help = help,
extra_help = extra_help,
copy = copy,
+ with = with
}
diff --git a/Sluift/main.cpp b/Sluift/main.cpp
index e2fa9c8..76ba572 100644
--- a/Sluift/main.cpp
+++ b/Sluift/main.cpp
@@ -14,6 +14,7 @@
#include <boost/program_options.hpp>
#include <boost/version.hpp>
#include <boost/numeric/conversion/cast.hpp>
+#include <boost/assign/list_of.hpp>
#include <Sluift/Console.h>
#include <Sluift/StandardTerminal.h>
#include <Sluift/sluift.h>
@@ -151,8 +152,13 @@ int main(int argc, char* argv[]) {
if (arguments.count("interactive") || arguments.count("script") == 0) {
// Import some useful functions into the global namespace
lua_getglobal(L, "sluift");
- lua_getfield(L, -1, "help");
- lua_setglobal(L, "help");
+ std::vector<std::string> globalImports = boost::assign::list_of
+ ("help")("with");
+ foreach (const std::string& globalImport, globalImports) {
+ lua_getfield(L, -1, globalImport.c_str());
+ lua_setglobal(L, globalImport.c_str());
+ }
+ lua_pop(L, 1);
std::cout << SLUIFT_WELCOME_STRING << std::endl;
#ifdef HAVE_EDITLINE
diff --git a/Sluift/sluift.cpp b/Sluift/sluift.cpp
index b2bdc29..39b92fc 100644
--- a/Sluift/sluift.cpp
+++ b/Sluift/sluift.cpp
@@ -126,7 +126,7 @@ static int sluift_index(lua_State* L) {
lua_pushnumber(L, Sluift::globals.timeout);
return 1;
}
- throw Lua::Exception("Unknown property");
+ return 0;
}
catch (const std::exception& e) {
return luaL_error(L, e.what());
@@ -339,7 +339,7 @@ SLUIFT_API int luaopen_sluift(lua_State* L) {
// Register convenience functions
lua_rawgeti(L, LUA_REGISTRYINDEX, Sluift::globals.coreLibIndex);
std::vector<std::string> coreLibExports = boost::assign::list_of
- ("tprint")("disco")("help")("get_help")("copy");
+ ("tprint")("disco")("help")("get_help")("copy")("with");
foreach (const std::string& coreLibExport, coreLibExports) {
lua_getfield(L, -1, coreLibExport.c_str());
lua_setfield(L, -3, coreLibExport.c_str());