<?xml version="1.0" encoding="UTF-8"?>
<!--Generated by Squarespace Site Server v5.11.5 (http://www.squarespace.com/) on Fri, 30 Jul 2010 15:48:34 GMT--><rss xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd" xmlns:dc="http://purl.org/dc/elements/1.1/" version="2.0"><channel><title>Me Dev, You Jane</title><link>http://medevyoujane.com/blog/</link><description></description><lastBuildDate>Mon, 15 Feb 2010 13:01:48 +0000</lastBuildDate><copyright></copyright><language>en-US</language><generator>Squarespace Site Server v5.11.5 (http://www.squarespace.com/)</generator><item><title>Erlang Quick Tip: The user_default module</title><category>Erlang</category><dc:creator>Jón Grétar Borgþórsson</dc:creator><pubDate>Sun, 03 Jan 2010 15:09:38 +0000</pubDate><link>http://medevyoujane.com/blog/2010/1/3/erlang-quick-tip-the-user_default-module.html</link><guid isPermaLink="false">257763:2635231:6209375</guid><description><![CDATA[<p>If you are anything like me you spend a lot of your time in the erlang shell debuging and testing your code. And some commands are used more than others but they may be a bit on the long side and you may make regular errors while typing it. One of these wonderful functions is <code>make:all([load]).</code> that will compile using your Emakefile and then magically reload the newly compiled modules into the running shell. What I reglarly do is to type <em>load</em> instead of <em>[load]</em>. </p>

<p>Enter the <em>user_default</em> module. Any function defined in the user defined <em>user_default</em> module or in the Erlang defined <em>shell_default</em> module will be allowed to run without typing in the module name. One of these functions that you may use often is the <code>c(module\_name).</code> function. First start by creating a directory for your utility modules. I like having it in the <em>~/.ebin/</em> diretory. Now add that direcory to the code path by opening or creating the file <em>~/.erlang</em> and inserting this line:</p>

<pre><code>code:add_pathz("/Users/username/.ebin").
</code></pre>

<p>Create your <em>user_default.erl</em> file and but in the following:</p>

<pre><code>-module (user_default).
-export ([sync/0]).

%% Compiles all files in Emakefile and load into current shell.
sync() -&gt;
  make:all([load]).
</code></pre>

<p>Then compile it with <code>erlc user_default.erl</code> and start an Erlang shell. Now inside a project you can run <code>sync().</code> and it will recompile and load you project.</p>

<p>For those interested I will put up my <em>~/.ebin</em> code up at <a href="http://github.com/JonGretar/erlang_user_utilities">github.com/JonGretar/erlang_user_utilities</a>. Please fork and make your own changes and share with the world.</p>
]]></description><wfw:commentRss>http://medevyoujane.com/blog/rss-comments-entry-6209375.xml</wfw:commentRss></item><item><title>Edging your way towards Ruby 1.9.1 and Rails 3.0pre</title><category>Ruby</category><dc:creator>Jón Grétar Borgþórsson</dc:creator><pubDate>Thu, 17 Dec 2009 21:11:05 +0000</pubDate><link>http://medevyoujane.com/blog/2009/12/17/edging-your-way-towards-ruby-191-and-rails-30pre.html</link><guid isPermaLink="false">257763:2635231:6085711</guid><description><![CDATA[<p>The Rails 3 release is expected any day now but many of you, like me, may not have the patience to wait until release to start fiddling with it. So why not take the time and do some Ruby 1.9 testing at the same time. We have all been delaying the 1.9 switch but the fact is that 1.9.1 is the current stable version of Ruby and we should all really be using it for <em>new projects</em>. Sure there may be some gems we may need that are not 1.9 compatible yet but that is just a perfect opportunity for you to learn the new features of the current Ruby release. I can think of no better Ruby 1.9 learning tool for you than updating that gem, that you need, to a 1.9 compatible status. Also we should always remember when we build our applications that we probably saved ourselves days and even weeks by using work that others have done and given away. The least we can do is to spend an hour fixing that bug.</p>

<p><strong>EDIT:</strong> <em>Some people prefer installing using RVM(Ruby Version Manager). I personally am a source guy but feel free to check the comments below for the RVM install info and skipping to the Rails part.</em></p>

<p><strong>EDIT 2:</strong> <em>Rails is now available as a pre-release gem and the rails installation step here is out of date.</em></p>

<p>There are many tutorials out there on how to install Ruby 1.9 but most of them involve installing the binaries with a "*19" suffix leaving you with 2 names for ruby. One called ruby and other called ruby19. I really dislike this methods as I see multiple ways how that can be annoying. I prefer my Ruby being called ruby so I usually install it in some directory that I can easily switch to by adding or removing a directory from the path.</p>

<p>So lets start by creating that installation directory. I also give my user the ownership of it. That may not be a smart idea for a production machine but as this is your local dev machine it's just handy that you never have to think about privileges when installing gems and so on:</p>

<pre><code>sudo mkdir -p /opt/ruby19
sudo chown $USER /opt/ruby19
</code></pre>

<p>Now lets get the latest Ruby source and install to our new Ruby directory:</p>

<pre><code>cd ~/Temp  
curl ftp://ftp.ruby-lang.org/pub/ruby/1.9/ruby-1.9.1-p376.tar.gz | tar zx
cd ruby-1.9.1-p376
./configure --prefix=/opt/ruby19 --enable-shared
make &amp;&amp; make install
</code></pre>

<p>All done. Now you should have ruby 1.9 set up and all you need to do is add it's bin directory to the path with the command <code>export PATH=/opt/ruby19/bin:$PATH</code> and you should be set to go. For convenience I usually open up <em>~/.bash_profile</em> and insert to it the line:</p>

<pre><code>alias ruby19ify="export PATH=/opt/ruby19/bin:$PATH"
</code></pre>

<p>That way whenever I open up a new terminal it will be using the default Ruby 1.8 version. But to switch to 1.9 i just run the command <code>ruby19ify</code> and my terminal session will use our custom ruby version and the 1.9 gem scripts. If you wish to fully switch to the new version simply add this to the path permanently. Check your Ruby install by running the command <code>ruby -v</code> and you should be greeted with:</p>

