diff options
| author | Remko Tronçon <git@el-tramo.be> | 2013-12-27 19:50:41 (GMT) | 
|---|---|---|
| committer | Remko Tronçon <git@el-tramo.be> | 2014-01-03 11:09:07 (GMT) | 
| commit | a260aa27ab2af0c71d29b3e18cfa30569d3bcd7d (patch) | |
| tree | 3629bd64f53e8e2f355725ddd07ee5e8e9815f02 | |
| parent | 9d787c6337d7080cb32af800a96cf64d43373514 (diff) | |
| download | swift-a260aa27ab2af0c71d29b3e18cfa30569d3bcd7d.zip swift-a260aa27ab2af0c71d29b3e18cfa30569d3bcd7d.tar.bz2  | |
Sluift: Add with() function
Change-Id: Ife0a7748c2b354017bec5cfdddb0d096950dd15b
| -rw-r--r-- | Sluift/Examples/EchoBot_With.lua | 32 | ||||
| -rw-r--r-- | Sluift/core.lua | 110 | ||||
| -rw-r--r-- | Sluift/main.cpp | 10 | ||||
| -rw-r--r-- | Sluift/sluift.cpp | 4 | 
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());  | 
 Swift