<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>lua nova &#187; Uncategorized</title>
	<atom:link href="http://www.luanova.org/category/uncategorized/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.luanova.org</link>
	<description>welcome to the moon</description>
	<lastBuildDate>Thu, 23 Sep 2010 12:46:53 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0</generator>
		<item>
		<title>iOS Programming with Lua</title>
		<link>http://www.luanova.org/ioswithlua/</link>
		<comments>http://www.luanova.org/ioswithlua/#comments</comments>
		<pubDate>Thu, 23 Sep 2010 12:46:53 +0000</pubDate>
		<dc:creator>mathewburke</dc:creator>
				<category><![CDATA[Lua]]></category>
		<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[Lua iOS]]></category>

		<guid isPermaLink="false">http://luanova.org/?p=81</guid>
		<description><![CDATA[Matthew Burke, Bluedino Software In this article I will discuss three methods for using Lua to build iOS apps. The techniques range from using Lua to build the entire application (Corona) to using Lua as a component for scripting your application (do it yourself or Wax). Before getting into the details, there are two main [...]]]></description>
			<content:encoded><![CDATA[<h3>Matthew Burke, Bluedino Software</h3>

<p>In this article I will discuss three methods for using Lua to build iOS apps.  The techniques range from using Lua to build the entire application (<a href="#corona">Corona</a>) to using Lua as a component for scripting your application (<a href="#diy">do it yourself</a> or <a href="#wax">Wax</a>).  Before getting into the details, there are two main questions to answer:</p>

<ol>
<li>Why use Lua?</li>
<li>Will Apple let you use Lua?</li>
</ol>

<p>The answers to these questions are intertwined.</p>

<p>In case you landed here without knowing anything about Lua, let me hit the high points of the language.  If you already are familiar with Lua, you can <a href="#iphone-script">skip ahead</a>.</p>

<h3>About Lua</h3>

<p><a href="http://www.lua.org">Lua</a> is a fast, lightweight, embedded scripting language.  It is similar to languages such as JavaScript, Ruby or Python.  Many of its users, including myself, feel Lua is a particularly clean and elegant language.</p>

<p>Lua was created in 1993 by Roberto Ierusalimschy, Waldemar Celes and Luiz Henrique de Figueiredo at the Pontifical Catholic University in Rio de Janeiro, Brazil.  It is used in a range of applications including <a href="http://micasaverde.com/">Mi Casa Verde</a>, <a href="http://since1968.com/article/190/mark-hamburg-interview-adobe-photoshop-lightroom-part-2-of-2">Adobe Lightroom</a>, <a href="http://www.shatters.net/celestia/">Celestia</a>, <a href="http://www.lighttpd.net/">lighttpd</a>, <a href="http://www.luatex.org/">LuaTeX</a>, <a href="http://nmap.org/">nmap</a>, <a href="http://www.wireshark.org/">Wireshark</a>, Cisco&#8217;s Adaptive Security Appliance, <a href="http://www.hempeldesigngroup.com/lego/pbLua/">pbLua</a>, and a ton of games including <a href="http://en.wikipedia.org/wiki/Grim_Fandango">Grim Fandango</a>, <a href="http://en.wikipedia.org/wiki/World_of_Warcraft">World of Warcraft</a>, <a href="http://en.wikipedia.org/wiki/Tap_Tap_Revenge">Tap Tap Revenge</a>, and many others.  <a href="http://www.lua.org/license.html">Lua&#8217;s license</a> is a variation of the MIT License&mdash;this means that there are essentially no hurdles to including Lua in both commerical and non-commerical projects.</p>

<p>Lua&#8217;s main data structuring mechanism is the table&mdash;a combination resizable array and hash.  Listing 1 shows a table we might use in a hypothetical application to keep track of automobiles and their gas mileage.  We can store information about the automobile using string keys such as <strong>license</strong> and <strong>make</strong>.  A series of mileage readings are stored using integer indices.</p>

<div class="panelHeader">Listing 1: A Lua Table</div>

<p><code></p>


<div class="wp_syntax"><div class="code"><pre class="lua" style="font-family:monospace;">&nbsp;
car_data <span style="color: #66cc66;">=</span> <span style="color: #66cc66;">&#123;</span> license <span style="color: #66cc66;">=</span> <span style="color: #ff0000;">'XVW1942'</span>, make <span style="color: #66cc66;">=</span> <span style="color: #ff0000;">'Volvo'</span>,
                model <span style="color: #66cc66;">=</span> <span style="color: #ff0000;">'XC70'</span>, <span style="color: #cc66cc;">30</span>, <span style="color: #cc66cc;">31.3</span>, <span style="color: #cc66cc;">32.4</span>, <span style="color: #cc66cc;">34.0</span> <span style="color: #66cc66;">&#125;</span>
&nbsp;
<span style="color: #b1b100;">print</span><span style="color: #66cc66;">&#40;</span>car_data<span style="color: #66cc66;">&#91;</span><span style="color: #cc66cc;">1</span><span style="color: #66cc66;">&#93;</span><span style="color: #66cc66;">&#41;</span>                <span style="color: #808080; font-style: italic;">-- 30</span>
<span style="color: #b1b100;">print</span><span style="color: #66cc66;">&#40;</span>car_data<span style="color: #66cc66;">&#91;</span><span style="color: #ff0000;">'license'</span><span style="color: #66cc66;">&#93;</span><span style="color: #66cc66;">&#41;</span>       <span style="color: #808080; font-style: italic;">-- XVW1942</span>
<span style="color: #b1b100;">print</span><span style="color: #66cc66;">&#40;</span>car_data.license<span style="color: #66cc66;">&#41;</span>          <span style="color: #808080; font-style: italic;">-- XVW1942 (also!)</span></pre></div></div>


<p></code></p>

<div class="panelFooter">In Lua, array indices start at one, not zero.
Comments are indicated by &#8216;&#8211;&#8217; and run to the end of the line.
</div>

<p>Out of the box, Lua is neither an object-oriented (OO) programming language nor a functional programming language.  Rather, it provides a small set of mechanisms with which you can build your own higher-level features.  A number of different object systems have been built in Lua including more traditional OO systems as well as classless OO systems (<em>&agrave; la</em> languages like <a href="http://research.sun.com/self/language.html">Self</a> or <a href="http://www.iolanguage.com/">Io</a>).  Lua supports first-class functions and lexical closures and has a meta-programming facility (known as metatables and metamethods).  Lua can be used in a functional programming style</p>

<p>For a gentle introduction to OO in Lua, read <a href="http://www.lua.org/pil/16.html">Programming in Lua</a> (<span class="tiny">in fact, PIL is a very well-written book on Lua in particular and programming in general</span>).  You should also look at the several examples available on <a href="http://lua-users.org/wiki/ObjectOrientedProgramming">Lua wiki</a>.</p>

<p>If you <em>like</em> drinking from a firehose, Listing 2 shows one possible implementation for a linked list class.  The table stored in the variable <strong>List</strong> serves as a metatable for all linked list objects.  It  provides a fall-back location for looking up table indexes and thus serves as a class dispatch mechanism.  The line &#8220;<strong>List.__index = List</strong>&#8221; is what allows us to create methods for our list objects.  Methods are implemented as functions stored in the <strong>List</strong> metatable.  When we attempt to call one of these functions on our list object, the lookup mechanism will lead us to the function defined on the <strong>List</strong> metatable and that&#8217;s what will get run.</p>

<p>The code shows a number of additional features of Lua: multiple assignment (<span class="tiny">and functions can return multiple results</span>), syntactic sugar for method calls (the &#8216;:&#8217; notation, this performs the common technique&mdash;used in languages ranging from Python to Objective-C&mdash;of rewriting the function call to have an additional parameter which points to <strong>self</strong>).</p>

<div class="panelHeader">Listing 2: Linked List Class</div>

<p><code></p>

<pre>
List = {}
List.__index = List

function List:new()
  local l = { head = {}, tail = {}, size = 0 }
  l.head.__next, l.tail.__prev = l.tail, l.head
  return setmetatable(l, self)
end

function List:first()
  if self.size > 0 then
    return self.head.next
  else
    return nil
  end
end

function List:addFirst(elem)
   local node = { prev = self.head, value = elem, 
                        next = self.head.next }
   node.next.prev = node
   self.head.next = node
   self.size = self.size + 1
end

mylist = List:new()
mylist:addFirst(12)
print(mylist:first())

</pre>

<p></code></p>

<p>I&#8217;m sure I&#8217;ve left out the really interesting/important things (<span class="tiny">such as lexical closures</span>), but this at least gives you a little taste of Lua.  There are more samplings below when we get to actual iPhone coding.  For further details on Lua, see the <a href="">web site</a>.</p>

<p><a name="iphone-script"></a></p>

<h3>Can I Script on iOS?</h3>

<p>Of the two questions listed at the beginning of this article, the most important question to address is are you allowed to use Lua (or any interpreted language) on the iPhone?  After all, early on the iPhone Developer Program License Agree stated that &#8220;[n]o interpreted code may be downloaded or used in an Application except for code that is interpreted and run by Apple&#8217;s Documented APIs and built- in interpreter(s).&#8221;</p>

<p>In fact, an earlier version of this article was tabled when Apple made changes to the developer license  (circa April 2010) which forbade developing iOS applications in any language other than Objective-C and Javascript (<span class="tiny">the Javascript could be used either to build web apps or native apps via the UIWebView</span>).  Recently (September 2010), Apple again changed the developer license to allow the use of scripting languages..</p>

<p>There are still several important constraints in place.  In particluar, although you can use Lua and other scripting languages, you cannot create an application where users could download plugins for your app from your website (<span class="tiny">in-app purchasing anyone?</span>), nor can you allow the user to write scripts, download scripts, etc.  There are (<span class="tiny">and have been, e.g. Tap Tap Revenge</span>) quite a number of apps available on the app store that use Lua as well as other languages.</p>

<p>Of course, creating a plugin system and allowing users to write scripts are two major use cases for including a language like Lua in your application, so what&#8217;s left?  Plenty!</p>

<h3>Why Use Lua for iOS development?</h3>

<p>Although you cannot expose a plugin system to the end user, nor can you give her the ability to write her own scripts, you can still develop your system using a plugin architecture!  This can both speed up initial development as well as be a big help when it&#8217;s time to add functionality for the next version.</p>

<p>There are other benefits from using Lua.  It allows you to develop using rapid prototyping (<span class="tiny">beware my pet peeve: don&#8217;t devolve into seat-of-your-pants programming</span>), reduces/eliminates the need to worry about memory allocation, allows more of your team to participate in development (<span class="tiny">many Lua projects have non-programmers writing code</span>), makes it easier to <em>tune</em> your application, and provides a powerful persistence mechanism.</p>

<p>In short, using Lua can reduce development time and lower entry barriers. And it&#8217;s just plain <em>fun</em>!</p>

<p>Assuming you&#8217;re sold you on the idea of using Lua, how do we go about it?</p>

<p><a name="corona"></p>

<h3>Corona</h3>

<p></a></p>

<p>Ansca Mobile&#8217;s Corona allows you to develop your iOS app entirely in Lua.  And it&#8217;s not just for iOS.  You can also develop apps for Android.  In fact, you can use the same source code to build both an iOS and an Android app.  This adds a compelling reason to use Lua (<span class="tiny">and, in particular, to use Corona</span>): the ability to easily build cross-platform applications.</p>

<p>Listing 3 is the complete source for an app.</p>

<div class="panelHeader">Listing 3: main.lua from the Swirly Text app</div>

<p><code></p>

<pre>
local w, h = display.stageWidth, display.stageHeight
local dx, dy, dtheta = 5, 5, 5


local background = display.newRect(0, 0, w, h)
background:setFillColor(255, 255, 255)


local message = display.newText('Hello from Corona', w/2, h/2)
message:setTextColor(0, 0, 200)


local function update(event)
   local counter_spin = false
   message:translate(dx, dy)
   message:rotate(dtheta)
   if message.x > w or message.x < 0 then
      dx = -1 * dx
      counter_spin = true
   end
   if message.y > h or message.y < 0 then
      dy = -1 * dy
      counter_spin = true
   end
   if counter_spin then
      dtheta = -1 * dtheta
   end
end


Runtime:addEventListener('enterFrame', update)

</pre>

<p></code></p>

<p>Corona apps are developed using your favorite text editor&mdash;I use Emacs.  All Lua source code and any necessary resources (images, sounds, and data) must reside in a single directory and Corona expects a Lua file, <strong>main.lua</strong> which is where your app starts executing.  You test your code in Corona's simulator which runs on both Intel and PPC Macs.  Figure 1 shows my Corona 'IDE': namely Emacs with two windows (a Lua file and the project directory), the Corona terminal (you can print debugging info to the terminal), and the Corona simulator.</p>

<div class="panelHeader">Figure 1: My Corona 'IDE'</div>

<p><a href="http://mysite.mweb.co.za/residents/sdonovan/lua/CoronaIDE.png">
<img src="http://mysite.mweb.co.za/residents/sdonovan/lua/CoronaIDE.png" width="760px" style="margin: 10px" /></a></p>

<div class="panelFooter">Clockwise from the left: Corona simulator, Emacs with two windows (a source file and project directory), the Corona terminal (for debugging info).</div>

<p>When you are ready to run your app on actual hardware, you use the Corona Simulator's <strong>Open for Build</strong> option.  For an iOS build, you must have a provisioning profile (either development or distribution)&mdash;<span class="tiny">yes, Virginia, you do need a membership in the iOS Developer Program</span>&mdash;which is uploaded, along with your app's source and resources, to Ansca's servers.  A compiled app is returned to you. For Android builds, you will need a suitable signing certificate.  Again the build process is handled by uploading your source to Ansca's servers.  You do not need to have the Android SDK installed.</p>

<p>I haven't done any in-depth poking around, but both the .apk file from the Android build process and the iOS .app bundle contain a file containing all your Lua code pre-processed in some fashion.  Approximately seven seconds of examination suggests that it's not <em>standard</em> byte-compiled Lua code, but I'm guessing it must be a similar format.</p>

<p>Corona's event system lets you handle touches (<span class="tiny">including multi-touch</span>), access the GPS and the acceleratometer, handle animation, and define custom events.  There is a powerful graphics system which allows you to draw circles, rectangles and text.  They've recently added polylines so you can draw regular lines and polygons.  You can also display images.  Corona allows you to group these objects and do transformations on them.  Listing 4, an excerpt from a Solar System simulator, shows a (crude) example of grouping graphics objects.  Other Corona features include playing audio and video clips, a cryptography library, networking using the LuaSocket library, and access to SQLite databases (using LuaSQLite).  There is some access to native widgets including textfields, alerts and activity indicators. There's a nice feature where you can overlay a web view for doing things like login screens and a sample application provides a library for connecting to Facebook.  The last thing I'll mention is that there is a (more expensive) game edition that includes the Box2D physics engine, sprites and some OpenFeint functionality such as leaderboards.</p>

<div class="panelHeader">Listing 4: excerpt from Solar System app</div>

<p><code></p>

<pre>
function new(params)
   local color = params.color or planet_colors[random(#planet_colors)]
   local radius = params.radius or planetRadius()
   local planet = display.newGroup()

   planet.theta = 0
   local x = params.x - ox
   local y = params.y - oy
   planet.orbital_radius = sqrt(x*x+y*y)

   local body = display.newCircle(x + ox, y + oy, radius, radius)
   body:setFillColor(unpack(color))
   planet:insert(body, true)
   planet.body = body

   planet.delta_theta = (40/planet.orbital_radius) * 0.1

   return planet
end

</pre>

<p></code></p>

<div class="panelFooter">By passing a table as a function's paramter, we can make use of named
parameters and default values.  Thus, the idiom of local radius = params.radius or planetRadius()
</div>

<p>Corona gives you a lot.  However, there are still a lot of things missing with Corona.  The biggest item is the limited access to native controls.  Not to mention the access that is provided is awkward to use because of limited support in Corona's simulator.  In the simulator, native alerts and activity indicators are implemented using OS X equivalents, rather than the iOS widgets.  However, text fields, text boxes and web popups are unusable when running in the simulator. This makes development, to say the least, painful.</p>

<p>Finally, there is no mechanism to access the Objective-C API except for what ANSCA has specifically provided.  Not only does this mean you cannot access large portions of the standard libraries, but you cannot make use of third-party libraries like Three20, or one of the mobile ads APIs.  Of course, with the release of the Android version of Corona, you may not want to access the Objective-C API since it limits (<span class="tiny">or complicates</span>) your ability to do multi-platform applications.  It would be nice, however, to be able to add in Lua extensions that use Lua's C API, as many of these are multi-platform.</p>

<p>I've found the ANSCA staff to be quite helpful and responsive to questions posted in the forums on their website.  With the release of version 2.0 (September 2010), Corona costs $249 per developer per year.  The Game Edition is $349 per developer per year.  Ansca's website indicates that the game edition prices is pre-release.  I assume that means it will be higher when it is officially released.</p>

<p><a name="diy"></p>

<h3>DIY</h3>

<p></a></p>

<p>Including the Lua interpeter in your iOS app is simple. Open an Xcode project and add the Lua source files (<span class="tiny">except <strong>lua.c</strong> and <strong>luac.c</strong>&mdash;source for the command line programs</span>).  Compile.  You can now make use of the standard Lua C API to create an interpreter and run some code.  An example project, iLua, may be downloaded from <a href="http://github.com/profburke/ilua">http://github.com/profburke/ilua</a>.  iLuaShell is a simple, view-based application that presents the user with two text fields&mdash;an editable one where the user can enter Lua code and a non-editable one where the results of evaluating the Lua code are displayed.</p>

<p>The work is done in the method, <strong>evaluate</strong>, which is shown in Listing 5.  The method retrieves the text of the first text field, hands it off to the Lua interpreter which parses and executes it, and then sets the Lua output as the text of the output field.</p>

<div class="panelHeader">Listing 5: LuaTrial's <strong>evaluate</strong> method.</div>

<p><code></p>


<div class="wp_syntax"><div class="code"><pre class="c" style="font-family:monospace;"><span style="color: #339933;">-</span><span style="color: #009900;">&#40;</span><span style="color: #993333;">void</span><span style="color: #009900;">&#41;</span>evaluate <span style="color: #009900;">&#123;</span>
    <span style="color: #993333;">int</span> err<span style="color: #339933;">;</span>
&nbsp;
    <span style="color: #009900;">&#91;</span>input resignFirstResponder<span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
    lua_settop<span style="color: #009900;">&#40;</span>L<span style="color: #339933;">,</span> <span style="color: #0000dd;">0</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
    err <span style="color: #339933;">=</span> luaL_loadstring<span style="color: #009900;">&#40;</span>L<span style="color: #339933;">,</span> <span style="color: #009900;">&#91;</span>input.<span style="color: #202020;">text</span> 
                     cStringUsingEncoding<span style="color: #339933;">:</span>NSASCIIStringEncoding<span style="color: #009900;">&#93;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #0000dd;">0</span> <span style="color: #339933;">!=</span> err<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
        output.<span style="color: #202020;">text</span> <span style="color: #339933;">=</span> <span style="color: #009900;">&#91;</span>NSString stringWithCString<span style="color: #339933;">:</span>lua_tostring<span style="color: #009900;">&#40;</span>L<span style="color: #339933;">,</span> <span style="color: #339933;">-</span><span style="color: #0000dd;">1</span><span style="color: #009900;">&#41;</span> 
                             encoding<span style="color: #339933;">:</span>NSASCIIStringEncoding<span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
        lua_pop<span style="color: #009900;">&#40;</span>L<span style="color: #339933;">,</span> <span style="color: #0000dd;">1</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #b1b100;">return</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
&nbsp;
    err <span style="color: #339933;">=</span> lua_pcall<span style="color: #009900;">&#40;</span>L<span style="color: #339933;">,</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">,</span> LUA_MULTRET<span style="color: #339933;">,</span> <span style="color: #0000dd;">0</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #0000dd;">0</span> <span style="color: #339933;">!=</span> err<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
        output.<span style="color: #202020;">text</span> <span style="color: #339933;">=</span> <span style="color: #009900;">&#91;</span>NSString stringWithCString<span style="color: #339933;">:</span>lua_tostring<span style="color: #009900;">&#40;</span>L<span style="color: #339933;">,</span> <span style="color: #339933;">-</span><span style="color: #0000dd;">1</span><span style="color: #009900;">&#41;</span> 
                             encoding<span style="color: #339933;">:</span>NSASCIIStringEncoding<span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
        lua_pop<span style="color: #009900;">&#40;</span>L<span style="color: #339933;">,</span> <span style="color: #0000dd;">1</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        <span style="color: #b1b100;">return</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
    <span style="color: #993333;">int</span> nresults <span style="color: #339933;">=</span> lua_gettop<span style="color: #009900;">&#40;</span>L<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
    <span style="color: #b1b100;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #0000dd;">0</span> <span style="color: #339933;">==</span> nresults<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
        output.<span style="color: #202020;">text</span> <span style="color: #339933;">=</span> @<span style="color: #ff0000;">&quot;&lt;no results&gt;&quot;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span> <span style="color: #b1b100;">else</span> <span style="color: #009900;">&#123;</span>
        NSString <span style="color: #339933;">*</span>outputNS <span style="color: #339933;">=</span> <span style="color: #009900;">&#91;</span>NSString <span style="color: #993333;">string</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
        <span style="color: #b1b100;">for</span> <span style="color: #009900;">&#40;</span><span style="color: #993333;">int</span> i <span style="color: #339933;">=</span> nresults<span style="color: #339933;">;</span> i <span style="color: #339933;">&gt;</span> <span style="color: #0000dd;">0</span><span style="color: #339933;">;</span> i<span style="color: #339933;">--</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
            outputNS <span style="color: #339933;">=</span> <span style="color: #009900;">&#91;</span>outputNS stringByAppendingFormat<span style="color: #339933;">:</span>@<span style="color: #ff0000;">&quot;%s &quot;</span><span style="color: #339933;">,</span> 
                                               lua_tostring<span style="color: #009900;">&#40;</span>L<span style="color: #339933;">,</span> <span style="color: #339933;">-</span><span style="color: #0000dd;">1</span> <span style="color: #339933;">*</span> i<span style="color: #009900;">&#41;</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
        <span style="color: #009900;">&#125;</span>
        lua_pop<span style="color: #009900;">&#40;</span>L<span style="color: #339933;">,</span> nresults<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
        output.<span style="color: #202020;">text</span> <span style="color: #339933;">=</span> outputNS<span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span></pre></div></div>


<p></code></p>

<p>Note the error checking and handling is minimal.  A little additional effort could yield a nice Lua shell&mdash;not that you could actually put it in the App Store...</p>

<p>What are the drawbacks to this approach?  The biggest one is the lack of a bridge to Objective-C.  Ideally we want to call Objective-C methods from Lua. Going the other direction is important also.  Being able to code callbacks and delegate methods in Lua would be a big win.</p>

<p>Pursuing that leads us to...</p>

<p><a name="wax"></p>

<h3>iPhone Wax</h3>

<p></a></p>

<p>Powerful interoperability between Lua and Objective-C is the star attraction of iOS Wax by Corey Johnson.  Using Wax, you can easily subclass Objective-C classes <em>in Lua</em>!  Listing 6 shows a Wax implementation of a custom view controller.  In particular, this code is a port of the application described in the DIY section.  Details after the listing.</p>

<div class="panelHeader">Listing 6: RootViewController.lua</div>

<p><code></p>

<pre>
waxClass{'RootViewController', UI.ViewController }

function init(self)
        self.super:init()

    self.input = UI.TextView:initWithFrame(CGRect(20, 20, 280, 114))

    self.output = UI.TextView:initWithFrame(CGRect(20, 184, 280, 225))

    local evalButton = UI.Button:buttonWithType(UIButtonTypeRoundedRect)
    evalButton:setTitle_forState('Evaluate', UIControlStateNormal)
    evalButton:setFrame(CGRect(200, 142, 100, 32))
    evalButton:addTarget_action_forControlEvents(self, 'eval:', 
                            UIControlEventTouchUpInside)
    self.evalButton = evalButton
    
    self:view():addSubview(self.input)
    self:view():addSubview(self.output)
    self:view():addSubview(self.evalButton)
    
    return self
end

function eval(self, sender)
    self.input:resignFirstResponder()

    local code, errmsg = loadstring(self.input:text())  
    if not code then
        self.output:setText(errmsg)
        return
    end
    
    local success, result = pcall(code)
    print('result is ' .. tostring(result))
    if not success then
        self.output:setText('Error: ' .. tostring(result))
    else
        self.output:setText(tostring(result))
    end 
    
end

</pre>

<p></code></p>

<p>The <strong>waxClass</strong> function essentially defines a new Objective-C class.  In this instance we are defining a class named <strong>RootViewController</strong> which is a sub-class of <strong>UIViewController</strong>.  (<span class="tiny">In Wax, the Objective-C classes have been put into namespaces, hence <strong>UI.ViewController</strong>, rather than <strong>UIViewController</strong></span>).  The Lua representation of instances of this class is a table (<span class="tiny">well, really a <strong>userdata</strong>, but you can think table...</span>), hence items like <strong>self.input</strong> are Lua table fields and <strong>not</strong> Objective-C properties.  To access properties you use setters and getters, e.g. <strong>self.output:setText()</strong>.  If you're like me, this will trip you up until you embarass yourself by asking about it in the <a href="http://groups.google.com/group/iphonewax">mailing list</a>.  Aftewards, you won't mix it up again. (<span class="tiny">Actually, the people on the mailing list are quite nice.</span>)</p>

<p>Wax classes can also implement protocols.  For instance, the Wax sample project, <strong>States</strong>, demonstrates handling a <strong>UITableView</strong> with two custom <strong>UITableViewController</strong> classes.  Each of which implement the <strong>UITableViewDelegate</strong> and <strong>UITableViewDataSource</strong> protocols.  Listing 7 is a minor variation on this theme and presents a class that implements the <strong>UITableViewDataSource</strong> protocol for a multi-section table.</p>

<p><code></p>

<pre>
<div class="panelHeader">Listing 7: SortedDataSource.lua</div>
waxClass{'SortedDataSource', NS.Object, protocols = {'UITableViewDataSource'}, }


function init(self, source_table)
    self.source_table = source_table
    return self
end


function numberOfSectionsInTableView(self, tableView)
    return #self.source_table.headers
end


function tableView_numberOfRowsInSection(self, tableView, section)
    local index = self.source_table.headers[section+1]
    return #self.source_table[index]
end


function tableView_cellForRowAtIndexPath(self, tableView, indexPath)  
    local identifier = 'TableViewCell'
    local cell = tableView:dequeueReusableCellWithIdentifier(identifier)
    cell = cell or UI.TableViewCell:initWithStyle_reuseIdentifier(UITableViewCellStyleDefault, 
                                                      identifier)

    local key = self.source_table.headers[indexPath:section()+1]
    local component = self.source_table[key]
    local player = component[indexPath:row()+1]
    cell:setText(player[1] .. ' ' .. player[2] .. ' ' .. player[3])

    return cell
end

function tableView_titleForHeaderInSection(self, tableView, section)
    return self.source_table.headers[section+1]
end

</pre>

<p></code></p>

<div class="panelFooter">
Note the <em>toll-free</em> conversion of Lua strings to Objective-C strings in functions such as <strong>tableView_titleForHeaderInSection</strong>.
</div>

<p>The uniform naming scheme Wax uses allows you to easily predict the name to use for accessing an Objective-C function from Lua.  Wax comes with a TextMate bundle which makes it very easy to manipulate the Objective-C calls.  For example, you can paste method signatures copied from Xcode's documentation and have them automatically transformed into Lua calls. (<span class="tiny">I'm debating writing Emacs functions to do this or just drink the Kool-ade and start using TextMate.</span>)</p>

<p>Wax has a number of other goodies including extensions for working with SQLite, easy HTTP requests, XML and JSON handling, and working with Core Graphics transforms and gradients.  In addition, recent updates include the ability to write the App delegate in Lua (rather than having a small Objective-C implementation that launches Wax), and the ability to run tests from the command line (in a headless simulator).  Perhaps the most interesting (and powerful) new development is that Wax now provides an interactive console so you can telnet into the simulator (or a device!) and interact with a running application: tweak its parameters or inspect its current state.</p>

<p>Wax is open source and is also licensed with an MIT-style license.  The project is being actively developed and used by a number of developers.</p>

<h3>Summary</h3>

<p>Lua-powered apps <em>are</em> available in the app store.  The Ansca forum for listing Corona apps has over 150 topics (<span class="tiny">I haven't read them all...they may not <strong>all</strong> announce new apps</span>).   Reading through the Wax mailing list, you'll see several developers announcing apps they've written using Wax, and there are likely to be many others who have not posted to the list.  And there are many apps that have taken the DIY approach.</p>

<p>Corona offers a very nice alternative for building iOS apps, but only if you don't need native UI elements.  It's great that they've added native text fields, but the fact that you can't see them in the simulator is a real show-stopper.  But throw its Android capabilities into the mix, and Corona is certainly worth considering.  I like using Corona and I hope/expect to see lots of improvements over time.  Just to weasel out of making an endorsement, I should add that although I have not had any major problems building apps with Corona, the dependency on Ansca and their servers to do builds is something you should seriously think about.</p>

<p>Of course the DIY approach is the complete opposite: you have total control.  But if you need a lot of interaction between your Lua code and your Objective-C code, doing the bindings can be a fair amount of effort.  Johnson's Wax does a fantastic job of bridging Lua and Objective-C.  Wax also plays well with Lua C libraries&mdash;something which Corona doesn't handle.</p>

<p>Although they may not go as far as we'd like, the recent changes to the iOS developer agreement mean that you can now use Lua in iOS development without the stress of worrying that you're setting youself up for app rejection.  I believe the range of techniques available for using Lua in your iOS project means that using Lua will often be a useful tool for successfully completing your iOS project.  Given the active communities surrounding Corona and Wax, as well as the ease of plotting your own course if you want more direct control of your use of Lua, I encourage you to take advantage of this gem of a language.</p>

<h3>References</h3>

<ul>
<li><a href="http://www.lua.org">Lua's Website</a> (<span class="tiny">http://www.lua.org</span>)</li>
<li><a href="http://developer.anscamobile.com">Corona Developer Portal</a> (<span class="tiny">http://developer.anscamobile.com</span>)</li>
<li><a href="http://github.com/probablycorey/wax/">Wax's Repository</a> (<span class="tiny">http://github.com/probablycorey/wax/</span>)</li>
<li><a href="http://probablyinteractive.com/2009/10/19/How%20does%20iPhone%20Wax%20work.html">Wax Syntax Tips</a> (<span class="tiny">http://probablyinteractive.com/2009/10/19/How%20does%20iPhone%20Wax%20work.html</span>)</li>
<li><a href="http://groups.google.com/group/iphonewax">http://groups.google.com/group/iphonewax</a></li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://www.luanova.org/ioswithlua/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Porting Lua to RISC OS</title>
		<link>http://www.luanova.org/porting-lua-to-risc-os/</link>
		<comments>http://www.luanova.org/porting-lua-to-risc-os/#comments</comments>
		<pubDate>Wed, 03 Mar 2010 10:20:37 +0000</pubDate>
		<dc:creator>wra1th</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://luanova.org/?p=53</guid>
		<description><![CDATA[I do not expect many users of Lua will have heard of the operating system known as RISC OS. They are more likely, though, to have heard of the ARM processor architecture. The Wikipedia article on the ARM does not mention that the ARM CPU and RISC OS were in fact originally created for each [...]]]></description>
			<content:encoded><![CDATA[<p>I do not expect many users of Lua will have heard of the
operating system known as RISC OS. They are more likely,
though, to have heard of the ARM processor architecture.
The <a href="http://en.wikipedia.org/wiki/ARM_architecture">Wikipedia article</a> on the ARM
does not mention that the ARM CPU and RISC OS were
in fact originally created for each other by Acorn Computers
Ltd, in Cambridge (UK) in 1988. The article on
<a href="http://en.wikipedia.org/wiki/RISC_OS">RISC OS</a>
gives the full story.</p>

<p>RISC OS offers a very simple interface to user software, via
the ARM&#8217;s SWI (SoftWare Interrupt) instruction. Data is passed
between the user&#8217;s software and the operating system in ARM
registers; that data may consist of pointers to buffers in
memory that hold further data. RISC OS has always contained the
BBC BASIC programming language. This offers the user means
of accessing the operating system using:</p>

<ul>
<li><strong>DIM</strong> &#8212; to reserve a block of memory of a given size and pass
back its address;</li>
<li>Indirection operators ! (for words), ? (for bytes) and $ (for strings);</li>
<li><strong>SYS</strong> &#8212; to call an SWI with given values in the registers on entry
and variables to receive register values on exit;</li>
<li>an inbuilt ARM assembler and a <strong>CALL</strong> command to link to assembled code.</li>
</ul>

<p>With these facilities BBC BASIC is sufficiently powerful to enable
a user to control every aspect of her machine, if she is equipped
with the RISC OS PRMs (Programming Reference Manuals) -
these give details, for each of the modules constituting RISC OS, the
protocols and input/output details for each of the SWIs available,
and of the messages by which the kernel communicates with the modules.</p>

<p>Acorn Computers Ltd started out as manufacturers of laboratory equipment.
Their computers (with the exception of the RISCix work stations)
were always intended as single-user machines over which the user has
total control. Security? An irrelevance in those days. Just as
today&#8217;s motorist almost certainly does not carry a set of tappet-calipers
in his hip-pocket and has never disassembled a carburettor on the
kitchen table, so modern computer-owners are unlikely to want to
know about SWIs or programming. But RISC OS developed in an era
when computers had only just become affordable, and there was a sizable
minority of people who wanted not just to do things with their
computer but to understand how it did them, and how they could control it.
In the end it was the association with education that did for Acorn
Computers Ltd and for RISC OS, after ARM Holdings Ltd had been split off.</p>

<p>Porting Unix or Windows software to RISC OS is fraught with problems.
RISC OS uses cooperative, not preemptive, multitasking. The RISC OS
filing system is fundamentally different, too, and not just
syntactically (a dot is the directory separator symbol). Filer objects
have a filetype attribute that is not part of the object&#8217;s name.</p>

<p>RISC OS filing systems were designed on the supposition that they
were part of a graphical user interface &#8211; the GUI is not just
something tacked on later to a commandline interface. When a user
clicks on the icon of an object in a directory-window the window
manager broadcasts a message to all running tasks:</p>

<pre><code>An object at coordinates (x,y) with pathname obj_name and
filetype obj_type has just been clicked on. Are any of you
guys interested?
</code></pre>

<p>If a task is interested it sends back an acknowledgment (so that
the broadcast is aborted) and has its way with the object. If no
task replies, the taskmanager looks to see if a system command
(a sort of environment macro) <strong>Alias$@RunType_xxx</strong> has been defined,
where xxx are the hexadecimal digits of <strong>obj_type</strong>. If it has,
it is executed with <strong>obj_name</strong> as a commandline argument.
This command generally starts up a task and passes on its argument
to it. There is a special type for command files &#8211; known as
&#8220;obeyfiles&#8221;. An obeyfile always &#8220;knows&#8221; where it is because the
operating system sets the variable <strong>Obey$Dir</strong> to the pathname of the
directory containing it when it is executed. Textfiles constitute
a special type. Holding down the SHIFT key when clicking a file
will always open it in a text editor (even if the user has not
installed a text editor &#8211; there is a basic multifile texteditor
incorporated in the OS, so fundamental is the role of editing
ASCII text &#8211; the same principle applies to graphics, both
bit-mapped and vector). Each type of object is displayed by
its own icon, apart from application directories.</p>

<p>RISC OS has two types of directory. There are ordinary directories,
and there are application directories.</p>

<ul>
<li><p>Click on the icon of an ordinary directory with the left mouse
button and its window will open; with the right mouse button and
the currently open directory window containing it will simultaneously
close &#8211; this makes navigation and the avoidance of window clutter
very simple and direct &#8211; no opening of menus needed.</p></li>
<li><p>Application directories behave differently. Their appearance is
governed by a file inside them called !Sprites &#8211; a bit-mapped graphics
file. Click an application directory and the obeyfile !Run inside it
will be executed. To open an application directory like an
ordinary directory you must depress the SHIFT key when you click.</p></li>
</ul>

<p>The point about application directories is that they can be treated
as a package. There is no such thing as installing or deinstalling
or registering an application. You simply load the application
directory to wherever you want in the filing system and it will
be launched when you click on it. To deinstall, simply delete it.
This independence of position is achieved by a file called !Boot
within an application. It is executed when the window manager is
first made aware of the application&#8217;s existence by the opening of
the window of the directory containing it; this action can be
suppressed by holding down the CTRL key when opening a directory
window. The !Boot file will define system variables and macros
which will inform user software about where the application
is, and anything else they need to know of it. Alternatively the
user can &#8220;filer_boot&#8221; and &#8220;filer_run&#8221; applications from obeyfiles
that are inserted into the boot sequence. This is done by loading the
obeyfiles into appropriate places in the directory !Boot that must
reside at the top level of any RISC OS filing system. Only the !Boot
directory is off-limits for the user&#8217;s personal whims (though even
that is highly customizable). In other words, the filing system is
not a thing of labyrinthine complexity that belongs to the manufacturer
or to tradition. It belongs to the user. This is made possible by the
relocatability of applications.</p>

<p>In the RISC OS GUI, the window on top of the window stack is not
necessarily the window with the input focus. I often find myself
inputting text even though the window containing it is partially
obscured by another window that I need to be reading at the same time,
to compose my input. If I drag a window with the left-hand button
it will come to the top of the window stack, and so be dragged over
any other windows. If I drag with the right-hand button it will retain
its position in the window stack, and so be dragged behind some
windows and over others. The single most exasperating and thoughtless
aspect in Microsoft Windows, to my mind, is the way windows leap to
the top, obscuring what you need to be reading. Real desktops do not
behave in this way, unless somebody has left the door open and there
is a gale blowing through. It is a small detail, but a crucial one.
I have not sufficient experience to know which Linux window managers,
if any, get this right.</p>

<p>Of course, applications in read-only filing systems may need to
rent space for their configuration files on another, writable filing
system. RISC OS is usually held in ROM, so startup and switchoff are
immediate. I can switch on both my computers, one RISC OS, an Iyonix,
and the other Windows XP, an Advent 4211 notebook, at the
same time, and by the time the Advent is ready to use I have
read my emails, replied to them and switched off the Iyonix.</p>

<p>I mention all these details so that readers who are only familiar with
Windows or Unix will understand that there are other operating systems
which present a very different user experience. Many of the worries
and tools to deal with them (defragmenting the hard disc, installing
and removing packages, viruses, rootkits) that the Windows or Unix user
must take into consideration do not exist for the RISC OS user.
The other side of the coin is that RISC OS cannot deliver much that
is now taken for granted &#8211; its user base is too small to catch up.</p>

<p>As BASICs go, BBC BASIC is very good. There is a version for Windows,
I believe, with many improvements. It is almost unfair to call it
BASIC, because the facilities I cited above give it a whiff of
BCPL. Recall that BCPL was developed in Cambridge and was the grand-daddy
of C. BCPL was untyped. Although I am an admirer of BBC BASIC, I am not
blind to its limitations as a programming language. For a long time I
wondered if it were possible to have the best of both worlds:
something that incorporated the advances in programming language design
since 1964, BASIC&#8217;s year of birth, and yet retained the integration
with the operating system and the ease of use which BBC BASIC can
boast. I spent many years on different attempts to realize this dream.
Then I came across Lua.</p>

<p>Lua is portable to any platform with an ANSI C compiler. Lua is a
modern phenomenon, if we take the development of C as the watershed
dividing ancient from modern. Lua is safe, and it can make no
assumptions about its host platform; it certainly cannot peek
or poke memory. RISC OS is unsafe, tied to the ARM architecture, and
uses memory references. It is written mostly in ARM assembler; it
conflates 32-bit integers with addresses, with file-handles,
task-handles, task-manager messages, &#8230; . It is in some ways a
relic of the age before C. To marry Lua with RISC OS, to produce
what I called in an unimaginative moment, RiscLua, these contradictions
had to be squared.</p>

<p>The first problem is that ARM CPUs tend not to have floating-point
hardware. Continual conversion between doubles and 32-bit integers would
be a burden. This problem is solved by #defining LUA_NUMBER to int
and leaving out the math library. I also extended the Lua VM with bit
operations, putting them on an equal footing with the other arithmetic
operations. For those that have to use floating point numbers I
put in a library implementing doubles in the heap.</p>

<p>To integrate Lua with RISC OS, something along the lines of BBC BASIC&#8217;s
DIM,!,?,$ and SYS was needed. To begin with I used userdata for holding
the values of addresses. Then I could reserve blocks of garbage-collectible
memory, and I could check that references were within set bounds. One
downside was that the error-checking slowed things down. Much worse was
the problem of how to convert the data returned in a register from an
SWI call. To what sort of Lua value should it be converted? An integer,
a userdatum holding an address, a file-handle, a string, &#8230;. ? Eventually
I realised that this problem had no universal solution. The only answer
was to play as dirty as BBC BASIC; to abandon userdata and simply conflate
integers with addresses. This made RiscLua less safe, but faster,
and allowed a syntax for indirection that was very close to that
of BBC BASIC &#8211; an advantage for users more accustomed to BBC BASIC
than to anything else. The latest versions of RiscLua have a riscos
library containing <strong>dim</strong>, <strong>sys</strong>, <strong>!</strong>, <strong>?</strong> and <strong>$</strong> (these are allowable in variable
names in RiscLua). Where BBC BASIC might have <strong>x!4</strong> RiscLua can have <strong>![x+4]</strong>.
The symbols <strong>!</strong>,<strong>?</strong> and <strong>$</strong> in the riscos environment are just empty tables
with metamethods: <strong>__index</strong> peeks and <strong>__newindex</strong> pokes. The <strong>sys</strong> function
has one little twist that <strong>SYS</strong> does not have: a nil argument for a register
value means &#8220;use the value returned for that register by the previous
call to sys&#8221;. This is useful because the register usage for SWI calls
in RISC OS has been carefully optimized to minimize shuffling data
between registers, something which can be exploited by this syntax.</p>

<p>There are a few other extensions: backslash is sugar for <strong>function</strong> and &#8216;=>&#8217; is sugar
for <strong>return</strong>.</p>

<p><img src="http://mysite.mweb.co.za/residents/sdonovan/lua/untangle.png"/></p>

<p>This is a
texteditor window displaying a short RiscLua script that uses Roberto&#8217;s
lpeg library to run code enclosed in <strong>&lt;lua&gt; &#8230; &lt;/lua&gt;</strong> tags (with the
remainder of the text taking the value &#8220;text&#8221;). The point of the picture
is the third icon with the green arrow pointing down.
If you shift-drag the icon of a scriptfile onto the green arrow of
a texteditor window, the script is run (with <strong>arg[1]</strong> holding the
name of a pseudofile containing the contents of the window) and the
contents of the window are replaced by the standard output of the
script. This provides the texteditor with a convenient facility -
any scripting language can be used so long as the texteditor has been
configured to understand the right command line syntax for it.
In this case, shift dragging &#8220;untangle&#8221; onto the green arrow of a
window containing &#8220;&lt;lua&gt;print(text:upper())&lt;/lua&gt;hello&#8221; would
convert its contents to &#8220;HELLO&#8221;. Yes, I know it is contrived, but
I hope it shows the general principle.</p>

<p><img src="http://mysite.mweb.co.za/residents/sdonovan/lua/screen.png"/></p>

<p>This shows the final dialogue box when the
following program is run.</p>

<pre><code>-- Fred, tiny wimp program using error dialogue
require "wimp.task"
do
 local dim,! in riscos
 local buffer, wimp_msgs = dim(256), dim(4)
 local title$ = dim "Fred\r"
 local ask = "Count is %d. CANCEL to stop now?"
 local goodbye = "You reached %d. Goodbye."
 local flags = 23  -- for dialogue window
 ![wimp_msgs] = 0  -- no wimp messages
 fred = task.new(title$,wimp_msgs,buffer)   -- create task "fred"
 in fred do
  count = 0                      -- give it a counter
  handler[0] = \ (self)      -- give it a null-event handler
    count = count + 1
    local click = self:report(ask:format(count),flags)
    =&gt; (click ~= 1)          -- OK button to continue
  end -- handler
  preclosedown = \ (self)     -- give it a farewell action
     self:report(goodbye:format(count))
  end -- preclosedown
 end -- do
 fred:init()                   -- register it
 fred:run()                    -- run it
end -- do
</code></pre>

<p>This is a toy example of a RiscLua wimp program. It puts up a
window with two buttons, CANCEL for stopping, OK for carrying
on, and it increments a counter showing the number of times OK is
clicked. I hope the program is not too opaque. Note the use of
Peter Shook&#8217;s patch in <strong>local dim,! in riscos</strong> and the convenient
syntax provided by lexical environments in <strong>in fred do &#8230; end</strong>.
The wimp.task library provides a single function <strong>task.new</strong> which
returns a table, with methods &#8220;init&#8221;, &#8220;run&#8221;, &#8220;preclosedown&#8221;, etc
and a table, &#8220;handler&#8221; of event-handlers, indexed by the event-codes
sent by the taskmanager. Nothing much surprising about this
approach.</p>

<p>I will not pretend that RiscLua can do all the things that BBC BASIC
can do. It has no inbuilt ARM assembler, it does not have
extensive commands for sound or graphics. But there are things that
make RiscLua, for me, much more satisfying to use. It is more
expressive, more modular, more consistent and more concise. It
fulfils my quest, and still offers plenty of opportunities for
further development.</p>

<p>RiscLua and its sources are available at http://lua.riscos.org.uk/ .</p>

<p><a href="http://www.wra1th.plus.com/">Gavin Wraith</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.luanova.org/porting-lua-to-risc-os/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Sputnik: An Introduction I</title>
		<link>http://www.luanova.org/sputnik/</link>
		<comments>http://www.luanova.org/sputnik/#comments</comments>
		<pubDate>Thu, 12 Nov 2009 06:08:07 +0000</pubDate>
		<dc:creator>stevejdonovan</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[Lua]]></category>
		<category><![CDATA[web frameworks]]></category>
		<category><![CDATA[Wiki]]></category>

		<guid isPermaLink="false">http://luanova.org/?p=21</guid>
		<description><![CDATA[Beyond WikiWiki Sputnik is a second-generation extensible wiki engine written in Lua. First generation wikis (like the original WikiWIki) opened our eyes to the possibility of easy collaborative content generation, with automatic revision control. However, anybody who has been involved with a Wiki knows that they are not self-organizing, and so behind any Wiki is [...]]]></description>
			<content:encoded><![CDATA[<h2>Beyond WikiWiki</h2>

<p><a href="http://sputnik.freewisdom.org/">Sputnik</a> is a second-generation extensible wiki engine written in Lua. First generation wikis (like the original <a href="http://c2.com/cgi/wiki">WikiWIki</a>) opened our eyes to the possibility of easy collaborative content generation, with automatic revision control.  However, anybody who has been involved with a Wiki knows that they are not self-organizing, and so behind any Wiki is a core of busy elves correcting and &#8216;refactoring&#8217; content.  Plus, all content is usually in the form of marked-up text, plus uploaded binary data like images.  For instance,  Wiki pages often turn into discussions, but there is usually no way to structure these discussions and no support for creating them.</p>

<p>A second-generation wiki allows for &#8216;virtual&#8217; pages, pages with explicit data fields, structured discussions, complete control of permissions, and namespace management.  The site designer can choose the right balance between freedom and structure that is appropriate for the community and its common purpose.</p>

<h2>Frameworks and Libraries</h2>

<p>There are two basic approaches to software development; either start small, pulling as much functionality in using libraries, or to start with a framework, which does most of the job, and customize it to fit your functionality.  Frameworks have a bad <a href="http://discuss.joelonsoftware.com/default.asp?joel.3.219431.12">reputation</a> because framework developers can get just a little mad in the process of writing them.  But if you want something that can do wiki-like things, manage the content and control the revisions, handle authentication, then it&#8217;s time to get a Wiki framework, because these are not easy applications to get right. As the <a href="http://gitorious.org/sputnik?page=4">Sputnik git page</a> says, &#8220;Sputnik provides a good foundation for anything that&#8217;s kind of like a wiki but not quite.&#8221;</p>

<p>It is true that the first trade-off is the freedom to do things <em>your</em> way, since you must learn how the framework does things, and cooperate with it. In a way, it is like collaboration with another developer on a project which you have just joined.  I am assuming here that you want to get something done, which is not a million miles from a Wiki, and don&#8217;t want to rewrite a whole bunch of wheels, just maybe update the hubcaps.  A better analogy would be this: if you want to equip a kitchen, then using a framework that includes the kitchen sink is appropriate (and not just a joke). Maybe you just want different fittings for your kitchen sink.</p>

<h2>Getting Sputnik</h2>

<p><a href="http://sputnik.freewisdom.org/en/Installation">Installing Sputnik</a> is straightforward, providing you are on a Unix-like platform (like Linux or OS X) although it does also run on Windows.  In this introduction, I assume that it is an Unix environment (although out of convenience, not religious fervour; it is very easy to get a Linux virtual machine and set it up for Sputnik testing.)   After following instructions, you will have a Sputnik install in <strong>~/sputnik</strong>, no special permissions necessary.  Starting the webserver is then just:</p>


<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;">  ~<span style="color: #000000; font-weight: bold;">/</span>sputnik$ .<span style="color: #000000; font-weight: bold;">/</span>bin<span style="color: #000000; font-weight: bold;">/</span>sputnik.lua start-xavante sputnik.ws</pre></div></div>


<p>Sputnik comes with the <a href="http://www.keplerproject.org">Kepler stack</a>, including the Lua webserver Xavante.  This is quite good enough for testing and experimentation.</p>

<p>A useful change is to first edit <strong>sputnik.ws</strong> and set <strong>BASE_URL</strong> to &#8216;/&#8217; and to add <strong>SHOW_STACK_TRACE = true</strong>. Sputnik will then give you Lua error traces when some hitch occurs. Then just open <strong>http://localhost:8080</strong> in your favourite browser and start playing. Create a special user <strong>Admin</strong> to view and edit the configuration nodes.</p>

<p>All Sputnik configuration is via nodes with Lua content. For instance, <strong>sputnik/config</strong>  assigns a set of fields to values. If you are editing this file (as Admin) and make a syntax error (such as <strong>&#8216;Sputnik&#8221;</strong>, mismatching string delimiters) the edit field will turn pink. <strong>sputnik/navigation</strong> controls the navigation bar menu:</p>


<div class="wp_syntax"><div class="code"><pre class="lua" style="font-family:monospace;">  NAVIGATION <span style="color: #66cc66;">=</span> <span style="color: #66cc66;">&#123;</span>
     <span style="color: #66cc66;">&#123;</span>id<span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;index&quot;</span>, title<span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;Start&quot;</span>,
       <span style="color: #66cc66;">&#123;</span>id<span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;snippets&quot;</span>, title<span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;Snippets&quot;</span><span style="color: #66cc66;">&#125;</span>,
       <span style="color: #66cc66;">&#123;</span>id<span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;tags&quot;</span>, title<span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;Tags&quot;</span><span style="color: #66cc66;">&#125;</span>,
       <span style="color: #66cc66;">&#123;</span>id<span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;sputnik&quot;</span>,title<span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;Configure&quot;</span><span style="color: #66cc66;">&#125;</span>,
     <span style="color: #66cc66;">&#125;</span>,
     <span style="color: #66cc66;">&#123;</span>id<span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;News&quot;</span>, title<span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;Timeline&quot;</span>,
       <span style="color: #66cc66;">&#123;</span>id<span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;News&quot;</span><span style="color: #66cc66;">&#125;</span>,
       <span style="color: #66cc66;">&#123;</span>id<span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;Future Plans&quot;</span><span style="color: #66cc66;">&#125;</span>,
       <span style="color: #66cc66;">&#123;</span>id<span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;history&quot;</span>, title<span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;Recent Wiki Edits&quot;</span><span style="color: #66cc66;">&#125;</span>,
       <span style="color: #66cc66;">&#123;</span>id<span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;history/edits_by_recent_users&quot;</span>, title<span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;Edits by Recent Users&quot;</span><span style="color: #66cc66;">&#125;</span>,
       <span style="color: #66cc66;">&#123;</span>id<span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;history.rss&quot;</span>, title<span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;RSS Feed&quot;</span><span style="color: #66cc66;">&#125;</span>,
     <span style="color: #66cc66;">&#125;</span>,
  <span style="color: #66cc66;">&#125;</span></pre></div></div>


<p>Creating a new node is easy; if you ask for a node <strong>test</strong> then it will tell you that this node does not exist, but then will give you several types to choose from.  The &#8216;Basic&#8217; type is a plain Wiki page, and the link provided is something like <strong>http://localhost:8080/?p=test.edit&amp;prototype=</strong>.  In general, a Sputnik request has a <em>node id</em> (&#8216;test&#8217;), an <em>action</em> (&#8216;edit&#8217;) and <em>parameters</em> (&#8216;prototype=&#8217;)</p>

<p>If you click on this link you can edit your new Wiki node.  The markup used is <a href="http://daringfireball.net/projects/markdown/">Markdown</a> which has a clean, readable syntax. In addition, Sputnik supports Wiki links; a link to your new page would be <strong>[[test]]</strong> and a link with some text would be <strong>[[test|My First Page]]</strong> . There is a convenient toolbar providing the most common operations when editing.</p>

<h2>Customizing Sputnik</h2>

<p>A lot can be done with basic Sputnik, just by editing the configuration nodes.  (And, yes, the configuration nodes are Wiki nodes, so you can revert to an earlier version.)  Also, like any modern Web framework, style and functionality are kept separate as CSS and HTML; these <a href="http://sputnik.freewisdom.org/en/Sightings">Sputnik sites</a> show that you can get just about any look and feel.</p>

<p>Since the configuration is done with Lua data, it <em>technically</em> involves programming, but not in any serious sense of the word.  Lua is particularly well-suited to expressing configuration, since it was originally conceived as a data-description language.  This data is converted into Lua table structures using Lua itself, using a <a href="http://lua-users.org/wiki/SandBoxes">sandbox</a> so that it will not execute any dangerous stuff.</p>

<p>The first &#8216;real&#8217; customization we will do is make a whole set of pages default to a particular node type. That is, any node like <strong>pages/GeneralInfo</strong> or <strong>pages/Introduction</strong> will be created as &#8216;Basic&#8217; nodes.</p>

<p>If Sputnik cannot find a node, it will first attempt to find a <em>node default</em> with that name.  The request for &#8216;pages&#8217; results in Sputnik attempting to load a Lua module like so: <strong>require &#8220;sputnik.node_defaults.pages&#8221;</strong>. So we have to create a file <strong>pages.lua</strong> in a directory so that Sputnik can resolve this module.</p>

<p>Sputnik itself is distributed as a <a href="www.luarocks.org">LuaRocks</a> application. In my system, the Sputnik package sits at <strong>~/sputnik/rocks/sputnik/9.03.16-0/lua</strong> &#8211; call this <strong>$SPUTNIK</strong>.  The relevant package directory structure is:</p>

<pre><code>    sputnik
        actions
        hooks
        node_defaults
        ....
</code></pre>

<p>It <em>is</em> possible to customize Sputnik by putting a suitable <strong>pages.lua</strong> in <strong>$SPUTNIK/sputnik/node_defaults</strong>, but that is a road of misery that will end in tears.  However, it&#8217;s useful to acquaint yourself with the contents of this directory because it defines the standard namespaces.</p>

<p>The best quick solution is to add directories to the <strong>LUA_PATH</strong> environment variable before launching Sputnik:</p>


<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;">  ~<span style="color: #000000; font-weight: bold;">/</span>sputnik$ <span style="color: #7a0874; font-weight: bold;">export</span> <span style="color: #007800;">LUA_PATH</span>=<span style="color: #ff0000;">&quot;;;<span style="color: #007800;">$HOME</span>/sputnik/examples/?.lua&quot;</span></pre></div></div>


<p>Then create a directory <strong>~/sputnik/examples/sputnik/node_defaults</strong> containing this file, <strong>pages.lua</strong>:</p>


<div class="wp_syntax"><div class="code"><pre class="lua" style="font-family:monospace;">  module<span style="color: #66cc66;">&#40;</span>..., package.seeall<span style="color: #66cc66;">&#41;</span>
&nbsp;
  NODE <span style="color: #66cc66;">=</span> <span style="color: #66cc66;">&#123;</span>
     title<span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;Pages&quot;</span>,
     content <span style="color: #66cc66;">=</span> <span style="color: #ff0000;">&quot;&quot;</span>,
     child_defaults <span style="color: #66cc66;">=</span> <span style="color: #66cc66;">&#91;</span><span style="color: #66cc66;">&#91;</span>
          any<span style="color: #66cc66;">=</span><span style="color: #ff0000;">'prototype = &quot;&quot;'</span>
      <span style="color: #66cc66;">&#93;</span><span style="color: #66cc66;">&#93;</span>,
  <span style="color: #66cc66;">&#125;</span></pre></div></div>


<p>It is structured as a Lua module, which contains a single exported table, <strong>NODE</strong> .  The definition of the field <strong>child_defaults</strong> may appear a little hairy at first, but it&#8217;s now time to get the three different ways to do string literals in Lua straight.  Whether you use single or double quotes for a string, does not matter; it is a convenience so that you can embed the other kind of quotes: <strong>&#8216;prototype = &#8220;&#8221;&#8216;</strong>. This string is then further embedded in a Lua &#8216;long string&#8217; literal.</p>

<p>After restarting Sputnik, go to <strong>pages</strong>: nothing much to see at this point &#8211; but note that Sputnik can find the node. If you go to <strong>pages/Introduction</strong> you will get another blank page with a title, which you can edit directly as a Wiki page.  The <strong>child_defaults</strong> field tells Sputnik that any &#8216;child&#8217; of <strong>pages</strong> like <strong>pages/Introduction</strong> has a particular prototype value which corresponds to the &#8216;Basic&#8217; node type.</p>

<p>If you enter this text</p>

<pre><code>    Some text for the Introduction node. See [[pages/Basic]]
</code></pre>

<p>and save, the result will have a link to a new page, which you can in turn edit.</p>

<p>To see how Sputnik saves pages by default, look at the <strong>~/sputnik/wiki-data</strong> directory. There will be a subdirectory <strong>pages%2FIntroduction</strong> with files <strong>000001</strong> and <strong>index</strong>. (The subdirectory is just the URL-encoded form of &#8216;pages/Introduction&#8217; ).  <strong>index</strong> will contain something like this:</p>


<div class="wp_syntax"><div class="code"><pre class="lua" style="font-family:monospace;">  add_version<span style="color: #66cc66;">&#123;</span>
  version   <span style="color: #66cc66;">=</span> <span style="color: #ff0000;">&quot;000001&quot;</span>,
  timestamp <span style="color: #66cc66;">=</span> <span style="color: #ff0000;">&quot;2009-11-01 14:33:07&quot;</span>,
  author    <span style="color: #66cc66;">=</span> <span style="color: #ff0000;">&quot;&quot;</span>,
  comment   <span style="color: #66cc66;">=</span> <span style="color: #ff0000;">&quot;&quot;</span>,
   <span style="color: #66cc66;">&#91;</span><span style="color: #ff0000;">&quot;minor&quot;</span><span style="color: #66cc66;">&#93;</span> <span style="color: #66cc66;">=</span> <span style="color: #ff0000;">&quot;&quot;</span>,
   <span style="color: #66cc66;">&#91;</span><span style="color: #ff0000;">&quot;ip&quot;</span><span style="color: #66cc66;">&#93;</span> <span style="color: #66cc66;">=</span> <span style="color: #ff0000;">&quot;127.0.0.1&quot;</span>,
  <span style="color: #66cc66;">&#125;</span></pre></div></div>


<p>And <strong>000001</strong> contains the node text:</p>


<div class="wp_syntax"><div class="code"><pre class="lua" style="font-family:monospace;">  title          <span style="color: #66cc66;">=</span> <span style="color: #ff0000;">&quot;pages/Introduction&quot;</span>
  category       <span style="color: #66cc66;">=</span> <span style="color: #ff0000;">&quot;&quot;</span>
  content        <span style="color: #66cc66;">=</span> <span style="color: #66cc66;">&#91;</span><span style="color: #66cc66;">=</span><span style="color: #66cc66;">&#91;</span>Some text <span style="color: #b1b100;">for</span> the Introduction node. See <span style="color: #66cc66;">&#91;</span><span style="color: #66cc66;">&#91;</span>pages<span style="color: #66cc66;">/</span>Basic<span style="color: #66cc66;">&#93;</span><span style="color: #66cc66;">&#93;</span>
&nbsp;
  <span style="color: #66cc66;">&#93;</span><span style="color: #66cc66;">=</span><span style="color: #66cc66;">&#93;</span>
  breadcrumb     <span style="color: #66cc66;">=</span> <span style="color: #ff0000;">&quot;&quot;</span></pre></div></div>


<p>As the node is edited, each revision is saved in a similar format, <strong>000002</strong>, etc.  In this way, edit history is managed in a simple way, easily readable by humans, as opposed to being stored in some relational database. However, using a database for storage is also supported by the Sputnik content manager, which is called <a href="http://sputnik.freewisdom.org/en/Saci">Saci</a>.</p>

<h2>Custom Output</h2>

<p>Before actually starting with code, it&#8217;s useful to have a handy shortcut to the Lua executable used by Sputnik.  I suggest creating a little executable script like this on your path:</p>


<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;">  $<span style="color: #000000; font-weight: bold;">&gt;</span> <span style="color: #c20cb9; font-weight: bold;">cat</span> ~<span style="color: #000000; font-weight: bold;">/</span>bin<span style="color: #000000; font-weight: bold;">/</span>slua
  ~<span style="color: #000000; font-weight: bold;">/</span>sputnik<span style="color: #000000; font-weight: bold;">/</span>bin<span style="color: #000000; font-weight: bold;">/</span>lua -lluarocks.require <span style="color: #007800;">$*</span></pre></div></div>


<p>Before we actually get round to generating dynamic content, here is a quick review of <a href="http://cosmo.luaforge.net/">Cosmo</a>,  which is a powerful template engine used by Sputnik.</p>


<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;">  ~$ slua</pre></div></div>



<div class="wp_syntax"><div class="code"><pre class="lua" style="font-family:monospace;">  Lua 5.1.4  Copyright <span style="color: #66cc66;">&#40;</span>C<span style="color: #66cc66;">&#41;</span> <span style="color: #cc66cc;">1994</span>-<span style="color: #cc66cc;">2008</span> Lua.org, PUC-Rio
  <span style="color: #66cc66;">&gt;</span> <span style="color: #b1b100;">require</span> <span style="color: #ff0000;">&quot;cosmo&quot;</span>
  <span style="color: #66cc66;">&gt;</span> template <span style="color: #66cc66;">=</span> <span style="color: #ff0000;">&quot;$rank of $suit&quot;</span>
  <span style="color: #66cc66;">&gt;</span> values <span style="color: #66cc66;">=</span> <span style="color: #66cc66;">&#123;</span>rank<span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;Ace&quot;</span>,suit<span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;Spades&quot;</span><span style="color: #66cc66;">&#125;</span>
  <span style="color: #66cc66;">&gt;</span> <span style="color: #66cc66;">=</span> cosmo.fill<span style="color: #66cc66;">&#40;</span>template,values<span style="color: #66cc66;">&#41;</span>
  Ace of Spades</pre></div></div>


<p>That&#8217;s useful, although only a little more friendly than Lua&#8217;s <strong>string.format</strong> function.  However, Cosmo goes way beyond simple <a href="http://lua-users.org/wiki/StringInterpolation">string interpolation</a>.</p>


<div class="wp_syntax"><div class="code"><pre class="lua" style="font-family:monospace;">  <span style="color: #808080; font-style: italic;">-- testcosmo.lua</span>
  <span style="color: #b1b100;">require</span> <span style="color: #ff0000;">&quot;cosmo&quot;</span>
  template <span style="color: #66cc66;">=</span> <span style="color: #66cc66;">&#91;</span><span style="color: #66cc66;">==</span><span style="color: #66cc66;">&#91;</span>
  <span style="color: #66cc66;">&lt;</span>h1<span style="color: #66cc66;">&gt;</span>$list_name<span style="color: #66cc66;">&lt;/</span>h1<span style="color: #66cc66;">&gt;</span>
  <span style="color: #66cc66;">&lt;</span>ul<span style="color: #66cc66;">&gt;</span>
   $do_items<span style="color: #66cc66;">&#91;</span><span style="color: #66cc66;">&#91;</span><span style="color: #66cc66;">&lt;</span>li<span style="color: #66cc66;">&gt;</span>$item<span style="color: #66cc66;">&lt;/</span>li<span style="color: #66cc66;">&gt;</span><span style="color: #66cc66;">&#93;</span><span style="color: #66cc66;">&#93;</span>
  <span style="color: #66cc66;">&lt;/</span>ul<span style="color: #66cc66;">&gt;</span>
  <span style="color: #66cc66;">&#93;</span><span style="color: #66cc66;">==</span><span style="color: #66cc66;">&#93;</span>
&nbsp;
  <span style="color: #b1b100;">print</span><span style="color: #66cc66;">&#40;</span>cosmo.fill<span style="color: #66cc66;">&#40;</span>template, <span style="color: #66cc66;">&#123;</span>
      list_name <span style="color: #66cc66;">=</span> <span style="color: #ff0000;">&quot;My List&quot;</span>,
      do_items  <span style="color: #66cc66;">=</span> <span style="color: #b1b100;">function</span><span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span>
          <span style="color: #b1b100;">for</span> i<span style="color: #66cc66;">=</span><span style="color: #cc66cc;">1</span>,<span style="color: #cc66cc;">5</span> <span style="color: #b1b100;">do</span>
             cosmo.yield <span style="color: #66cc66;">&#123;</span> item <span style="color: #66cc66;">=</span> i <span style="color: #66cc66;">&#125;</span>
          <span style="color: #b1b100;">end</span>
      <span style="color: #b1b100;">end</span>
  <span style="color: #66cc66;">&#125;</span>
  <span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span></pre></div></div>



<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;">  ~$ slua testcosmo.lua</pre></div></div>



<div class="wp_syntax"><div class="code"><pre class="html" style="font-family:monospace;">  &lt;h1&gt;My List&lt;/h1&gt;
  &lt;ul&gt;
   &lt;li&gt;1&lt;/li&gt;&lt;li&gt;2&lt;/li&gt;&lt;li&gt;3&lt;/li&gt;&lt;li&gt;4&lt;/li&gt;&lt;li&gt;5&lt;/li&gt;
  &lt;/ul&gt;</pre></div></div>


<p><em>Subtemplates</em> are a powerful feature which makes generating HTML straightforward.</p>

<p>Now, we create a node which creates custom HTML output.  First, put <strong>Memory.lua</strong> in your  <strong>node_defaults</strong> directory:</p>


<div class="wp_syntax"><div class="code"><pre class="lua" style="font-family:monospace;">  module<span style="color: #66cc66;">&#40;</span>..., package.seeall<span style="color: #66cc66;">&#41;</span>
&nbsp;
  NODE <span style="color: #66cc66;">=</span> <span style="color: #66cc66;">&#123;</span>
      title <span style="color: #66cc66;">=</span> <span style="color: #ff0000;">&quot;Lua Memory&quot;</span>,
      content <span style="color: #66cc66;">=</span> <span style="color: #ff0000;">&quot;&quot;</span>,
      actions <span style="color: #66cc66;">=</span> <span style="color: #66cc66;">&#91;</span><span style="color: #66cc66;">&#91;</span>
          show<span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;Memory.show_memory&quot;</span>
      <span style="color: #66cc66;">&#93;</span><span style="color: #66cc66;">&#93;</span>,
  <span style="color: #66cc66;">&#125;</span></pre></div></div>


<p>Create a directory <strong>actions</strong> (that is, <strong>~/sputnik/examples/sputnik/actions</strong>) and put this <strong>Memory.lua</strong> in it:</p>


<div class="wp_syntax"><div class="code"><pre class="lua" style="font-family:monospace;">  module<span style="color: #66cc66;">&#40;</span>..., package.seeall<span style="color: #66cc66;">&#41;</span>
&nbsp;
  actions <span style="color: #66cc66;">=</span> <span style="color: #66cc66;">&#123;</span><span style="color: #66cc66;">&#125;</span>
&nbsp;
  <span style="color: #b1b100;">local</span> template <span style="color: #66cc66;">=</span> <span style="color: #66cc66;">&#91;</span><span style="color: #66cc66;">=</span><span style="color: #66cc66;">&#91;</span>
     <span style="color: #66cc66;">&lt;</span>h2<span style="color: #66cc66;">&gt;</span>Memory used by Lua is $mem kb<span style="color: #66cc66;">&lt;/</span>h2<span style="color: #66cc66;">&gt;</span>
  <span style="color: #66cc66;">&#93;</span><span style="color: #66cc66;">=</span><span style="color: #66cc66;">&#93;</span>
&nbsp;
  <span style="color: #b1b100;">function</span> actions.show_memory <span style="color: #66cc66;">&#40;</span>node, request, sputnik<span style="color: #66cc66;">&#41;</span>
      node.inner_html <span style="color: #66cc66;">=</span> cosmo.f<span style="color: #66cc66;">&#40;</span>template<span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#123;</span>
          mem <span style="color: #66cc66;">=</span> <span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">'%6.0f'</span><span style="color: #66cc66;">&#41;</span>:<span style="color: #b1b100;">format</span><span style="color: #66cc66;">&#40;</span><span style="color: #b1b100;">collectgarbage</span><span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">'count'</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span>,
      <span style="color: #66cc66;">&#125;</span>
      <span style="color: #b1b100;">return</span> node.wrappers.default<span style="color: #66cc66;">&#40;</span>node, request, sputnik<span style="color: #66cc66;">&#41;</span>
  <span style="color: #b1b100;">end</span></pre></div></div>


<p>The convention is that any <em>action</em> functions are in the <strong>actions</strong> directory; these functions must be in a nested <strong>actions</strong> table.  Visiting the node <strong>Memory</strong> will show the memory managed by Lua (as returned by the <strong>collectgarbage(&#8216;count&#8217;)</strong> call).</p>

<p>The node&#8217;s <strong>inner_html</strong> is the source for the node&#8217;s display area, that is, not including the menu and all other frame decorations.  <strong>node.wrappers.default</strong> is the actual function which generates the source for the <em>whole</em> page.</p>

<p>So, we now have a customized node with generated output.  Please note that it does not appear in <strong>wiki-data</strong>; the node is fully &#8216;virtual&#8217; and has no storage associated with it.</p>

<p>To take this example further, let us wrap the output of the <strong>ps</strong> command:</p>


<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;">  ~$ <span style="color: #c20cb9; font-weight: bold;">ps</span> aux <span style="color: #660033;">--cols</span> <span style="color: #000000;">256</span>
  USER       PID <span style="color: #000000; font-weight: bold;">%</span>CPU <span style="color: #000000; font-weight: bold;">%</span>MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
  ...
  sdonovan  <span style="color: #000000;">2867</span>  <span style="color: #000000;">0.8</span>  <span style="color: #000000;">2.3</span>  <span style="color: #000000;">41972</span> <span style="color: #000000;">15932</span> pts<span style="color: #000000; font-weight: bold;">/</span><span style="color: #000000;">1</span>    Sl   <span style="color: #000000;">10</span>:<span style="color: #000000;">47</span>   <span style="color: #000000;">3</span>:<span style="color: #000000;">57</span> <span style="color: #000000; font-weight: bold;">/</span>home<span style="color: #000000; font-weight: bold;">/</span>sdonovan<span style="color: #000000; font-weight: bold;">/</span>lua<span style="color: #000000; font-weight: bold;">/</span>scite<span style="color: #000000; font-weight: bold;">/</span>SciTE
  sdonovan  <span style="color: #000000;">2902</span>  <span style="color: #000000;">1.2</span> <span style="color: #000000;">12.4</span> <span style="color: #000000;">179152</span> <span style="color: #000000;">83160</span> ?        Sl   <span style="color: #000000;">10</span>:<span style="color: #000000;">48</span>   <span style="color: #000000;">5</span>:<span style="color: #000000;">19</span> <span style="color: #000000; font-weight: bold;">/</span>usr<span style="color: #000000; font-weight: bold;">/</span>lib<span style="color: #000000; font-weight: bold;">/</span>iceweasel<span style="color: #000000; font-weight: bold;">/</span>firefox-bin <span style="color: #660033;">-a</span> firefox
  sdonovan  <span style="color: #000000;">5993</span>  <span style="color: #000000;">0.0</span>  <span style="color: #000000;">0.4</span>   <span style="color: #000000;">5360</span>  <span style="color: #000000;">2844</span> pts<span style="color: #000000; font-weight: bold;">/</span><span style="color: #000000;">2</span>    Ss   <span style="color: #000000;">16</span>:<span style="color: #000000;">13</span>   <span style="color: #000000;">0</span>:00 <span style="color: #c20cb9; font-weight: bold;">bash</span>
  sdonovan  <span style="color: #000000;">7118</span>  <span style="color: #000000;">0.0</span>  <span style="color: #000000;">0.3</span>   <span style="color: #000000;">5360</span>  <span style="color: #000000;">2024</span> pts<span style="color: #000000; font-weight: bold;">/</span><span style="color: #000000;">0</span>    S+   <span style="color: #000000;">18</span>:03   <span style="color: #000000;">0</span>:00 <span style="color: #c20cb9; font-weight: bold;">bash</span>
  sdonovan  <span style="color: #000000;">7119</span>  <span style="color: #000000;">0.4</span>  <span style="color: #000000;">1.1</span>   <span style="color: #000000;">8384</span>  <span style="color: #000000;">7380</span> pts<span style="color: #000000; font-weight: bold;">/</span><span style="color: #000000;">0</span>    S+   <span style="color: #000000;">18</span>:03   <span style="color: #000000;">0</span>:01 <span style="color: #000000; font-weight: bold;">/</span>home<span style="color: #000000; font-weight: bold;">/</span>sdonovan<span style="color: #000000; font-weight: bold;">/</span>sputnik<span style="color: #000000; font-weight: bold;">/</span>bin<span style="color: #000000; font-weight: bold;">/</span>lua -lluarocks.require <span style="color: #000000; font-weight: bold;">/</span>home<span style="color: #000000; font-weight: bold;">/</span>sdonovan<span style="color: #000000; font-weight: bold;">/</span>sputnik<span style="color: #000000; font-weight: bold;">/</span>rocks<span style="color: #000000; font-weight: bold;">/</span>sputnik<span style="color: #000000; font-weight: bold;">/</span>9.03.16-<span style="color: #000000;">0</span><span style="color: #000000; font-weight: bold;">/</span>bin<span style="color: #000000; font-weight: bold;">/</span>sputnik.lua start-xavante sputnik.ws</pre></div></div>


<p>(The <strong>&#8211;cols</strong> flag is necessary to prevent <strong>ps</strong> from thoughtfully truncating the line length to fit the terminal screen)</p>

<p>Chopping lines up is easy using <strong>sputnik.util.split</strong> &#8211; notice that it returns multiple values, not a table:</p>


<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;">  ~$ slua</pre></div></div>



<div class="wp_syntax"><div class="code"><pre class="lua" style="font-family:monospace;">  Lua 5.1.4  Copyright <span style="color: #66cc66;">&#40;</span>C<span style="color: #66cc66;">&#41;</span> <span style="color: #cc66cc;">1994</span>-<span style="color: #cc66cc;">2008</span> Lua.org, PUC-Rio
  <span style="color: #66cc66;">&gt;</span> util <span style="color: #66cc66;">=</span> <span style="color: #b1b100;">require</span> <span style="color: #ff0000;">'sputnik.util'</span>
  <span style="color: #66cc66;">&gt;</span> <span style="color: #66cc66;">=</span> util.split<span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">'one two three'</span>,<span style="color: #ff0000;">'%s+'</span><span style="color: #66cc66;">&#41;</span>
  one     two     three</pre></div></div>


<p>With this, a more exciting version of <strong>actions/Memory.lua</strong> can be written:</p>


<div class="wp_syntax"><div class="code"><pre class="lua" style="font-family:monospace;">  module<span style="color: #66cc66;">&#40;</span>..., package.seeall<span style="color: #66cc66;">&#41;</span>
  <span style="color: #b1b100;">local</span> util <span style="color: #66cc66;">=</span> <span style="color: #b1b100;">require</span> <span style="color: #ff0000;">'sputnik.util'</span>
  actions <span style="color: #66cc66;">=</span> <span style="color: #66cc66;">&#123;</span><span style="color: #66cc66;">&#125;</span>
&nbsp;
  <span style="color: #b1b100;">local</span> template <span style="color: #66cc66;">=</span> <span style="color: #66cc66;">&#91;</span><span style="color: #66cc66;">=</span><span style="color: #66cc66;">&#91;</span>
     <span style="color: #66cc66;">&lt;</span>h2<span style="color: #66cc66;">&gt;</span>Memory used by Lua is $mem kb<span style="color: #66cc66;">&lt;/</span>h2<span style="color: #66cc66;">&gt;</span>
     <span style="color: #66cc66;">&lt;</span>h2<span style="color: #66cc66;">&gt;</span>Processes<span style="color: #66cc66;">&lt;/</span>h2<span style="color: #66cc66;">&gt;</span>
     <span style="color: #66cc66;">&lt;</span>table<span style="color: #66cc66;">&gt;</span>
     <span style="color: #66cc66;">&lt;</span>tr<span style="color: #66cc66;">&gt;</span>
      <span style="color: #66cc66;">&lt;</span>th<span style="color: #66cc66;">&gt;</span>User<span style="color: #66cc66;">&lt;/</span>th<span style="color: #66cc66;">&gt;&lt;</span>th<span style="color: #66cc66;">&gt;</span>CPU<span style="color: #66cc66;">&lt;/</span>th<span style="color: #66cc66;">&gt;&lt;</span>th<span style="color: #66cc66;">&gt;</span>Mem<span style="color: #66cc66;">&lt;/</span>th<span style="color: #66cc66;">&gt;&lt;</span>th<span style="color: #66cc66;">&gt;</span>Command<span style="color: #66cc66;">&lt;/</span>th<span style="color: #66cc66;">&gt;</span>
     <span style="color: #66cc66;">&lt;/</span>tr<span style="color: #66cc66;">&gt;</span>
     $do_processes<span style="color: #66cc66;">&#91;</span><span style="color: #66cc66;">&#91;</span>
          <span style="color: #66cc66;">&lt;</span>tr<span style="color: #66cc66;">&gt;</span>
          <span style="color: #66cc66;">&lt;</span>td<span style="color: #66cc66;">&gt;</span>$user<span style="color: #66cc66;">&lt;/</span>td<span style="color: #66cc66;">&gt;&lt;</span>td<span style="color: #66cc66;">&gt;</span>$cpu<span style="color: #66cc66;">&lt;/</span>td<span style="color: #66cc66;">&gt;&lt;</span>td<span style="color: #66cc66;">&gt;</span>$mem<span style="color: #66cc66;">&lt;/</span>td<span style="color: #66cc66;">&gt;&lt;</span>td<span style="color: #66cc66;">&gt;</span>$cmd<span style="color: #66cc66;">&lt;/</span>td<span style="color: #66cc66;">&gt;</span>
          <span style="color: #66cc66;">&lt;/</span>tr<span style="color: #66cc66;">&gt;</span>
     <span style="color: #66cc66;">&#93;</span><span style="color: #66cc66;">&#93;</span>
     <span style="color: #66cc66;">&lt;/</span>table<span style="color: #66cc66;">&gt;</span>
  <span style="color: #66cc66;">&#93;</span><span style="color: #66cc66;">=</span><span style="color: #66cc66;">&#93;</span>
&nbsp;
  <span style="color: #b1b100;">function</span> actions.show_memory <span style="color: #66cc66;">&#40;</span>node, request, sputnik<span style="color: #66cc66;">&#41;</span>
      node.inner_html <span style="color: #66cc66;">=</span> cosmo.f<span style="color: #66cc66;">&#40;</span>template<span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#123;</span>
          mem <span style="color: #66cc66;">=</span> <span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">'%6.0f'</span><span style="color: #66cc66;">&#41;</span>:<span style="color: #b1b100;">format</span><span style="color: #66cc66;">&#40;</span><span style="color: #b1b100;">collectgarbage</span><span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">'count'</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span>,
          do_processes <span style="color: #66cc66;">=</span> <span style="color: #b1b100;">function</span><span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span>
              <span style="color: #b1b100;">local</span> user <span style="color: #66cc66;">=</span> <span style="color: #b1b100;">os.getenv</span> <span style="color: #ff0000;">'USER'</span>
              <span style="color: #808080; font-style: italic;">-- this works on LInux, may need some mods for BSD/OS X.</span>
              <span style="color: #b1b100;">local</span> f <span style="color: #66cc66;">=</span> <span style="color: #b1b100;">io</span>.popen<span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">'ps --cols 256 aux'</span>,<span style="color: #ff0000;">'r'</span><span style="color: #66cc66;">&#41;</span>
              f:<span style="color: #b1b100;">read</span><span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span> <span style="color: #808080; font-style: italic;">-- not interested in column headers</span>
              <span style="color: #b1b100;">for</span> line <span style="color: #b1b100;">in</span> f:lines<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span> <span style="color: #b1b100;">do</span>
                  <span style="color: #b1b100;">local</span> fields <span style="color: #66cc66;">=</span> <span style="color: #66cc66;">&#123;</span>util.split<span style="color: #66cc66;">&#40;</span>line,<span style="color: #ff0000;">'%s+'</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#125;</span>
                  <span style="color: #b1b100;">if</span> fields<span style="color: #66cc66;">&#91;</span><span style="color: #cc66cc;">1</span><span style="color: #66cc66;">&#93;</span> <span style="color: #66cc66;">==</span> user <span style="color: #b1b100;">then</span>
                      cosmo.yield <span style="color: #66cc66;">&#123;</span>
                          user <span style="color: #66cc66;">=</span> fields<span style="color: #66cc66;">&#91;</span><span style="color: #cc66cc;">1</span><span style="color: #66cc66;">&#93;</span>, cpu <span style="color: #66cc66;">=</span> fields<span style="color: #66cc66;">&#91;</span><span style="color: #cc66cc;">3</span><span style="color: #66cc66;">&#93;</span>, mem <span style="color: #66cc66;">=</span> fields<span style="color: #66cc66;">&#91;</span><span style="color: #cc66cc;">4</span><span style="color: #66cc66;">&#93;</span>, cmd <span style="color: #66cc66;">=</span> fields<span style="color: #66cc66;">&#91;</span><span style="color: #cc66cc;">11</span><span style="color: #66cc66;">&#93;</span>,
                      <span style="color: #66cc66;">&#125;</span>
                  <span style="color: #b1b100;">end</span>
              <span style="color: #b1b100;">end</span>
          <span style="color: #b1b100;">end</span>
      <span style="color: #66cc66;">&#125;</span>
      <span style="color: #b1b100;">return</span> node.wrappers.default<span style="color: #66cc66;">&#40;</span>node, request, sputnik<span style="color: #66cc66;">&#41;</span>
  <span style="color: #b1b100;">end</span></pre></div></div>


<p>Now the node <strong>Memory</strong> is actually useful for the administrator of the website &#8211; but probably not a good idea to expose to the world!</p>

<h2>Permissions</h2>

<p>The node <strong>Memory</strong> should be restricted; only the Admin user should be able to view it. Also, it does not make sense to edit it, even as an administrator.  <strong>actions/Memory.lua</strong> needs to have a <em>permissions</em> field:</p>


<div class="wp_syntax"><div class="code"><pre class="lua" style="font-family:monospace;">  module<span style="color: #66cc66;">&#40;</span>..., package.seeall<span style="color: #66cc66;">&#41;</span>
&nbsp;
  NODE <span style="color: #66cc66;">=</span> <span style="color: #66cc66;">&#123;</span>
      title <span style="color: #66cc66;">=</span> <span style="color: #ff0000;">&quot;Lua Memory&quot;</span>,
      content <span style="color: #66cc66;">=</span> <span style="color: #ff0000;">&quot;&quot;</span>,
      actions <span style="color: #66cc66;">=</span> <span style="color: #66cc66;">&#91;</span><span style="color: #66cc66;">&#91;</span>
          show<span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;Memory.show_memory&quot;</span>
      <span style="color: #66cc66;">&#93;</span><span style="color: #66cc66;">&#93;</span>,
      permissions <span style="color: #66cc66;">=</span> <span style="color: #66cc66;">&#91;</span><span style="color: #66cc66;">&#91;</span>
          deny<span style="color: #66cc66;">&#40;</span>all_users,all_actions<span style="color: #66cc66;">&#41;</span>
          allow<span style="color: #66cc66;">&#40;</span>Admin,show<span style="color: #66cc66;">&#41;</span>
      <span style="color: #66cc66;">&#93;</span><span style="color: #66cc66;">&#93;</span>
  <span style="color: #66cc66;">&#125;</span></pre></div></div>


<p>We start by prohibiting <em>everything</em>, and then only let Admin view the page.  Notice that all of the usual little action icons on the right-hand side have disappeared.</p>

<p>To get back to the <strong>pages</strong> example; we may insist that only authenticated users can edit the pages.  There are two kinds of solution to this, make it site-wide policy or only for children of <strong>pages</strong>.  The first solution requires no code; as Admin, go to the <strong>@Root</strong> node, and choose the &#8216;configure&#8217; action (which is usually the little gear icon next to &#8216;edit&#8217; on the actions toolbar)  Now open the &#8216;Advanced Fields&#8217; section, and you can then edit the &#8216;Permissions&#8217; field.  By default, Sputnik comments out this line:</p>


<div class="wp_syntax"><div class="code"><pre class="lua" style="font-family:monospace;">  <span style="color: #808080; font-style: italic;">-- deny(Anonymous, edit_and_save)</span></pre></div></div>


<p>Remove the comment and save.  Now anonymous users have lost their power to make edits anywhere on the site.</p>

<p>We&#8217;ve already seen with <strong>Memory</strong> how to enforce permissions for a single node. But how to do this for a group of nodes?  Sputnik <em>prototypes</em> provide the solution.  A prototype acts as the &#8216;type&#8217; of a node. When a node is retrieved from storage, Sputnik copies default values from its prototype node.  The basic prototype of all nodes is <strong>@Root</strong>.</p>

<p>Previously, the <strong>pages</strong> node has insisted that its children have an &#8216;empty&#8217; prototype.  The idea is to create an explicit prototype that will apply to the children, which will be called <strong>@pages</strong>. (By convention, all prototypes begin with &#8216;@&#8217;)</p>

<p><strong>node_defaults/pages.lua</strong> becomes:</p>


<div class="wp_syntax"><div class="code"><pre class="lua" style="font-family:monospace;">  module<span style="color: #66cc66;">&#40;</span>..., package.seeall<span style="color: #66cc66;">&#41;</span>
&nbsp;
  NODE <span style="color: #66cc66;">=</span> <span style="color: #66cc66;">&#123;</span>
     title<span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;Pages&quot;</span>,
     content <span style="color: #66cc66;">=</span> <span style="color: #ff0000;">&quot;&quot;</span>,
     child_defaults <span style="color: #66cc66;">=</span> <span style="color: #66cc66;">&#91;</span><span style="color: #66cc66;">&#91;</span>
          any<span style="color: #66cc66;">=</span><span style="color: #ff0000;">'prototype = &quot;@pages&quot;'</span>
      <span style="color: #66cc66;">&#93;</span><span style="color: #66cc66;">&#93;</span>
  <span style="color: #66cc66;">&#125;</span></pre></div></div>


<p>and create a new file <strong>node_defaults/@pages.lua</strong> to define the <strong>@pages</strong> prototype:</p>


<div class="wp_syntax"><div class="code"><pre class="lua" style="font-family:monospace;">  module<span style="color: #66cc66;">&#40;</span>..., package.seeall<span style="color: #66cc66;">&#41;</span>
&nbsp;
  NODE <span style="color: #66cc66;">=</span> <span style="color: #66cc66;">&#123;</span>
     content <span style="color: #66cc66;">=</span> <span style="color: #ff0000;">&quot;&quot;</span>,
     permissions<span style="color: #66cc66;">=</span><span style="color: #66cc66;">&#91;</span><span style="color: #66cc66;">&#91;</span>
          deny<span style="color: #66cc66;">&#40;</span>Anonymous,edit_and_save<span style="color: #66cc66;">&#41;</span>
     <span style="color: #66cc66;">&#93;</span><span style="color: #66cc66;">&#93;</span>
  <span style="color: #66cc66;">&#125;</span></pre></div></div>


<p>It does very little, just explicitly overrides the permissions.</p>

<h2>Hooks</h2>

<p>Continuing with the <strong>pages</strong> example, it would be useful if we could track the author of a particular page, defined simply as the user that first edited it.  Also, we would like to track the creation date.  So the prototype for all pages must include these new_fields and define a <em>save hook</em> which will be called when the node is saved:</p>


<div class="wp_syntax"><div class="code"><pre class="lua" style="font-family:monospace;">  <span style="color: #808080; font-style: italic;">-- node_defaults/@pages.lua</span>
  module<span style="color: #66cc66;">&#40;</span>..., package.seeall<span style="color: #66cc66;">&#41;</span>
&nbsp;
  NODE <span style="color: #66cc66;">=</span> <span style="color: #66cc66;">&#123;</span>
     content <span style="color: #66cc66;">=</span> <span style="color: #ff0000;">&quot;&quot;</span>,
     permissions<span style="color: #66cc66;">=</span><span style="color: #66cc66;">&#91;</span><span style="color: #66cc66;">&#91;</span>
          deny<span style="color: #66cc66;">&#40;</span>Anonymous,edit_and_save<span style="color: #66cc66;">&#41;</span>
     <span style="color: #66cc66;">&#93;</span><span style="color: #66cc66;">&#93;</span>,
     fields <span style="color: #66cc66;">=</span> <span style="color: #66cc66;">&#91;</span><span style="color: #66cc66;">&#91;</span>
        author <span style="color: #66cc66;">=</span> <span style="color: #66cc66;">&#123;</span><span style="color: #cc66cc;">1.1</span><span style="color: #66cc66;">&#125;</span>
        creation_time <span style="color: #66cc66;">=</span> <span style="color: #66cc66;">&#123;</span><span style="color: #cc66cc;">1.2</span><span style="color: #66cc66;">&#125;</span>
    <span style="color: #66cc66;">&#93;</span><span style="color: #66cc66;">&#93;</span>,
     save_hook <span style="color: #66cc66;">=</span> <span style="color: #ff0000;">&quot;pages.save_page&quot;</span>
  <span style="color: #66cc66;">&#125;</span></pre></div></div>


<p>Create a directory &#8216;sputnik/hooks&#8217; as before, and put <strong>pages.lua</strong> in it:</p>


<div class="wp_syntax"><div class="code"><pre class="lua" style="font-family:monospace;">  <span style="color: #808080; font-style: italic;">-- hooks/pages.lua</span>
  module<span style="color: #66cc66;">&#40;</span>..., package.seeall<span style="color: #66cc66;">&#41;</span>
&nbsp;
  <span style="color: #b1b100;">function</span> save_page<span style="color: #66cc66;">&#40;</span>node, request, sputnik<span style="color: #66cc66;">&#41;</span>
      <span style="color: #b1b100;">if</span> <span style="color: #b1b100;">not</span> node.creation_time <span style="color: #b1b100;">then</span>
         <span style="color: #b1b100;">local</span> params <span style="color: #66cc66;">=</span> <span style="color: #66cc66;">&#123;</span><span style="color: #66cc66;">&#125;</span>
         params.author <span style="color: #66cc66;">=</span> request.user
         params.creation_time <span style="color: #66cc66;">=</span> <span style="color: #b1b100;">tostring</span><span style="color: #66cc66;">&#40;</span><span style="color: #b1b100;">os.time</span><span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span>
         node <span style="color: #66cc66;">=</span> sputnik:update_node_with_params<span style="color: #66cc66;">&#40;</span>node, params<span style="color: #66cc66;">&#41;</span>
      <span style="color: #b1b100;">end</span>
      <span style="color: #b1b100;">return</span> node
  <span style="color: #b1b100;">end</span></pre></div></div>


<p>When a node&#8217;s <strong>save_hook</strong> field is set to <strong>MODULE.FUNCTION</strong> , then Sputnik will try to load <strong>sputnik.hooks.MODULE</strong> and use the <strong>FUNCTION</strong> defined by that module.  In this case, the save hook is only interested in a new node, where the author and creation time fields have not been assigned yet.  It uses the <strong>update_node_with_params</strong> method to write the new key/value pairs into the node.</p>

<p>Now, after saving <strong>pages/fred</strong>, the revision in the <strong>pages%2Ffred</strong> directory will look like this:</p>


<div class="wp_syntax"><div class="code"><pre class="lua" style="font-family:monospace;">  title          <span style="color: #66cc66;">=</span> <span style="color: #ff0000;">&quot;pages/fred&quot;</span>
  category       <span style="color: #66cc66;">=</span> <span style="color: #ff0000;">&quot;&quot;</span>
  prototype      <span style="color: #66cc66;">=</span> <span style="color: #ff0000;">&quot;@pages&quot;</span>
  content        <span style="color: #66cc66;">=</span> <span style="color: #66cc66;">&#91;</span><span style="color: #66cc66;">&#91;</span>Some content<span style="color: #66cc66;">!</span>
  <span style="color: #66cc66;">&#93;</span><span style="color: #66cc66;">&#93;</span>
  breadcrumb     <span style="color: #66cc66;">=</span> <span style="color: #ff0000;">&quot;&quot;</span>
  author         <span style="color: #66cc66;">=</span> <span style="color: #ff0000;">&quot;sdonovan&quot;</span>
  creation_time  <span style="color: #66cc66;">=</span> <span style="color: #ff0000;">&quot;1257157113&quot;</span></pre></div></div>


<p>This shows that we are saving the new information, although these fields are not displayed yet.</p>

<h2>Wrapping up</h2>

<p>Currently, <strong>pages</strong> is blank, and like <strong>Memory</strong>  we can output something sensible by defining a &#8216;show&#8217; action that will display a table of the existing pages.</p>

<p>If you are accustomed to regular Web frameworks, you are probably tempted to maintain and use a relational database at this point.  Sputnik does not exclude that, you are free to store things as you wish, but it&#8217;s best to work with the underlying &#8216;document-oriented&#8217; database machinery provided by Saci.</p>

<p>The existing pages can be found by querying Saci, which provides a <strong>get_nodes_by_prefix</strong> method. The prefix identifies the <em>namespace</em> for the nodes, which is <strong>pages</strong> in this case. This method returns a table where the keys are the <em>identifiers</em> (e.g. <strong>pages/fred</strong>) and the values are the node objects. Here is code that creates a list of nodes from this table, and sorts it by creation time.</p>


<div class="wp_syntax"><div class="code"><pre class="lua" style="font-family:monospace;">  <span style="color: #b1b100;">local</span> <span style="color: #b1b100;">function</span> pages_in_order <span style="color: #66cc66;">&#40;</span>sputnik<span style="color: #66cc66;">&#41;</span>
      <span style="color: #b1b100;">local</span> pages <span style="color: #66cc66;">=</span> sputnik.saci:get_nodes_by_prefix <span style="color: #ff0000;">'pages'</span>
      <span style="color: #b1b100;">local</span> res <span style="color: #66cc66;">=</span> <span style="color: #66cc66;">&#123;</span><span style="color: #66cc66;">&#125;</span>
      <span style="color: #b1b100;">for</span> id,page <span style="color: #b1b100;">in</span> <span style="color: #b1b100;">pairs</span><span style="color: #66cc66;">&#40;</span>pages<span style="color: #66cc66;">&#41;</span> <span style="color: #b1b100;">do</span>
          res<span style="color: #66cc66;">&#91;</span>#res+<span style="color: #cc66cc;">1</span><span style="color: #66cc66;">&#93;</span> <span style="color: #66cc66;">=</span> page
      <span style="color: #b1b100;">end</span>
      <span style="color: #b1b100;">table.sort</span><span style="color: #66cc66;">&#40;</span>res,<span style="color: #b1b100;">function</span><span style="color: #66cc66;">&#40;</span>p1,p2<span style="color: #66cc66;">&#41;</span> <span style="color: #b1b100;">return</span> p1.creation_time <span style="color: #66cc66;">&lt;</span> p2.creation_time <span style="color: #b1b100;">end</span><span style="color: #66cc66;">&#41;</span>
      <span style="color: #b1b100;">return</span> res
  <span style="color: #b1b100;">end</span></pre></div></div>


<p><strong>node_defaults/pages.lua</strong> gets an actions field, just as with <strong>node_defaults/Memory.lua</strong>:</p>


<div class="wp_syntax"><div class="code"><pre class="lua" style="font-family:monospace;">  actions<span style="color: #66cc66;">=</span><span style="color: #66cc66;">&#91;</span><span style="color: #66cc66;">&#91;</span>
      show<span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;pages.show_pages&quot;</span>
  <span style="color: #66cc66;">&#93;</span><span style="color: #66cc66;">&#93;</span></pre></div></div>


<p>And <strong>actions/pages.lua</strong> will be:</p>


<div class="wp_syntax"><div class="code"><pre class="lua" style="font-family:monospace;">  module <span style="color: #66cc66;">&#40;</span>...,package.seeall<span style="color: #66cc66;">&#41;</span>
&nbsp;
  actions <span style="color: #66cc66;">=</span> <span style="color: #66cc66;">&#123;</span><span style="color: #66cc66;">&#125;</span>
&nbsp;
  <span style="color: #b1b100;">local</span> template <span style="color: #66cc66;">=</span> <span style="color: #66cc66;">&#91;</span><span style="color: #66cc66;">=</span><span style="color: #66cc66;">&#91;</span>
     <span style="color: #66cc66;">&lt;</span>h2<span style="color: #66cc66;">&gt;</span>Existing Pages<span style="color: #66cc66;">&lt;/</span>h2<span style="color: #66cc66;">&gt;</span>
     <span style="color: #66cc66;">&lt;</span>table<span style="color: #66cc66;">&gt;</span>
     <span style="color: #66cc66;">&lt;</span>tr<span style="color: #66cc66;">&gt;</span>
      <span style="color: #66cc66;">&lt;</span>th<span style="color: #66cc66;">&gt;</span>Page<span style="color: #66cc66;">&lt;/</span>th<span style="color: #66cc66;">&gt;&lt;</span>th<span style="color: #66cc66;">&gt;</span>Author<span style="color: #66cc66;">&lt;/</span>th<span style="color: #66cc66;">&gt;&lt;</span>th<span style="color: #66cc66;">&gt;</span>Created<span style="color: #66cc66;">&lt;/</span>th<span style="color: #66cc66;">&gt;</span>
     <span style="color: #66cc66;">&lt;/</span>tr<span style="color: #66cc66;">&gt;</span>
     $do_pages<span style="color: #66cc66;">&#91;</span><span style="color: #66cc66;">&#91;</span>
          <span style="color: #66cc66;">&lt;</span>tr<span style="color: #66cc66;">&gt;</span>
          <span style="color: #66cc66;">&lt;</span>td<span style="color: #66cc66;">&gt;&lt;</span>a href<span style="color: #66cc66;">=</span><span style="color: #ff0000;">&quot;?p=$id&quot;</span><span style="color: #66cc66;">&gt;</span>$name<span style="color: #66cc66;">&lt;/</span>a<span style="color: #66cc66;">&gt;&lt;/</span>td<span style="color: #66cc66;">&gt;&lt;</span>td<span style="color: #66cc66;">&gt;</span>$author<span style="color: #66cc66;">&lt;/</span>td<span style="color: #66cc66;">&gt;&lt;</span>td<span style="color: #66cc66;">&gt;</span>$created<span style="color: #66cc66;">&lt;/</span>td<span style="color: #66cc66;">&gt;</span>
          <span style="color: #66cc66;">&lt;/</span>tr<span style="color: #66cc66;">&gt;</span>
     <span style="color: #66cc66;">&#93;</span><span style="color: #66cc66;">&#93;</span>
     <span style="color: #66cc66;">&lt;/</span>table<span style="color: #66cc66;">&gt;</span>
  <span style="color: #66cc66;">&#93;</span><span style="color: #66cc66;">=</span><span style="color: #66cc66;">&#93;</span>
&nbsp;
  <span style="color: #b1b100;">local</span> <span style="color: #b1b100;">function</span> pages_in_order<span style="color: #66cc66;">&#40;</span>sputnik<span style="color: #66cc66;">&#41;</span>
  ....
  <span style="color: #b1b100;">end</span>
&nbsp;
  <span style="color: #b1b100;">function</span> actions.show_pages<span style="color: #66cc66;">&#40;</span>node, request, sputnik<span style="color: #66cc66;">&#41;</span>
      node.inner_html <span style="color: #66cc66;">=</span> cosmo.f<span style="color: #66cc66;">&#40;</span>template<span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#123;</span>
          do_pages <span style="color: #66cc66;">=</span> <span style="color: #b1b100;">function</span><span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span>
              <span style="color: #b1b100;">local</span> pages <span style="color: #66cc66;">=</span> pages_in_order<span style="color: #66cc66;">&#40;</span>sputnik<span style="color: #66cc66;">&#41;</span>
              <span style="color: #b1b100;">for</span> _,page <span style="color: #b1b100;">in</span> <span style="color: #b1b100;">ipairs</span><span style="color: #66cc66;">&#40;</span>pages<span style="color: #66cc66;">&#41;</span> <span style="color: #b1b100;">do</span>
                  cosmo.yield<span style="color: #66cc66;">&#123;</span>
                      id <span style="color: #66cc66;">=</span> page.id,
                      name <span style="color: #66cc66;">=</span> page.id:<span style="color: #b1b100;">gsub</span><span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">'pages/'</span>,<span style="color: #ff0000;">''</span><span style="color: #66cc66;">&#41;</span>,
                      author <span style="color: #66cc66;">=</span> page.author,
                      created <span style="color: #66cc66;">=</span> sputnik:format_time<span style="color: #66cc66;">&#40;</span>page.creation_time,<span style="color: #ff0000;">&quot;%d %b %Y&quot;</span><span style="color: #66cc66;">&#41;</span>
                  <span style="color: #66cc66;">&#125;</span>
              <span style="color: #b1b100;">end</span>
          <span style="color: #b1b100;">end</span>
      <span style="color: #66cc66;">&#125;</span>
      <span style="color: #b1b100;">return</span> node.wrappers.default<span style="color: #66cc66;">&#40;</span>node, request, sputnik<span style="color: #66cc66;">&#41;</span>
  <span style="color: #b1b100;">end</span></pre></div></div>


<h2>Beyond the Basics</h2>

<p>If you are curious about how Sputnik creates the whole page, note that <strong>node.wrappers.default</strong>
is usually implemented by the <strong>wrappers.default</strong> function in <strong>sputnik/actions/wiki.lua</strong> which does a Cosmo expansion of the <strong>node.html_main</strong> template (see <strong>NODE.html_main</strong> in <strong>sputnik/node_defaults/@Root.lua</strong>)</p>

<p>If you don&#8217;t like a visual feature, then it is often easy to remove it.  For instance, editing <strong>@Root</strong> as Admin (using <strong>@Root.configure</strong> as before) you can open up the &#8216;HTML Fields&#8217; and modify the templates directly. Removing the menu bar is as easy as clearing out the text in the &#8216;Menu&#8217; field.</p>

<p>For a good overview of Sputnik permissions, see this <a href="http://sputnik.freewisdom.org/en/list/Way_to_lockdown_editing_features_">list question</a> and its reply.</p>

<p>The next part of this tutorial will deal with further customizations, like internationalization, providing a custom form for editing a node&#8217;s fields, and using the built-in <strong>@Collection</strong> prototype to simplify the common pattern of groups of content nodes.  And Sputnik&#8217;s ability to create custom actions will change the way you look at file extensions forever.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.luanova.org/sputnik/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
	</channel>
</rss>