<pre><code>ruby 1.9.1p376 (2009-12-07 revision 26041) [i386-darwin10.2.0]
</code></pre>

<p>Now before we install Rails we should update RubyGems to the latest version with the command:</p>

<pre><code>gem update --system
</code></pre>

<p>While we used the Temp directory for the Ruby source files we really want to put the Rails source to your code directory as you are going to want to update this on a regular basis. The installation is dead simple:</p>

<pre><code>cd *SomePlaceYouStoreCode*
git clone git://github.com/rails/rails.git
cd rails
git submodule init
git submodule update
rake install
</code></pre>

<p>Now every time you wish to update Rails(do it at least weekly) you simply cd to the source directory and perform the following commands:</p>

<p>git pull
  git submodule update
  rake install</p>

<p>And you should be set. Check that you have Rails 3 with the command <code>rails -v</code>, install your gems such as sqlite3, and start hacking away at rails. If you either successfully or unsuccessfully install a gem help other by reporting it at http://isitruby19.com/ as needed. If it fails then check the source code and see if you can't assist the community by fixing it. Do a few of those and, who knows, you might end up as a Ruby superstar like <a href="http://github.com/ryanb/">Ryan Bates</a> or <a href="http://geoffreygrosenbach.com/">Geoffrey Grosenbach</a>.</p>

<p>Remember that there are some big changes in Rails 3 that you need to be aware of. You may for example be surprised if you open up <em>config/environment.rb</em> as it is all but empty now. Gems are now set up using the <em>Gemfile</em> file in the root and there is a new file called <em>config/application.rb</em> for your configuration that are not environment bound. For a great collection of Rails 3 info visit the <a href="http://railsnotes.com/rails-3/">RailsNotes</a> site.</p>

<p>And remember. Fork and Patch.</p>
]]></description><wfw:commentRss>http://medevyoujane.com/blog/rss-comments-entry-6085711.xml</wfw:commentRss></item><item><title>Power CouchDB - Basic HTTP Handlers</title><category>CouchDBX</category><category>Erlang</category><dc:creator>Jón Grétar Borgþórsson</dc:creator><pubDate>Fri, 10 Apr 2009 17:22:28 +0000</pubDate><link>http://medevyoujane.com/blog/2009/4/10/power-couchdb-basic-http-handlers.html</link><guid isPermaLink="false">257763:2635231:3612074</guid><description><![CDATA[<p>You may know CouchDB's mostly as a kick ass document store but you can use it's base for many great things. Thanks to the fact that CouchDB is an amazingly well written and very modular piece of technology. It is easy to extend it and add your custom code to all areas of CouchDB. If you want to use your own language for views you can add it without even touching the CouchDB code. Write your own authentication handlers connected to LDAP or even CouchDB itself in just a few lines of erlang.</p>

<p>One thing that may interest you are the httpd_global_handlers. They are the little handlers for example behind the /_all_dbs and /_utils paths and more. You can also use them to easily make our own resources and in fact it is by far the simplest way to create a REST resource I know of. So if you are working with json resources it me be worth simply adding a handler in CouchDB rather than making it seperatly using webmachine or other technology. In fact here is an example of how making a resource for the computers environment variables. (Hey it could happen you needed that.)</p>

<script src="http://gist.github.com/105785.js">//Sample Code Inserted By Javascript</script>

<p>Well thats easy. We import a few helper functions from couch_httpd that will handle returning JSON data back to the client. We make a method that takes a #httpd record as a variable and if its path has one part we return all environment variables but if it has 2 parts we return the value of that specific one. In fact in creating this resource there are only a handful of lines that I would even call "my code".</p>

<p>Compile this and put in CouchDB's code path. To use it we just open up local.ini and define our new handler and map to '/_env'.</p>

<pre><code>[httpd_global_handlers]
_env = {my_httpd_handlers, handle_env_req}
</code></pre>

<p>Now just restart and go to <em>http://127.0.0.1/_env</em> and <em>http://127.0.0.1/_env/HOME</em> to see the result. For more complete examples of using handlers just go the the couchdb source and view the couch_httpd_misc_handlers.erl file.</p>]]></description><wfw:commentRss>http://medevyoujane.com/blog/rss-comments-entry-3612074.xml</wfw:commentRss></item><item><title>The State of Me - Jan 2009</title><category>Arduino</category><category>CouchDBX</category><category>ErlangXCode</category><category>Git</category><category>Nitrogen</category><category>Personal</category><dc:creator>Jón Grétar Borgþórsson</dc:creator><pubDate>Thu, 15 Jan 2009 15:15:02 +0000</pubDate><link>http://medevyoujane.com/blog/2009/1/15/the-state-of-me-jan-2009.html</link><guid isPermaLink="false">257763:2635231:2849039</guid><description><![CDATA[<p>Well. Just a little status update on me and my various projects for 2008.  </p>

<p>2008 was a good year for me and my education as a developer. I got to know <a href="http://erlang.org">Erlang</a> at the middle of the year and by the end of the year I was almost exclusively coding in Erlang. I have also started learning some standard C for playing with <a href="http://arduino.cc">Arduino</a>. I also learned the basics of Emacs and so far I like it though I still use <a href="http://macromates.com">Textmate</a> for many things. And I started using <a href="http://git-scm.com">Git</a> and <a href="http://github.com">Github</a>. I was to begin with skeptical about it and the fact that Linus Thorvalds was <a href="http://www.youtube.com/watch?v=4XpnKHJAok8">a bit of a dick</a> when talking about it didn't help. But once I tried it I found it to be very productive and combined with GitHub it's quickly revolutionizing open source development in the world.</p>

<p>I became a contributor to the <a href="http://nitrogenproject.com/">Nitrogen Web Framework</a>. I have many ideas for it and hope to add many things to it. Nitrogen is at a very exciting stage as we are finding the path we want to take and can make many choices at this stage.</p>

<p>Is started playing with a little project I call <a href="http://github.com/JonGretar/couchmail-poc">CouchMail</a>. It's basically a quick ugly hack to research gluing together a mail server with <a href="http://nitrogenproject.com">Nitrogen</a>, <a href="http://cappuccino.org/">Cappuccino</a>, Mochiweb and finally <a href="http://couchdb.org/">CouchDB</a> for data storage. If this works out ok I may consider writing a real application from scratch from what I learn.</p>

