egghelp.org community Forum Index
[ egghelp.org home | forum home ]
egghelp.org community
Discussion of eggdrop bots, shell accounts and tcl scripts.
 
 FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

Namespaces

 
Post new topic   Reply to topic    egghelp.org community Forum Index -> Tcl FAQ
View previous topic :: View next topic  
Author Message
Sir_Fz
Revered One


Joined: 27 Apr 2003
Posts: 3793
Location: Lebanon

PostPosted: Sat Dec 30, 2006 9:33 am    Post subject: Namespaces Reply with quote

Written by BarkerJr. Source: http://www.barkerjr.net/irc/eggdrop/Scripting/namespaces.php.
-----------------------------------------------------------------------------------------------------

Why namespaces? If you've ever had issues with global variables or procedures in your script conflicting with other scripts, you need namespaces. Namespaces are the closest that Tcl gets to object oriented programming. They allow the programmer to place variables and procedures inside one neat named-package in Tcl so as not to conflict with anything in the global namespace.


Lets Begin!
Code:
namespace eval MyScript {
  variable response "Hello World!"

  bind pub - "hi" MyScript::respond
  proc respond {nick uhost hand chan text} {
    variable response
    puthelp "PRIVMSG $nick :$response"
    return 1
  }
}

MyScript is the name of the namespace. This will be the prefix used in the name of variables and procedures if they are being called from other namespaces (such as the global). Notice that the bind specifies the full name in the procedure parameter. Another thing to note is that the variable $response resides within the namespace. That means it's not a global variable. So, inside the procedure, it is declared as a variable, rather than global. Note that variables must be declared on separate lines if you have more than one. They cannot be declared in one long line like globals.
Code:
catch MyScript::uninstall
namespace eval MyScript {
  variable response "Hello World!"

  bind pub - "hi" MyScript::respond
  proc respond {nick uhost hand chan text} {
    variable response
    puthelp "PRIVMSG $nick :$response"
    return 1
  }

  bind evnt - prerehash MyScript::uninstall
  proc uninstall {args} {
    unbind pub - "hi" MyScript::respond
    unbind evnt - prerehash MyScript::uninstall
    namespace delete MyScript
  }
}

Rather than forcing users to .restart to uninstall scripts, lets uninstall on rehash. If the user still has the script in the conf, it'll be loaded automatically after the rehash. First of all, binds are not directly associated with the namespace, so they have to be unbound separatly. Then the namespace itself can be deleted. Don't forget to kill any timers that may be in your script here, too. Also, in order to also uninstall/reinstall for users that .tcl source the script, add the top line to call the uninstall procedure. The catch is there so that the bot doesn't crash if the uninstall procedure doesn't exist yet (first run).
Code:
set ns "MyScript"
catch ${ns}::uninstall
namespace eval $ns {
  unset ::ns

  variable response "Hello World!"

  bind pub - "hi" [namespace current]::respond
  proc respond {nick uhost hand chan text} {
    variable response
    puthelp "PRIVMSG $nick :$response"
    return 1
  }

  bind evnt - prerehash [namespace current]::uninstall
  proc uninstall {args} {
    unbind pub - "hi" [namespace current]::respond
    unbind evnt - prerehash [namespace current]::uninstall
    namespace delete [namespace current]
  }
}

If you are worried about the the namespace possibly conflicting with another namespace, do something like this. First, set the namespace in a global variable. It's only used in the first two lines, so we unset the global variable after, so as not to clutter up the global namespace. After that, [namespace current] should be used anywhere MyScript was used. Doing this will make it practically impossible for your script to conflict with someone else's.


All Done!
-----------------------------------------------------------------------------------------------------
Edit: Replaced [set] commands with [variable] inside namespace after reading user's tip.
_________________
Follow me on GitHub

- Opposing

Public Tcl scripts


Last edited by Sir_Fz on Thu Jan 11, 2007 10:35 pm; edited 1 time in total
Back to top
View user's profile Send private message Visit poster's website
user
 


Joined: 18 Mar 2003
Posts: 1452
Location: Norway

PostPosted: Sat Dec 30, 2006 11:59 am    Post subject: slight error Reply with quote

To create a variable inside a namespace you have to use 'variable', not 'set'. If a variable by that name exists in a parent namespace, you'll change the existing one outside your namespace (which defeats the purpose of this whole name conflict avoiding thing Razz)
Code:
% set test 1; namespace eval test {set test 2}; set test
2
% set test2 1; namespace eval test2 {variable test2 2}; set test2
1

You can assign a value to scalar variables using 'variable' (like i did in test 2), but if your variable is an array, do 'variable theArray', then 'set' / 'array set' to create elements. Just make sure you use 'variable' the first time you address a variable inside your namespace if you want to make sure you're not messing with parent namespaces.
_________________
Have you ever read "The Manual"?
Back to top
View user's profile Send private message
nml375
Revered One


Joined: 04 Aug 2006
Posts: 2829

PostPosted: Sat Feb 28, 2009 1:21 pm    Post subject: Reply with quote

When dealing with namespaces, and making sure bindings work correctly, I'd create a separate namespace called eggdrop with a replacement for the bind function, utilizing the namespace code along with uplevel to capture the actual namespace. No more hazzle with namespace current..
Keep in mind that your binds will look a little messy however.

Code:
namespace eval eggdrop {
#First export functions for easy access:
 namespace export bind

 proc bind {type flag mask proc} {
  ::bind $type $flag $mask [uplevel 1 [list namespace code $proc]]
 }
}


To use this, you'd simply do something like this:
Code:
namespace eval myspace {
 #import the namespace along with bind, so we don't have to use the long version ::eggdrop::bind
 namespace import ::eggdrop::*

 proc myproc {nick host handle text} {
  puthelp "PRIVMSG $nick :Hello $nick! I see you from $host, know you as $handle, and recieved $text from you."
 }
 bind msg - foo myproc

}

_________________
NML_375, idling at #eggdrop@IrcNET
Back to top
View user's profile Send private message
Display posts from previous:   
Post new topic   Reply to topic    egghelp.org community Forum Index -> Tcl FAQ All times are GMT - 4 Hours
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Forum hosting provided by Reverse.net

Powered by phpBB © 2001, 2005 phpBB Group
subGreen style by ktauber