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!
Related
So recently I'm trying to make a GlobalBan script for my admin module in ROBLOX, but I came across an error when I tried to do GlobalBan.
Below is the error and script:
local defaultDatabase = "Private";
local authenticationToken = "Private"
local HttpService = game:GetService("HttpService");
local DataStoreService = game:GetService("DataStoreService");
local FirebaseService = {};
local UseFirebase = true;
--== Script;
function FirebaseService:SetUseFirebase(value)
UseFirebase = value and true or false;
end
function FirebaseService:GetFirebase(name, database)
database = database or defaultDatabase;
local datastore = DataStoreService:GetDataStore(name);
local databaseName = database..HttpService:UrlEncode(name);
local authentication = ".json?auth="..authenticationToken;
local Firebase = {};
function Firebase.GetDatastore()
return datastore;
end
function Firebase:GetAsync(directory)
local data = nil;
--== Firebase Get;
local getTick = tick();
local tries = 0; repeat until pcall(function() tries = tries +1;
data = HttpService:GetAsync(databaseName..HttpService:UrlEncode(directory and "/"..directory or "")..authentication, true);
end) or tries > 2;
if type(data) == "string" then
if data:sub(1,1) == '"' then
return data:sub(2, data:len()-1);
elseif data:len() <= 0 then
return nil;
end
end
return tonumber(data) or data ~= "null" and data or nil;
end
function Firebase:SetAsync(directory, value, header)
if not UseFirebase then return end
if value == "[]" then self:RemoveAsync(directory); return end;
--== Firebase Set;
header = header or {["X-HTTP-Method-Override"]="PUT"};
local replyJson = "";
if type(value) == "string" and value:len() >= 1 and value:sub(1,1) ~= "{" and value:sub(1,1) ~= "[" then
value = '"'..value..'"';
end
local success, errorMessage = pcall(function()
replyJson = HttpService:PostAsync(databaseName..HttpService:UrlEncode(directory and "/"..directory or "")..authentication, value,
Enum.HttpContentType.ApplicationUrlEncoded, false, header);
end);
if not success then
warn("FirebaseService>> [ERROR] "..errorMessage);
pcall(function()
replyJson = HttpService:JSONDecode(replyJson or "[]");
end)
end
end
function Firebase:RemoveAsync(directory)
if not UseFirebase then return end
self:SetAsync(directory, "", {["X-HTTP-Method-Override"]="DELETE"});
end
function Firebase:IncrementAsync(directory, delta)
delta = delta or 1;
if type(delta) ~= "number" then warn("FirebaseService>> increment delta is not a number for key ("..directory.."), delta(",delta,")"); return end;
local data = self:GetAsync(directory) or 0;
if data and type(data) == "number" then
data = data+delta;
self:SetAsync(directory, data);
else
warn("FirebaseService>> Invalid data type to increment for key ("..directory..")");
end
return data;
end
function Firebase:UpdateAsync(directory, callback)
local data = self:GetAsync(directory);
local callbackData = callback(data);
if callbackData then
self:SetAsync(directory, callbackData);
end
end
return Firebase;
end
return FirebaseService;
Error Code:
23:50:36.033 TestService: Data table for bans is currently nil. - Studio
23:50:36.255 FirebaseService>> [ERROR] HTTP 401 (Unauthorized) - Studio
I have tried to create new database + renewing my auth token, still getting Error code 401.
I feel like its my auth token issue but at the same time I don't think it is either, hope you guys can help me figure out the error. Feel free to ask if you need more info regarding this issue.
It turns out my auth token was the wrong one, everything's good now
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>
dic1 = {}
class Piglet:
pass
def __init__(self,name,age):
self.name = name
self.age = age
def speak_or_not(self):
if self.age>2:
return True
else:
return False
def speak_dic(self):
global dic1
dic1[self.name] = speak_or_not()
pig1 = Piglet("Shaun",3)
pig1.speak_dic()
print(dic1)
I want to add the return value of the function speak_or_not as a value of dictionary dic1 which will result in a output like: {"Shaun":True} since age>2. But it prints an empty dictionary.
How to call a function and set the return value of the function as a value of the dictionary?
The code is not correct. In the speak_dic function, you are calling speak_or_not, which does not exist. Instead, you need to call self.speak_or_not.
Attaching the corrected code below.
dic1 = {}
class Piglet:
def __init__(self,name,age):
self.name = name
self.age = age
def speak_or_not(self):
if self.age>2:
return True
else:
return False
def speak_dic(self):
global dic1
dic1[self.name] = self.speak_or_not()
pig1 = Piglet("Shaun",3)
pig1.speak_dic()
print(pig1)
Also, you need to print dic1 to show the dictionary.
Hope this helps.
I've found that I can use private variables in coffeescript classes like so:
class Book
title = null
numberOfPages = null
constructor: (t, nop) ->
title = t
numberOfPages = nop
ripOutPages: (numPages) -> numberOfPages = numberOfPages - numPages
isEmpty: -> numberOfPages == 0
So my first question is, is this considered a reasonable approach in coffeescript?
And my second question is, is there a neater way to achieve this (i.e. not having to initialise the variables in the class body then assign them in the constructor)?
Thanks,
Tom
If you look at the generated JS code, you will notice that those are more like "private" static class properties, not "private" instance properties:
var Book;
Book = (function() {
var numberOfPages, title;
title = null;
numberOfPages = null;
function Book(t, nop) {
title = t;
numberOfPages = nop;
}
Book.prototype.ripOutPages = function(numPages) {
return numberOfPages = numberOfPages - numPages;
};
Book.prototype.isEmpty = function() {
return numberOfPages === 0;
};
return Book;
})();
Every instance you create shares the same title and numberOfPages variables. So I guess the answer is: No, it's not a suitable approach for what you are trying to do.
JavaScript simply doesn't have "private" properties (yet).
If you really-really want "private" variable, you might want to define your methods as closures:
class Book
constructor: (t, nop) ->
# Those are two local variables:
title = t
numberOfPages = nop
# The following closures will have access to the two variable above:
#title = -> title # <- accessor to title
#numberOfPages = -> numberOfPages # <- accessor to numberoOfPage
#ripOutPages = (numPages) -> numberOfPages = numberOfPages - numPages
isEmpty: -> #numberOfPages() == 0
# ^^^^^^^^^^^^^^^^
# declared "as usual" as it uses accessor to access the "private" variables
# Some tests
lotr = new Book("The Lord of the Rings",1137)
hobbit = new Book("The Hobbit",276)
console.log lotr.title(), lotr.numberOfPages()
console.log hobbit.title(), hobbit.numberOfPages()
lotr.ripOutPages 100
console.log lotr.title(), lotr.numberOfPages()
Producing:
The Lord of the Rings 1137
The Hobbit 276
The Lord of the Rings 1037
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"