<p>I forked <a href="https://github.com/JonGretar/couchdbx">CouchDB<em>X</em></a> and completely rewrote the UI. I like my changes as they remove CouchDB from the desktop and you don't have to know about it until it is needed. I have most of the new code needed for CouchDB 0.9.0 ready so it should come out as soon as the new CouchDB is released.</p>

<p><a href="http://github.com/JonGretar/erlangxcode">ErlangXcode</a> is an attempt to make Apple's <a href="http://apple.com/xcode">Xcode 3 IDE</a> be a kick ass Erlang IDE. A lot of the basic syntax is there with some, like records, still to be implemented. Also a basic build system in place and compilation errors show up in-code. I had to take a bit a break from it before going nuts though. Xcode's plugin system is 100% undocumented and there is no way do debug anything. What you have to do is to make small changes, compile and then reboot Xcode. There are no errors. The code just works, quietly doesn't work or it crashes Xcode. Hopefully I will quickly have energy to deal with it again soon. I did however start a little wiki project at <a href="http://code.google.com/p/xcode-plugin/">google code</a> documenting the xcode plugin system.</p>

<p>Finally there is a little project I started in the middle of the year called AstAssist. It's in a bit of a pause at the moment but basically it is an Erlang based system for <a href="http://asterisk.org/">Asterisk</a> management. It's a complete solution for configuration, monitoring, event parsing, fastagi and so on. I have some of the basics done and hope to continue later in the year.</p>

<p>Well.. That's the bullet points. Hope some or all of these will become something amazing in 2009.</p>
]]></description><wfw:commentRss>http://medevyoujane.com/blog/rss-comments-entry-2849039.xml</wfw:commentRss></item><item><title>Erlang Web Development Frameworks</title><category>Erlang</category><category>Nitrogen</category><dc:creator>Jón Grétar Borgþórsson</dc:creator><pubDate>Thu, 18 Dec 2008 16:11:13 +0000</pubDate><link>http://medevyoujane.com/blog/2008/12/18/erlang-web-development-frameworks.html</link><guid isPermaLink="false">257763:2635231:2716362</guid><description><![CDATA[<h3>Web Frameworks.</h3>

<p>I'm going to mention the two of the most interesting web frameworks out there. They choose a very different path and I would call both of them production ready. As they are both projects in active development you might have a problem with a new release breaking a few things.</p>

<h4><a href="http://github.com/rklophaus/nitrogen/wikis">Nitrogen</a></h4>

<p>Nitrogen is the new kid on the scene but has quickly become my favorite framework. Unlike most frameworks it's  <a href="http://yuiblog.com/blog/2007/01/17/event-plan/">event driven</a>. I enjoy it even more than Rails at the moment. It's dead simple to get started in and very powerful. It's in very active development and new and cool features are added almost weekly. The last new feature added was the simplest but one of the most powerful Comet implementation out there. </p>

<p>ONe of it's drawbacks is that there is no routing system in it. Paths are defined by the module names. So <strong>web_index.erl</strong> becomes <em>/web/index</em> or <em>/web</em> and <strong>web_blog_comment.erl</strong> becomes <em>/web/blog/comment</em>. Some might find this a bit limiting.</p>

<p>There are many cool features planned and one of the most interesting is implementing Erlangs power to be a distributed web frameworks. Thus solving many of the problems of scalability that many other web frameworks have</p>

<p><strong>Pros:</strong></p>

<ul>
<li>Dead simple.</li>
<li>Nice bindings system.</li>
<li>Kick ass Comet support.</li>
<li>Interesting future ideas.</li>
</ul>

<p><strong>Cons:</strong></p>

<ul>
<li>No routing at the moment.</li>
<li>A little too simple on the template side.</li>
<li>Really young so no real documentation yet.</li>
</ul>

<h4><a href="http://www.erlang-web.org/">Erlang Web</a></h4>

<p>I have not much experience with Erlang Web but many seem to have started using it. It's and MVC framework built on OTP principles and uses many standard Erlang practices. It's template system on first view reminds me a bit of good old WebObjects. Currently it supports INETS and Yaws but not MochiWeb at the moment.</p>

<p><strong>Pros:</strong></p>

<ul>
<li>Very Flexible.</li>
<li>Powerful template language.</li>
<li>OTP Principles.</li>
</ul>

<p><strong>Cons:</strong></p>

<ul>
<li>Could be simpler.</li>
<li>Needs way better documentation.</li>
</ul>

<h3>Template Languages</h3>

<p>Sometimes you may just want something simpler. Just a little template engine on a custom built web server to show some dynamic data. Or for use in your own web framework. Here are 2 notable template engines.</p>

<h4><a href="http://github.com/kevsmith/herml">HERML</a></h4>

<p>HERML is an erlang implementation of the <a href="http://haml.hamptoncatlin.com/">HAML</a> markup language. It's quick and simple but remember that this skips HTML altogether so it might not be for everyone.</p>

<h4><a href="http://code.google.com/p/erlydtl/">ErlyDTL</a></h4>

<p>ErlyDTL is an erlang implementation of the Django Template Language. I personally found DTL to be Django's most anoying feature but as many people like it it's best to mention it.</p>
]]></description><wfw:commentRss>http://medevyoujane.com/blog/rss-comments-entry-2716362.xml</wfw:commentRss></item><item><title>5 Minute Blog Using Nitrogen and CouchDB</title><category>Erlang</category><category>Nitrogen</category><dc:creator>Jón Grétar Borgþórsson</dc:creator><pubDate>Fri, 12 Dec 2008 03:16:58 +0000</pubDate><link>http://medevyoujane.com/blog/2008/12/12/5-minute-blog-using-nitrogen-and-couchdb.html</link><guid isPermaLink="false">257763:2635231:2685564</guid><description><![CDATA[<h3>Introduction</h3>

<p><em>NOTE: This tutorial is very very old and uses early versions of both Nitrogen and CouchDB and many things here may not work as advertised.</em></p>

