+ Reply to Thread
Page 2 of 3 FirstFirst 1 2 3 LastLast
Results 16 to 30 of 35

  Click here to go to the first Rift Team post in this thread.   Thread: Exposing addons to other things that want them?

  1. #16
    Rift Chaser Imhothar's Avatar
    Join Date
    Feb 2012
    Posts
    395

    Default

    The Addon "data" table is provided to every Lua file loaded by Rift. The Lua files are actuall called with two tables which you can access like this at the top of your Lua file:
    Code:
    local table1, table2 = ...
    table1 has the keys "id", "identifier", "data" and "toc". "toc" contains the entire contents of RiftAddon.toc. I have no idea what table2 is for as it is empty. If you do not care about the tables themselves just use:
    Code:
    local id = (...).id
    local identifier = (...).identifier
    local data = (...).data
    local toc = (...).toc
    In all my files I then call
    Code:
    setfenv(1, data)
    so not to mess with the global namespace. Making the table public is quick:
    Code:
    _G[identifier] = data
    and works independently of your Addon's name. You could alternatively make a different table public which contains only the public API methods of your Addon and relays all requests to your internal code. This way you can achieve a very good encapsulation.

  2. #17
    Champion Lorandii's Avatar
    Join Date
    Jun 2011
    Posts
    513

    Default

    This whole thread has been discussed recently
    Code:
    local MyAddon, MyAddonData = ...
    The table MyAddonData can contain anything, and yes, starts with a nil value. You could use the data table to contain options, localizations, frames, variables, whatever.
    • local L = MyAddonData.L -- assuming you already created localization meta table (how-to link)
    • MyAddonData.options -- if you wanted your options in a seperate file within the same addon
    • MyAddonData.someFrameName -- create the frame in FileOne.lua and access it in FileTwo.lua
    And so on and so forth.

  3. #18
    Rift Chaser Imhothar's Avatar
    Join Date
    Feb 2012
    Posts
    395

    Default

    Hm, I was assuming MyAddon.data was supposed to be the private table. What purpose does it have if that role is taken by the second table? MyAddon.data is empty on startup, too.

  4. #19
    Champion Lorandii's Avatar
    Join Date
    Jun 2011
    Posts
    513

    Default

    Quote Originally Posted by Imhothar View Post
    Hm, I was assuming MyAddon.data was supposed to be the private table. What purpose does it have if that role is taken by the second table? MyAddon.data is empty on startup, too.
    It is the private table, and you are are reading it wrong. I typed "MyAddonData" not "MyAddon.Data". Name it whatever you wish, just like any other variable. I could have typed
    Code:
    local Bob, Mary = ...
    For all that it matters.

  5. #20
    Rift Chaser Imhothar's Avatar
    Join Date
    Feb 2012
    Posts
    395

    Default

    I didn't misread it.
    Code:
    local MyAddon, somethingElse =...
    MyAddon.data is initally present and is an empty table. I'd like to know its purpose.

  6. #21
    Champion Lorandii's Avatar
    Join Date
    Jun 2011
    Posts
    513

    Default

    Oh, sorry, I misread you. I apologize. Scrolled up to see you first post with the explanation using table1, table2 ... and I'm not sure what the .data is for. The only thing I ever use that first table is creating functions.
    Code:
    local MyAddon, privateData = ...
    function MyAddon:SomeFunction() end
    If you figure out something fancier, I'd love to know!

  7.   Click here to go to the next Rift Team post in this thread.   #22
    RIFT Moderator
    Join Date
    Oct 2010
    Posts
    900

    Default

    Quote Originally Posted by Lorandii View Post
    Oh, sorry, I misread you. I apologize. Scrolled up to see you first post with the explanation using table1, table2 ... and I'm not sure what the .data is for. The only thing I ever use that first table is creating functions.
    Code:
    local MyAddon, privateData = ...
    function MyAddon:SomeFunction() end
    If you figure out something fancier, I'd love to know!
    Actually, what you're doing is kind of unsupported

    "data", or "privateData", is the table that's guaranteed to be preserved through the lifetime of the addon. "MyAddon" is simply the same table you'd get from Inspect.Addon.Detail(). It might be destroyed without notice and recreated. Right now what you're doing will probably work, but it may at some point stop working.

    In retrospect it's possible I should have made it read-only. I may do that in the future if this turns out to be a common issue.

  8. #23
    Rift Chaser Imhothar's Avatar
    Join Date
    Feb 2012
    Posts
    395

    Default

    No problem.
    The documentation of Inspect.Addon.Detail() says it is "The "data" table provided to the addon at load time.". Whatever that's good for.

    Well I make most of my functions local to avoid name clashing.

    All of my files start with
    Code:
    local identifier = (...).identifier
    local addon = (...).data
    
    -- Make local copies of globals here
    local print = print
    ...
    
    setfenv(1, addon)
    Module1 = Module1 or { }
    
    local function privateMethod1()
    ...
    end
    
    function Module1.InternalAddonMethod1()
    ...
    end
    But after I learned there is a dedicated private table provided by Rift I'm going to switch to that instead of (...).data now. Plus I don't want the private table to be queryable by any Rift API.

    After the setfenv everything is declared inside the addon table. First it saves me some tiping and second I won't pollute the global namespace if I accidentally forget the "local" keyword. I use the Addon:Method() syntax only for "instance" methods where the "self" argument varies (i.e. static or instance method), which is not required for static modules without inheritance and saves the passing of one parameter.

    I try to follow the public/private ideology of OO programming. In this example privateMethod1 would be "private" to Module1. In contrary InternalAddonMethod1 is "public", but only usable inside my Addon (like "internal" in C#). Module1 in this example is more comparable to a namespace (or static class) than a class.

    For classes I use the colon syntax in the public part:
    Code:
    setfenv(1, addon)
    Class1 = { }
    
    local function private1(self)
    end
    
    -- Callable with instance:Public1()
    local function Public1(self)
    
    
    -- Factory method for creating an instance of "Class"
    function Class1.New()
        local result = { } -- or UI.CreateFrame(...) etc
        result.Public1 = Public -- Or set metatable if result is not a Frame
        return result
    end
    There are many ways to do the latter. With or without metatable, declaring all public methods locally inside Class1.New() or not and more. But the result is the same: some functions are usable by others and some aren't, which I think is what the OP asked for.

    Using the MyAddon table as the container for the public API is a good idea. I like that.

  9. #24
    Rift Chaser Imhothar's Avatar
    Join Date
    Feb 2012
    Posts
    395

    Default

    Quote Originally Posted by ZorbaTHut View Post
    Actually, what you're doing is kind of unsupported

    "data", or "privateData", is the table that's guaranteed to be preserved through the lifetime of the addon. "MyAddon" is simply the same table you'd get from Inspect.Addon.Detail(). It might be destroyed without notice and recreated. Right now what you're doing will probably work, but it may at some point stop working.

    In retrospect it's possible I should have made it read-only. I may do that in the future if this turns out to be a common issue.
    Ok, after reading this scratch the last sentence in my previous post. Just realized that MyAddon.data and privateData are the same objects. There goes my perfect encapsulation

    I was worried about the result from Inspect.Addon.Detail() not being persistent. So the best way of providing an easy-to-use public API is probably still the global MyAddon = { } approach...?

  10. #25
    Champion Lorandii's Avatar
    Join Date
    Jun 2011
    Posts
    513

    Default

    Quote Originally Posted by ZorbaTHut View Post
    Actually, what you're doing is kind of unsupported

    "data", or "privateData", is the table that's guaranteed to be preserved through the lifetime of the addon. "MyAddon" is simply the same table you'd get from Inspect.Addon.Detail(). It might be destroyed without notice and recreated. Right now what you're doing will probably work, but it may at some point stop working.

    In retrospect it's possible I should have made it read-only. I may do that in the future if this turns out to be a common issue.
    Unsupported? Yikes! Would this be better, and supported?
    Code:
    local addon, pt = ...
    local MyAddon = addon or {}
    function MyAddon:SomeFunction() end

  11. #26
    Rift Disciple Verea's Avatar
    Join Date
    Feb 2011
    Location
    Netherlands
    Posts
    179

    Default

    Quote Originally Posted by Imhothar View Post
    I try to follow the public/private ideology of OO programming. In this example privateMethod1 would be "private" to Module1. In contrary InternalAddonMethod1 is "public", but only usable inside my Addon (like "internal" in C#). Module1 in this example is more comparable to a namespace (or static class) than a class.
    A bit off topic, but as you like OOP, here is a cool little trick to make variables private (i.e: only accessible through functions) yet make a public 'class'.

    Code:
    myClass = {}
    
    function myClass:new(object)
         local object = object or {}
         -- stuff here, the usual
    
         -- private
         self.varName = 0
    
         -- public
         local add = function(n)
              self.varName = self.varName + 10
         end
    
         return {
             add = add
         }
    end
    
    local someInstance = myClass:new()
    
    someInstance.add(100) -- can only change someInstance.varName through this function
    Just a cool example, for further OOP support, check out libTea:
    http://forums.riftgame.com/beta-addo...-everyone.html
    Asleep, level 50 Cleric @ Blightweald EU [Darkwind]
    I want to fly like an eagle, to the sea.
    I want to fly like an eagle, let my spirit carry me.

  12. #27
    Rift Chaser Imhothar's Avatar
    Join Date
    Feb 2012
    Posts
    395

    Default

    Iif you change "self" to "object" in your example it is definitely the way to go for public classes.
    But for code under my control I rather avoid the additional upvalue-lookup and take it a bit more relaxed with encapsulation and information hiding.

  13.   Click here to go to the next Rift Team post in this thread.   #28
    RIFT Moderator
    Join Date
    Oct 2010
    Posts
    900

    Default

    Quote Originally Posted by Imhothar View Post
    Ok, after reading this scratch the last sentence in my previous post. Just realized that MyAddon.data and privateData are the same objects. There goes my perfect encapsulation
    Perfect encapsulation is something we're intentionally not supporting. At some point I'd love to reintroduce the Lua debug functions, and once that happens, anyone will be able to walk through the upvalue tree to access any variables in your addon.

    Keep your code clean, absolutely, but there's never going to be a guaranteed way to *perfectly* prevent people from mucking around with your addon in ways you don't want. Scripting languages tend to not support that well

    Quote Originally Posted by Lorandii View Post
    Unsupported? Yikes! Would this be better, and supported?
    Code:
    local addon, pt = ...
    local MyAddon = addon or {}
    function MyAddon:SomeFunction() end
    Here's what you want to do:

    Code:
    local addonInfo, MyAddon = ...
    function MyAddon:SomeFunction() end
    If I do end up breaking your code, you'll probably have the standard patch-cycle-or-two of warning, by the way. Nobody likes randomly breaking addons.

    Edit: Actually, I'm gonna errata this.

    If the intention is that SomeFunction is private, then you want:

    Code:
    local addonInfo, MyAddonPriv = ...
    function MyAddonPriv:SomeFunction() end
    If the intention is that SomeFunction is public, then you probably want something along the lines of:

    Code:
    MyAddon = MyAddon or {}
    function MyAddon:SomeFunction() end
    Last edited by ZorbaTHut; 03-02-2012 at 12:45 PM.

  14. #29
    Champion Lorandii's Avatar
    Join Date
    Jun 2011
    Posts
    513

    Default

    No wonder my code was frustrating me, I had the variables backwards. Or at least their purpose. That was driving me nuts, actually. Thanks Zorba!

  15. #30
    RIFT Community Ambassador the_real_seebs's Avatar
    Join Date
    Jan 2011
    Posts
    13,477

    Default

    Oh, weird. I did a tiny test thing of

    local foo = ...

    and foo was nil.

    ... ohhh. I tested it with /print foo. So basically, I tried to find the global after defining a local. SMART! I AM SMART!
    You can play WoW in any MMO. You don't have to play WoW in RIFT. Oh, and no, RIFT is not a WoW clone. Not having fun any more? Learn to play, noob! I don't speak for Riftui, but I moderate stuff there. Got ideas for improving the RIFT community? Feel free to PM me. Just came back? Welcome back! Here's what's changed. (NOTE NEW URL)

+ Reply to Thread
Page 2 of 3 FirstFirst 1 2 3 LastLast

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts