I have a Lua class like below. I am using json to serialize the object and put it in a key value store. I am able to serialize the object and put it in the key value store successfully but i am not able to call any methods of the object after i retrieve the object from the key value store. I understand the json module skips the methods while encoding and my object does not have methods after decoding.
Is there a way to append methods to the class after i decode the object from json to lua ? some thing similar to function pointers in C language.
local class_name = "user_object";
user_object = {}; --user class
function user_object.new (mobile, password, uid)
local self = {};
self.mobile = mobile;
self.uid = uid; -- generate a uid which is a running number.
self.password = password;
self.messages_sent = 0;
self.put_request_count = 0;
self.get_request_count = 0;
self.last_time_active = "";
self.get_tickets = {};
self.put_tickets = {};
self.group_message_stream = {};
self.group_ownerships = {}; -- group names which he is owner of
self.group_memberships = {}; -- group names which he is member of
self.sent_poke_count = 0;
self.sent_poke_stream = {};
self.recv_poke_count = 0;
self.recv_poke_stream = {};
function self:add_put_ticket(ticketid)
table.insert(self.put_tickets, ticketid);
self:incr_put_count();
self:save();
return;
end
function self:add_get_ticket(ticketid)
table.insert(self.get_tickets, ticketid);
self:incr_get_count();
self:save();
return;
end
Function in Lua are first class objects, you can store a function in any variable. The line
function self:add_put_ticket(ticketid)
is equivalent to
self.add_put_ticket = function (self, ticketid)
From there, it should be obvious what to do: define your desired methods where they are accessible and assign them to the appropriate fields after deserialization
You can do this with metatables.
user = { name = 'ponzao' } -- Just a table with values.
User = {} -- Table containing the functions.
function User:allCapsName() return self.name:upper() end -- A method.
setmetatable(user, {__index = User}) -- For unavailable keys all calls are dispatched to User.
print(user:allCapsName()) --> "PONZAO"
Related
So I want a function to be used once a change in a property is detected. How do I do that
This can be achieved using metamethods __index and __newindex, but with some limitations. You need to use proxy table, i.e. result table will not be the same as observed table, as metamethod __newindex is called only if the table does not contain the key.
If you need to observe nested table properties, you must create recursive proxy table and modify it dinamically.
<script src="https://cdn.jsdelivr.net/npm/fengari-web#0.1.4/dist/fengari-web.js"></script>
<script type="application/lua">
function observable(data, callback)
return setmetatable({}, {
__index = data,
__newindex = function(self, n, v)
local oldv = data[n]
if v ~= oldv then
data[n] = v
callback(n, v, oldv)
end
end
})
end
local my_object = { test1 = 'value1' }
my_object = observable(my_object,
function(key,value,oldvalue)
print('key='..key
..', value='..tostring(value)
..', oldvalue='..tostring(oldvalue))
end)
my_object.test1 = 1
my_object.test2 = 2
my_object.test1 = 'othervalue'
my_object.test2 = nil
</script>
following problem is mine:
i want to have a function that create a new object in lua, but it should be possible to extend it.
function Class(table)
local a = {}
local t = {create = _create, __newindex = function(o,k,v)
if k == "create" then
--getmetatable(o).create = function()
--_create(o)
--v()
--end
-- or just create(v.params)
else
rawset(o,k,v)
end
end,
}
setmetatable(a,t)
t.__index = t
end
function _create(o,...)
return newTable
end
ele = Class:create()
function Class:create( n )
self.name = n
end
ele2 = Class:create("bbbb")
now the ele2 is without a name, but it schould be create a new object with the given string as name.
can i get the parameter of given value(type function) from newindex or can i execute the value?
There are a few things I'm not sure about. As Etan said, what is newTable and why are you trying to set create as a function of Class when Class is a function?
If you're looking for a way to init an instance of a class when it is created, you can do something like this:
function Class()
local class = {}
class.__index = class
return setmetatable(class, {__call = function(...)
local instance = setmetatable({}, class)
if instance.init then
instance:init(select(2, ...))
end
return instance
end})
end
--now an example:
Dog = Class()
function Dog:init(name)
self.name = name
end
function Dog:bark()
print(string.format("%s barked!", self.name))
end
local pedro = Dog("Pedro")
pedro:bark() --> pedro barked!
I am trying to access inputAC and inputB outside my function getVariables and I can't seem to get it working.
Here is the code I am working with but it does currently work.
func getVariables () {
var inputAC = textFieldAC.text.toInt()
var inputB = textFieldB.text.toInt()
}
var ac = inputAC
var b = inputB
Anyone have any ideas?
Thanks
You need to return the values from the function. Here is one way to do it by returning them in a tuple:
func getVariables () -> (Int?, Int?) {
var inputAC = textFieldAC.text.toInt()
var inputB = textFieldB.text.toInt()
return (inputAC, inputB)
}
var (ac, b) = getVariables()
// Since the values are optionals, you can use optional binding to
// safely unwrap the value.
if let acval = ac {
println("ac value is \(acval)")
} else {
println("alas, ac was nil")
}
These variables which are in getVariables method can not be access outside this method, because these are method local variables. Scope for accessing them is only for that method.
If you want to access them declare them as property or instance variables in class....
I would suggest you to instance this variables in class. If swift is not so different to java, you could declare them as class variables and set them in your method. Then, outside your method, you could access them with a
(this is java code, I'm sorry, but I try to give you the general idea)
In the class you should do something like this:
Int ac; int b;
In the method do something like this:
this.setInputAc(inputAc);
this.setInputB(inputAc);
Outside you should do something like this:
ac = this.getInputAc();
b = this.getInputB();
Also, declare your setter and getter for each variable
Just to give you the general idea.
I would like to read a dynamic object from a json file and then use this in a stringTemplate.
The following code works.
dynamic data = new { bcName = "Lixam B.V", periodName = "July 2013" };
var engine = new Template("<m.bcName> <m.periodName>");
engine.Add("m", data);
engine.Render().Should().Be("Lixam B.V July 2013");
The following code fails
var json = "{bcName : 'Lixam B.V', periodName : 'July 2013'}";
dynamic data = JsonConvert.DeserializeObject(json);
string name = (data.bcName);
name.Should().Be("Lixam B.V"); // this passes
var engine = new Template("<m.bcName> <m.periodName>");
engine.Add("m", data);
engine.Render().Should().Be("Lixam B.V July 2013"); //fails
Is there another way to configure JsonConverter to be compatible with StringTemplate
You need to create an IModelAdaptor for whatever the compiled type representing dynamic is, and register it using TemplateGroup.RegisterModelAdaptor.
Inspired on Mr. Harwell's answer, I've implemented an IModelAdaptor that enable the usage of Newtonsoft.Json parsed objects.
Here it goes:
internal class JTokenModelAdaptor : Antlr4.StringTemplate.IModelAdaptor
{
public object GetProperty(
Antlr4.StringTemplate.Interpreter interpreter,
Antlr4.StringTemplate.TemplateFrame frame,
object obj,
object property,
string propertyName)
{
var token = (obj as JToken)?.SelectToken(propertyName);
if (token == null)
return null;
if (token is JValue)
{
var jval = token as JValue;
return jval.Value;
}
return token;
}
}
You just need to register the adaptor in your template group, like this:
template.Group.RegisterModelAdaptor(typeof(JToken), new JTokenModelAdaptor());
Given a function like
function printAndAdd( s: String, a: int, b: int ) {
// ...
}
Is there any way to enumerate the arguments of the function (their names as well as their types) at runtime? Something like
for ( var arg: ArgumentDescriptor in printAndAdd ) {
// arg.type yields the class object of the argument, i.e. 'String' or 'int'.
// arg.name yields the name of the argument, i.e. 's' or 'a'
}
I have a list of event handlers which have different signatures, and I get the name of the event handler to call as well as an Array of objects. I could just apply() the array to the function, but I'd like to do some error checking first to give better error messages.
You can use describeType() to find the information you seek. However for this to work the function must be public. Private methods will not be introspected by describeType().
Assuming printAndAdd is a method of MyClass, you can do this:
var metadata:XML = describeType(MyClass);
//find all the 'parameter' nodes of any method called 'printAndAdd'
var params:XMLList = metadata..method.(#name == "printAndAdd").parameter;
for each (var param:XML in params) {
var index:int = param.#index;
var type:String = param.#type;
var optional:Boolean = param.#optional == "true";
}
One thing you will not be able to find, is the name of the paramater, but I suppose its index may suffice for your goal.
If you need more powerful reflection than this, take a look at the as3commons reflect library.