<p>Hey. Today I'm going to show you how to create a really, really simple blog in a few minutes using the <a href="http://nitrogenproject.com/">Nitrogen Web Framework</a> and the <a href="http://couchdb.org">CouchDB</a> document system. I presume you have basic erlang skills but this should be simple for anyone. I also presume you have already seen the <a href="nitrogen-erlang.tumblr.com/">Nitrogen Screencasts</a> and are familiar with the basic behavior of Nitrogen.</p>

<h3>Ingredients</h3>

<p>Here is what yo will need: </p>

<ul>
<li><a href="http://nitrogenproject.com/">Nitrogen</a></li>
<li><a href="http://couchdb.org">CouchDB</a> (or CouchDBX)</li>
<li><a href="http://ecouch.googlecode.com/">Ecouch</a></li>
<li><a href="http://medevyoujane.com/storage/tutorial-data/erlang/5MinBlog-Extra.zip">Extra Files</a></li>
</ul>

<p>I assume that Ecouch and Nitrogen are set up in the library path (see <a href="http://wiki.github.com/rklophaus/nitrogen/installing-nitrogen">here</a> for installation info). If you need any further help on this see <a href="http://medevyoujane.com/blog/2008/8/6/installing-erlang-and-a-few-libraries-on-mac-os-x.html">this post</a></p>

<p>If you are using Mac OS 10.5 I recommend you use my implementation of <a href="http://medevyoujane.com/blog/2008/11/23/my-couchdbx-version.html">CouchDBX</a> to get you started quickly.</p>

<p>First we create a new project in a location of your choosing with the command </p>

<pre><code>nitrogen create myblog
</code></pre>

<p>In there you will see a basic project to get started with. Now unzip the <a href="http://medevyoujane.com/storage/tutorial-data/erlang/5MinBlog-Extra.zip">Extra Files</a> and copy the files to your project. You will see a basic template I have set up for you at <strong>wwwroot/template.html</strong>. You will also see the module <strong>json_obj</strong> wich I savagely stole from the <a href="http://beebole.com/blog/2008/10/20/tutorial-web-application-erlang/">StickyNotes</a> tutorial. It's basically a module that will assist you dealing with  JSON data  in Erlang. As JSON's data types are incompatible with Erlang it's best to grab help wherever you can.</p>

<p>First we will need to start ecouch. Open up <strong>src/myblog_app.erl</strong> and modify start() to start up ecouch before nitrogen</p>

<pre><code>start(_, _) -&gt; 
  application:start(ecouch),
  nitrogen:start().
</code></pre>

<p>To start the development server open up a terminal to the project root, type in "<code>./start.sh</code>" and visit the website <a href="http://localhost:8000">http://localhost:8000</a>. You should see a nice website with the body "web_index body.". Whenever you change the code in the project you will have to recompile with the command "<code>sync:go().</code>".</p>

<h3>CouchDB</h3>

<p>First thing we want to do is create the database and our view. Open up CouchDB at <a href="http://127.0.0.1:5984/_utils/">http://127.0.0.1:5984/_utils/</a>, create a new database and name it "myblog". Next we are going to need a convenient view for Nitrogen. We are going to create a really simple view that returns a simple array with first the title and then the body. This makes it easy for us when we need to map the data later in Nitrogen as you will see later. We are also going to use the field timestamp as a key so the data is in time order.</p>

<p>To do that we select "Custom Query" under "Select view". Expand the "View Code" flap and replace the map function with the following.</p>

<pre><code>function(doc) {
  emit(doc.timestamp, [doc.title, doc.body]);
}
</code></pre>

<p>Select "Save As" and save as the design document: "nitrogen" and view name: "flat".</p>

<h3>The Model</h3>

<p>We could call the data from the pages themselves but I prefer to create a little model class to seperate the logic. Create the file <em>blog_posts.erl</em> inside src and export <em>get_posts/0</em> and <em>add_post/1</em>. First create the get_post/1.</p>

<pre><code>get_posts() -&gt;
    {ok, Return} = ecouch:view_access("myblog", "nitrogen", "flat"),
    RawRows = json_obj:get_value("rows", Return),
    F = fun(X) -&gt;
            json_obj:get_value("value", X)
    end,
    Rows = lists:map(F, RawRows),
    lists:reverse(Rows).
</code></pre>

<p>First of all we made a call to CouchDB using ecouch requesting the <em>nitrogen/flat</em> view for the <em>myblog</em> database. Now as Erlang has incompatible types to JSON there is a lot of ugly extra data in the raw return which looks like this</p>

<pre><code>{obj,[{"total_rows",2},
          {"offset",0},
          {"rows",
           [{obj,[{"id",&lt;&lt;"b8ffeaa68f2fd4010a105ddc56460466"&gt;&gt;},
                  {"key",123},
                  {"value",[&lt;&lt;"The Title"&gt;&gt;,&lt;&lt;"TheBody"&gt;&gt;]}]},
            {obj,[{"id",&lt;&lt;"53b075b3633f8d8b3654576806ef18b3"&gt;&gt;},
                  {"key",321},
                  {"value",[&lt;&lt;"Another Title"&gt;&gt;,&lt;&lt;"Another Body"&gt;&gt;]}]}]}]}
</code></pre>

<p>Now thats not very pretty is it so we use the json_obj module to query the value of "rows" so we don't have to parse this data by hand. We then make a fun that does the same thing for the "value" field of a row and use the map function to call it on each of the rows. We then reverse the list so the latest post is first. After doing all this the result of the function would be as following:</p>

<pre><code>[ [&lt;&lt;"Another Title"&gt;&gt;,&lt;&lt;"Another Body"&gt;&gt;], [&lt;&lt;"The Title"&gt;&gt;,&lt;&lt;"TheBody"&gt;&gt;] ]
</code></pre>

<p>Ahh... Much Nicer.</p>

<p>We also need to create the data so we add the add_post/1 method.</p>

<pre><code>add_post({post, Title, Body}) -&gt;
    JSONTemplate = {obj, []},
    WithTitle = json_obj:set_value("title", list_to_binary(Title), JSONTemplate),
    WithTitleAndBody = json_obj:set_value("body", list_to_binary(Body), WithTitle),
    Complete = json_obj:set_value("timestamp", calendar:time_to_seconds(now()), WithTitleAndBody),
    ecouch:doc_create("myblog", Complete).
</code></pre>

<p>This does not need much explanation. We start by creating an empty JSON object so that we can use the  json_obj functions on it. We then add the Title and Body parameters to the object and create a timestamp as well. Finally we ask ecouch to create the document.</p>

<h3>The Index Page</h3>

<p>Now edit the file called <em>src/pages/web_index.erl</em> and edit the function body() to look like this.</p>

<pre><code>body() -&gt;
    Data = blog_posts:get_posts(),
    Map = [titleHeader@text, bodyLabel@text],
    #bind { id=simpleBinding, data=Data, map=Map, body=[
        #panel { class="post", body=[
            #h2 { class="title", id=titleHeader },
            #panel { class="entry", body=[
                #label{ id=bodyLabel }
            ]}
        ]}
    ]}.
</code></pre>

<p>The main thing here is the data binding. We first take the output from our model and bind it to <em>Data</em>. As you remember the output of the model is a list of lists. Then we create the Map to describe how the elements of those lists should should bind to the page elements. So we are saying that the first element should bind to the "text" variable on the element with the id "titleHeader". We then use the #bind record, which is a sort of a for loop, and feed to it the Data and the Map.</p>

<p>You should now be able to sync and go see the webpage. Of course you can not see anything yes as we have yet to create any data.</p>

<h3>The Create Page</h3>

<p>Next create a new page using the command <code>nitrogen page /web/create</code> in your project root. Open up the newly generate <strong>src/pages/web_create.erl</strong> and replace body():</p>

<pre><code>body() -&gt;
    Body = [
        #label { text="Title:" },
        #textbox{ id=titleTextBox, class="create_title", next=body },
        #label { text="Body (HTML Allowed):" }, 
        #textarea{ id=bodyTextArea, class="create_body" },
        #br {},
        #link{ id=commitButton, text="Submit", postback=commit }
    ],

    %% Validations
    wf:wire(commitButton, titleTextBox, #validate { validators=[
        #is_required { text="Required." },
        #min_length { length=2, text="Title must be at least 2 characters long." }
    ]}),
    wf:wire(commitButton, bodyTextArea, #validate { validators=[
        #is_required { text="Required." }
    ]}),

    %% Render
    wf:render(Body).
</code></pre>

<p>Next up add a new event() just above the line that says ´event(_) -> ok.´</p>

<pre><code>event(commit) -&gt;
    [Title] = wf:q(titleTextBox),
    [Body] = wf:q(bodyTextArea),
    blog_posts:add_post({post, Title, Body}),
    Message = wf:f("Post ~p created. &lt;a href=\"/web/index\"&gt;click here&lt;/a&gt; to see it.", [Title]),
    wf:flash(Message);
</code></pre>

<p>There is nothing really complicated here as we have made most of the work already in the model. We set up a textfield and a textarea. We then bind the commitButton the generate the commit event. We then set up Validations so we can't submit empty data.</p>

<p>The commit event takes the value of the titleTextBox and bodyTextArea and sends it's data to <em>blog_posts:add_post/1</em>. It then formats a nice message and flashes it to the user.</p>

<p>Now sync and visit the page. Enter the create page and try submitting empty field. Then fill in the data and add a few posts. Visit the Index page to view your posts.</p>

<h3>Conclusion</h3>

<p>Even though this is not a very thorough nor complex tutorial it really shows how easily you can use together these two projects and create something really powerful with little code.</p>

<p>If you hit a problem please check my completed code <a href="http://medevyoujane.com/storage/tutorial-data/erlang/5MinBlog-Complete.zip">here</a></p>
]]></description><wfw:commentRss>http://medevyoujane.com/blog/rss-comments-entry-2685564.xml</wfw:commentRss></item><item><title>My CouchDBX version</title><category>Cocoa</category><category>CouchDBX</category><category>Erlang</category><dc:creator>Jón Grétar Borgþórsson</dc:creator><pubDate>Sun, 23 Nov 2008 21:31:00 +0000</pubDate><link>http://medevyoujane.com/blog/2008/11/23/my-couchdbx-version.html</link><guid isPermaLink="false">257763:2635231:2601575</guid><description><![CDATA[<p>Hey people.</p>

<p>I have been playing with <a href="http://jan.prima.de/~jan/plok/archives/142-CouchDBX-Revival.html">Jan's CouchDB<em>X</em></a> a bit and thought someone might enjoy what I did. CouchDBX is a nice little Mac OS X tool to run CouchDB without the need to set up Erlang or anything.</p>

<p>There are 3 major changes that I did. First of the UI is gone and everything is now in a status bar menu. Should make for quicker access to it and also stay out of the way. There is also a new transparent log window if you need to see what is happening on the Erlang level. The third an most important change is that CouchDBX now stores it's database in <strong>~/Documents/CouchDB</strong>. Before the database was inside the Application bundle itself and all the data disappeared every time you downloaded a new release of CouchDBX.</p>

<p>I have not renamed it or anything in case <a href="http://jan.prima.de/">Jan</a> would like to incorporate these changes to the original code or something.</p>

<p><strong>EDIT 26. Nov:</strong> There was a serious error in my old version that made the javascript engine not run correctly. This has now been fixed and you need to redownload.</p>

<ul>
<li><a href="http://dl-client.getdropbox.com/u/65508/CouchDBX.zip">Download</a></li>
<li><a href="http://github.com/JonGretar/couchdbx">My Source</a></li>
</ul>

<p><span class="full-image-block ssNonEditable"><span><img src="http://medevyoujane.com/storage/couchdbx/couchDBX-screenshot.png?__SQUARESPACE_CACHEVERSION=1227476827269" alt="CouchDBX Screenshot"/></span></span></p>
]]></description><wfw:commentRss>http://medevyoujane.com/blog/rss-comments-entry-2601575.xml</wfw:commentRss></item><item><title>A knock knock joke</title><category>Erlang</category><dc:creator>Jón Grétar Borgþórsson</dc:creator><pubDate>Fri, 21 Nov 2008 12:07:33 +0000</pubDate><link>http://medevyoujane.com/blog/2008/11/21/a-knock-knock-joke.html</link><guid isPermaLink="false">257763:2635231:2594513</guid><description><![CDATA[<p>Just a quick one in the morning.</p>

<pre><code>-module(knockknock).
-compile(export_all).

start_joke() -&gt;
    register(person_1, erlang:spawn(knockknock, person1, [])),
    register(person_2, erlang:spawn(knockknock, person2, [])),
    person_1 ! start_joke.

relay(Person, Message) -&gt;
    io:format("------- ~p -------~n", [Message]),
    Person ! Message.

person1() -&gt;
    receive 
        start_joke -&gt;
            relay(person_2, "Knock, Knock");
        "Who's There?" -&gt;
            timer:sleep(100000),
            relay(person_2, "Java")
    end,
    person1().

person2() -&gt;
    receive
        "Knock, Knock" -&gt;
            relay(person_1, "Who's There?");
        "Java" -&gt;
            relay(person_1, "Ha Ha")
    end,
    person2().
</code></pre>
]]></description><wfw:commentRss>http://medevyoujane.com/blog/rss-comments-entry-2594513.xml</wfw:commentRss></item><item><title>Adding Erlang library locations</title><category>Erlang</category><dc:creator>Jón Grétar Borgþórsson</dc:creator><pubDate>Thu, 13 Nov 2008 19:36:05 +0000</pubDate><link>http://medevyoujane.com/blog/2008/11/13/adding-erlang-library-locations.html</link><guid isPermaLink="false">257763:2635231:2559644</guid><description><![CDATA[<p>When adding Erlang libraries there are a few possible ways. The easy way is to add the libraries into the directory <em>/usr/local/lib/erlang/lib</em>. All directories there will be added to the library paths by default. The problem with that is that I don't like mixing 3rd party libraries with the core libraries. </p>

<p>Enter the ERL_LIBS environment variable. Set that to a directory and all the subdirectories of it that include code will the added automatically to the code path. To add it open up the file <em>/etc/bashrc</em> and add the following:</p>

<pre><code>ERL_LIBS=/Library/Erlang/lib
if [ -d $HOME/Library/Erlang/lib ]; then
  ERL_LIBS=$HOME/Library/Erlang/lib:$ERL_LIBS
fi
export ERL_LIBS
</code></pre>

<p>This way all libraries under /Library/Erlang/lib and /Users/JoeUser/Library/Erlang/lib will be added to Erlangs code paths. The libraries will be in priority before the system libraries but after the -pa code paths. Now you can add things like Mochiweb, Eunit, Nitrogen and more under the /Library/Erlang/lib directory.</p>

<p>You could also put this in the file <em>/usr/local/bin/erl</em></p>
]]></description><wfw:commentRss>http://medevyoujane.com/blog/rss-comments-entry-2559644.xml</wfw:commentRss></item><item><title>Contact List using SproutCore, Mochiweb and Mnesia</title><category>Erlang</category><dc:creator>Jón Grétar Borgþórsson</dc:creator><pubDate>Sat, 01 Nov 2008 21:01:02 +0000</pubDate><link>http://medevyoujane.com/blog/2008/11/1/contact-list-using-sproutcore-mochiweb-and-mnesia.html</link><guid isPermaLink="false">257763:2635231:2498499</guid><description><![CDATA[<p>Here is an example program using a <a href="http://sproutcore.com/">SproutCore</a> frontend talking to an <a href="http://erlang.org">Erlang</a> backend using the ReST protocol.</p>

<h2>Sproutcore</h2>

<p>Lets start by creating the Sproutcore application. I will not go into detail into the Sproutcore code as JavaScript and Sprutcore are way beyond a single tutorial. </p>

<pre><code>sc-init mochi_contacts
cd mochi_contacts
</code></pre>

<p>Inside <code>mochi_contacts</code> we find a nice little framework for our application. Lets start by creating our model with the command. "<code>sc-gen model mochi_contacts/contacts</code>". Then we edit our model at <strong>clients/mochi_contacts/model/contacts.js</strong> and add the following code.</p>

<pre><code>resourceURL: 'contacts',
properties: ["guid","fullname",'email','mobile'],

commitChanges: function(){
    if(this.get('fullname') == '') this.set('fullname', 'Unnamed');
    this.commit();
}
</code></pre>

<p>This is pretty straight forward. resourceURL defines the location of the data source. In this case it would be http://localhost/contacts/. In properties we define the keys we want to read from that resource. The commitChanges function then makes sure we have the fullname property defined and commits the changes to the resource.</p>

<p>Next up is our master controller. The master contoller handles our list view at the side. Create it with the command "<code>sc-gen controller mochi_contacts/master SC.CollectionController</code>", open up the file <strong>clients/mochi_contacts/controller/masterController.js</strong> and add the following.</p>

<pre><code>allowsEmptySelection: false,
allowsMultipleSelection: false,
canEditCollection: true,

addContact: function(sender){
    var content = this.get('content');
    var contact = MochiContacts.Contacts.newRecord({
        fullname: "Unnamed"
    },MochiContacts.server);

    contact.commitChanges();
    this.set('selection',[contact]);
},

delContact: function(sender){
    if(!confirm('Are you sure?')) return;
    var sel = (this.get('selection') || []).clone() ;
    var idx = sel.get('length') ;
    while(--idx &gt;= 0) {
        var contact = sel.objectAt(idx);
        contact.destroy();
    }
},
</code></pre>

<p>Not much to see here. Just basic functions for creating and deleting contacts from the list and 3 properties for defining the behaviour of the list view.</p>

<p>So now we need a second controller that will handle the form itself. Create it with the command "<code>sc-gen controller mochi_contacts/detail SC.ObjectController</code>" and put the following inside <strong>clients/mochi_contacts/controller/detailController.js</strong></p>

<pre><code>contentBinding: 'MochiContacts.masterController.selection',
commitChangesImmediately: false
</code></pre>

<p>Wow. Even less we do here. We simply bind the content of the controller to the currently selected object of the master controller. We then define that we dont want the changes to be posted automatically because we will add a button to do that.</p>

<p>Now we have to define the view. Open up <strong>clients/mochi_contacts/english.lproj/body.rhtml</strong> and remove everything. Replace with the following:</p>

<pre><code>&lt;% content_for('body') do %&gt;

&lt;% split_view :workspace, :class =&gt; 'sc-app-workspace footer', 
    :direction =&gt; :horizontal do %&gt;  
  &lt;% view :sidebar, :outlet =&gt; true do %&gt;
    &lt;% scroll_view :master_list, :outlet =&gt; true do %&gt;
      &lt;%= list_view :list_view, 
            :outlet =&gt; true, 
            :content_value_key =&gt; 'fullname', 
            :content_value_editable =&gt; false,
            :can_reorder_content =&gt; true,
            :bind =&gt; { 
              :content =&gt; 'MochiContacts.masterController.arrangedObjects', 
              :selection =&gt; 'MochiContacts.masterController.selection' 
            }
            %&gt;
    &lt;% end %&gt;
  &lt;% end %&gt;

  &lt;%= split_divider_view :outlet =&gt; true, :width =&gt; 5 %&gt;

  &lt;% view :detail_view, :outlet =&gt; true do %&gt;
    &lt;table class="card-detail"&gt;

      &lt;tr&gt;
        &lt;td&gt;&lt;label&gt;Full Name:&lt;/label&gt;&lt;/td&gt;
        &lt;td&gt;
          &lt;%= text_field_view :outlet =&gt; true, :hint =&gt; "Full Name",
            :bind =&gt; {
              :value =&gt; 'MochiContacts.detailController.fullname'
            } %&gt;
        &lt;/td&gt;
      &lt;/tr&gt;

      &lt;tr&gt;
        &lt;td&gt;&lt;label&gt;Email:&lt;/label&gt;&lt;/td&gt;
        &lt;td&gt;
          &lt;%= text_field_view :outlet =&gt; true, :hint =&gt; "email@email.com",
            :bind =&gt; {
              :value =&gt; 'MochiContacts.detailController.email'
            } %&gt;
        &lt;/td&gt;
      &lt;/tr&gt;

      &lt;tr&gt;
        &lt;td&gt;&lt;label&gt;Mobile:&lt;/label&gt;&lt;/td&gt;
        &lt;td&gt;
          &lt;%= text_field_view :outlet =&gt; true, :hint =&gt; "555-0000",
            :bind =&gt; {
              :value =&gt; 'MochiContacts.detailController.mobile'
            } %&gt;
        &lt;/td&gt;
      &lt;/tr&gt;

      &lt;tr&gt;
        &lt;td colspan="2" class="buttons"&gt;
          &lt;%= button_view :outlet =&gt; true, 
            :title =&gt; "Cancel",
            :action =&gt; 'MochiContacts.detailController.discardChanges',
            :bind =&gt; {
              :enabled =&gt; 'MochiContacts.detailController.hasChanges'
            } %&gt;
          &lt;%= button_view :outlet =&gt; true, 
            :title =&gt; "Save Changes", :default =&gt; true,
            :action =&gt; 'MochiContacts.detailController.commitChanges',
            :bind =&gt; {
              :enabled =&gt; "MochiContacts.detailController.hasChanges"
            } %&gt;
        &lt;/td&gt;
      &lt;/tr&gt;
    &lt;/table&gt;

  &lt;% end %&gt;
&lt;% end %&gt;

&lt;% view :footer, :class =&gt; 'sc-footer sc-square-theme' do %&gt;
  &lt;div class="left"&gt;
    &lt;%= button_view :outlet =&gt; true, :label =&gt; '+', 
        :action =&gt; 'MochiContacts.masterController.addContact' %&gt;
    &lt;%= button_view :outlet =&gt; true, :label =&gt; '-', 
        :action =&gt; 'MochiContacts.masterController.delContact' %&gt;
  &lt;/div&gt;

&lt;% end %&gt; &lt;!-- footer --&gt;

&lt;% end %&gt;
</code></pre>

<p>In here we have defined the views and bound their properties to the controllers.</p>

<p>Next we connect the contollers to the model. We do that inside <strong>clients/mochi_contacts/main.js</strong> by replacing the line <code>MochiContacts.server.preload(MochiContacts.FIXTURES);</code> with the following commands:</p>

<pre><code>var contactList = MochiContacts.Contacts.collection();
contactList.refresh();
MochiContacts.masterController.set('content', contactList);
MochiContacts.server.listFor(contactList);
</code></pre>

<p>Before we move to the Erlang part we have to edit <strong>sc-config</strong>. As javascript request are bound to it's own domain we have to proxy the request by adding this as the very last line:</p>

<pre><code>proxy '/contacts', :to =&gt; 'localhost:8808', :cookie_domain =&gt; 'localhost'
</code></pre>

<p>Now you should be able to start the server with the command <code>sc-server</code> and take a look at the result in <em>http://localhost:4020/mochi_contacts</em>.</p>

<h2>The Format</h2>

<p>The format SproutCore uses for REST calls are:</p>

<ul>
<li>CREATE = <strong>[POST]</strong>http://somesite/resource/create </li>
<li>READ = <strong>[GET]</strong>http://somesite/resource/list </li>
<li>UPDATE = <strong>[POST]</strong>http://somesite/resource/updateGUIDNUMBER </li>
<li>DELETE = <strong>[POST]</strong>http://somesite/resource/DESTROYGUIDNUMBER </li>
</ul>

<p>The Post values for CREATE and UPDATE methods are like:</p>

<pre><code>"records[0][mobile]" = "555-1234"
"records[0][email]" = "sam.jones@example.com"
"records[0][fullname]" = "Sam Joness"
"records[0][id]" =  "@658"
</code></pre>

<p>The body expected to return for the READ method is in JSON format and looks like:</p>

<pre><code>{"records": [
    { 
    "guid": "@570",
    "type": "Contacts",
    "fullname": "Frank Smith",
    "email": "frank.smith@example.com",
    "mobile": "555-4433"
    },{
    "guid": "@658",
    "type": "Contacts",
    "fullname": "Sam Jones",
    "email": "sam.jones@example.com",
    "mobile": "555-1234"
    }],
"ids": ["@570", "@658"]
}
</code></pre>

<p>Each record needs to have guid and type must be the name of the model it belongs to. ids must be a list of all the guid keys.</p>

<p>For mochijson2:encode/1 to be able to create this from an erlang term the format of the erlang term would be:</p>

<pre><code>{struct,[{&lt;&lt;"records"&gt;&gt;,
          [{struct,[{&lt;&lt;"guid"&gt;&gt;,&lt;&lt;"@570"&gt;&gt;},
                    {&lt;&lt;"type"&gt;&gt;,&lt;&lt;"Contacts"&gt;&gt;},
                    {&lt;&lt;"fullname"&gt;&gt;,&lt;&lt;"Frank Smith"&gt;&gt;},
                    {&lt;&lt;"email"&gt;&gt;,&lt;&lt;"frank.smith@example.com"&gt;&gt;},
                    {&lt;&lt;"mobile"&gt;&gt;,&lt;&lt;"555-4433"&gt;&gt;}]},
           {struct,[{&lt;&lt;"guid"&gt;&gt;,&lt;&lt;"@658"&gt;&gt;},
                    {&lt;&lt;"type"&gt;&gt;,&lt;&lt;"Contacts"&gt;&gt;},
                    {&lt;&lt;"fullname"&gt;&gt;,&lt;&lt;"Sam Jones"&gt;&gt;},
                    {&lt;&lt;"email"&gt;&gt;,&lt;&lt;"sam.jones@example.com"&gt;&gt;},
                    {&lt;&lt;"mobile"&gt;&gt;,&lt;&lt;"555-1234"&gt;&gt;}]}]},
         {&lt;&lt;"ids"&gt;&gt;,[&lt;&lt;"@570"&gt;&gt;,&lt;&lt;"@658"&gt;&gt;]}]}
</code></pre>

<h2>The Mochiweb Server</h2>

<p>Knowing the expected formats it should be easy to write a mochiweb server to handle this. This is my version. Possibly one of my worst Erlang code but after spending way to much time figuring out mochijson2 I'm just putting this out there. (How about some documentation mochiguys? ;)</p>

<pre><code>-module(web_server).
-include_lib("stdlib/include/qlc.hrl").
-export([start/0,stop/0,dispatch_requests/1]).
-record (contacts, {guid, type, fullname, email, mobile}).

start() -&gt;
    mnesia:create_schema([node()]),
    mnesia:start(),
    try
        mnesia:table_info(contacts, type)
    catch
        exit: _ -&gt;
            mnesia:create_table(contacts, 
                [{attributes, record_info(fields, contacts)},
                {type, set},
                {disc_copies, [node()]}])
    end,
    mochiweb_http:start([{port, 8808},{loop, fun dispatch_requests/1}]).

stop() -&gt;
    mochiweb_http:stop().

dispatch_requests(Req) -&gt;
    Path = Req:get(path),
    Method = Req:get(method),
    Post = Req:parse_post(),
    io:format("~p request for ~p with post: ~p~n", [Method, Path, Post]),
    Response = handle(Method, Path, Post),
    Req:respond(Response).


handle('GET', "/contacts/list", _Post) -&gt;
    F = fun() -&gt;
        Q = qlc:q([ build_struct(C) || C &lt;- mnesia:table(contacts) ]),
        Q2 = qlc:q(
            [ list_to_binary(C#contacts.guid) || C &lt;- mnesia:table(contacts) ]),
        Records = qlc:e(Q),
        IDs = qlc:e(Q2),
        Struct = {struct, [{&lt;&lt;"records"&gt;&gt;, Records},{&lt;&lt;"ids"&gt;&gt;, IDs}]},
        JSON = mochijson2:encode(Struct),
        list_to_binary(JSON)
    end,
    {atomic, Result} = mnesia:transaction(F),
    {200, [{"Content-Type", "text/javascript"}], Result };

handle('POST', "/contacts/create", Post) -&gt;
    Guid = proplists:get_value("records[0][_guid]", Post),
    FullName = proplists:get_value("records[0][fullname]", Post),
    Email = proplists:get_value("records[0][email]", Post),
    Mobile = proplists:get_value("records[0][mobile]", Post),
    F = fun() -&gt;
          mnesia:write(#contacts{
            guid=Guid, type="Contacts", fullname=FullName, 
            email=Email, mobile=Mobile}) 
    end,
    mnesia:transaction(F),
    {200, [{"Content-Type", "text/plain"}], &lt;&lt;"Created"&gt;&gt; };

handle('POST', "/contacts/update"++Guid, Post) -&gt;
    FullName = proplists:get_value("records[0][fullname]", Post),
    Email = proplists:get_value("records[0][email]", Post),
    Mobile = proplists:get_value("records[0][mobile]", Post),
    F = fun() -&gt;
          mnesia:write(#contacts{
            guid=Guid, type="Contacts", fullname=FullName, 
            email=Email, mobile=Mobile}) 
    end,
    mnesia:transaction(F),
    {200, [{"Content-Type", "text/plain"}], &lt;&lt;"Updated"&gt;&gt; };

handle('POST', "/contacts/destroy"++Guid, _Post) -&gt;
    F = fun() -&gt;
          mnesia:delete({contacts, Guid}) 
    end,
    mnesia:transaction(F),
    {200, [{"Content-Type", "text/plain"}], &lt;&lt;"Destoyed"&gt;&gt; };

handle(_, _, _) -&gt;
    {404, [{"Content-Type", "text/plain"}], &lt;&lt;"Unknown Request"&gt;&gt;}.

build_struct(Record) -&gt;
    {struct, [
        {&lt;&lt;"guid"&gt;&gt;, list_to_binary(Record#contacts.guid)},
        {&lt;&lt;"type"&gt;&gt;, list_to_binary(Record#contacts.type)},
        {&lt;&lt;"fullname"&gt;&gt;, list_to_binary(Record#contacts.fullname)},
        {&lt;&lt;"email"&gt;&gt;, list_to_binary(Record#contacts.email)},
        {&lt;&lt;"mobile"&gt;&gt;, list_to_binary(Record#contacts.mobile)}
    ]}.
</code></pre>

<p>Just compile this and start with <code>web_server:start()</code>.</p>

<p><a href="http://medevyoujane.com/storage/tutorial-data/erlang/mochi_contacts.zip">Download the source</a></p>
]]></description><wfw:commentRss>http://medevyoujane.com/blog/rss-comments-entry-2498499.xml</wfw:commentRss></item></channel></rss>