<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<link rel="stylesheet" href="stylesheets/screen.css" type="text/css" media="screen" />
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>
Stone: Dead-Simple Data Persistence
</title>
<script src="javascripts/rounded_corners_lite.inc.js" type="text/javascript"></script>
<style>
</style>
<script type="text/javascript">
window.onload = function() {
settings = {
tl: { radius: 10 },
tr: { radius: 10 },
bl: { radius: 10 },
br: { radius: 10 },
antiAlias: true,
autoPad: true,
validTags: ["div"]
}
var versionBox = new curvyCorners(settings, document.getElementById("version"));
versionBox.applyCornersToAll();
}
</script>
</head>
<body>
<div id="main">
<h1>Stone: Dead-Simple Data Persistence</h1>
<div id="version" class="clickable" onclick='document.location = "http://rubyforge.org/projects/stone"; return false'>
<p>Get Version</p>
<a href="http://rubyforge.org/projects/stone" class="numbers">0.1.2</a>
</div>
<h1>→ ‘stone’</h1>
<p><img src="images/stone.png" alt="" /></p>
<h2>Sections</h2>
<p><a href="#what">What</a></p>
<p><a href="#installing">Installing</a></p>
<a href="#running">Getting Up and Running</a>
<ul>
<li><a href="#rails">Rails</a></li>
<li><a href="#merb">Merb</a></li>
<li><a href="#everywhere">Everywhere Else</a></li>
</ul>
<a href="#usage">Usage</a>
<ul>
<li><a href="#models">Models</a></li>
<li><a href="#gppd">Get, Post, Put, and Delete</a></li>
</ul>
<p><a href="#word">A Word About Finding Stuff</a></p>
<p><a href="#license">License</a></p>
<p><a href="#contrib">Contributing</a></p>
<a href="#contact">Contact</a>
<br /><br />
<h2 id="what">What</h2>
<p>For small applications, a database can be overkill for storing your data in a consistent and
organized manner. Therefore, Stone was built to provide plug-and-play data persistence for
any application or framework. It is fast, and it is easy… therefore it is good.</p>
<p>You can check out an application that uses Merb+Stone <a href="http://theprestigio.us">here.</a></p>
<p>The source for that blog is <a href="http://github.com/ndemonner/written_in_stone/tree/master">here.</a></p>
<h2 id="installing">Installing</h2>
<pre>sudo gem install stone</pre>
<h2 id="running">Up and Running</h2>
<h3 id="rails">Rails</h3>
<ul>
<li>Create a new file in <code>config/initializers</code> called <code>stone.rb</code></li>
</ul>
<ul>
<li>Add the following code to your new file:
<pre class='syntax'>
<span class="ident">require</span> <span class="punct">'</span><span class="string">stone</span><span class="punct">'</span>
<span class="constant">Stone</span><span class="punct">.</span><span class="ident">start</span><span class="punct">(</span><span class="constant">Dir</span><span class="punct">.</span><span class="ident">pwd</span><span class="punct">,</span> <span class="constant">Dir</span><span class="punct">.</span><span class="ident">glob</span><span class="punct">(</span><span class="constant">File</span><span class="punct">.</span><span class="ident">join</span><span class="punct">(</span><span class="constant">Dir</span><span class="punct">.</span><span class="ident">pwd</span><span class="punct">,"</span><span class="string">app/models/*</span><span class="punct">")),</span> <span class="symbol">:rails</span><span class="punct">)</span>
</pre></li>
</ul>
<ul>
<li>Open your <code>environment.rb</code> file and look for the following lines:
<pre class='syntax'>
<span class="comment"># Skip frameworks you're not going to use (only works if using vendor/rails).</span>
<span class="comment"># To use Rails without a database, you must remove the Active Record framework</span>
<span class="comment"># config.frameworks -= [ :active_record, :active_resource, :action_mailer ]</span>
</pre></li>
</ul>
<ul>
<li>Uncomment the last of those lines, and leave only active_record,
so that it looks like this:
<pre class='syntax'>
<span class="comment"># Skip frameworks you're not going to use (only works if using vendor/rails).</span>
<span class="comment"># To use Rails without a database, you must remove the Active Record framework</span>
<span class="ident">config</span><span class="punct">.</span><span class="ident">frameworks</span> <span class="punct">-=</span> <span class="punct">[</span> <span class="symbol">:active_record</span> <span class="punct">]</span>
</pre></li>
</ul>
<ul>
<li>Create some models! We’ll use an Author as an example:
<pre class='syntax'>
stone-gen model Author name:string
</pre></li>
</ul>
<h3 id="merb">Merb</h3>
<ul>
<li>Add the following code to your <code>init.rb</code> file:
<pre class='syntax'>
<span class="ident">dependency</span> <span class="punct">'</span><span class="string">stone</span><span class="punct">'</span>
<span class="comment"># add this in the Merb::BootLoader.after_app_loads block</span>
<span class="comment"># at the bottom of init.rb</span>
<span class="constant">Stone</span><span class="punct">.</span><span class="ident">start</span><span class="punct">(</span><span class="constant">Dir</span><span class="punct">.</span><span class="ident">pwd</span><span class="punct">,</span> <span class="constant">Dir</span><span class="punct">.</span><span class="ident">glob</span><span class="punct">(</span><span class="constant">File</span><span class="punct">.</span><span class="ident">join</span><span class="punct">(</span><span class="constant">Dir</span><span class="punct">.</span><span class="ident">pwd</span><span class="punct">,"</span><span class="string">app/models/*</span><span class="punct">")),</span> <span class="symbol">:merb</span><span class="punct">)</span>
</pre></li>
</ul>
<ul>
<li>Create some models! We’ll use an Author as an example:
<pre class='syntax'>
stone-gen model Author name:string
</pre></li>
</ul>
<h3 id="everywhere">Everywhere Else</h3>
<p>Stone was designed to provide easy data storage management for <strong>any</strong>
app, not just web ones.</p>
<ul>
<li>Wherever you load your app, add the following:
<pre class='syntax'>
<span class="ident">require</span> <span class="punct">'</span><span class="string">stone</span><span class="punct">'</span>
<span class="comment"># replace path/to/models/ with wherever your models/resources may be</span>
<span class="constant">Stone</span><span class="punct">.</span><span class="ident">start</span><span class="punct">(</span><span class="constant">Dir</span><span class="punct">.</span><span class="ident">pwd</span><span class="punct">,</span> <span class="constant">Dir</span><span class="punct">.</span><span class="ident">glob</span><span class="punct">(</span><span class="constant">File</span><span class="punct">.</span><span class="ident">join</span><span class="punct">(</span><span class="constant">Dir</span><span class="punct">.</span><span class="ident">pwd</span><span class="punct">,"</span><span class="string">path/to/models/*</span><span class="punct">")))</span>
</pre></li>
</ul>
<ul>
<li>Create some models! See <a href="#models">Models</a>.</li>
</ul>
<p>That’s it! Remember, there are no databases to install with Stone. Instead,
your data gets persisted to files within <code>myapp/datastore/</code>.</p>
<h2 id="usage">Usage</h2>
<h3 id="models">Model Files</h3>
<p>Models are really easy to create. Here is an example:
<pre class='syntax'>
<span class="keyword">class </span><span class="class">Person</span>
<span class="ident">include</span> <span class="constant">Stone</span><span class="punct">::</span><span class="constant">Resource</span> <span class="comment"># gives you access to persistence methods</span>
<span class="comment"># defines an attribute called "name" of type String</span>
<span class="ident">field</span> <span class="symbol">:name</span><span class="punct">,</span> <span class="constant">String</span>
<span class="comment"># defines an attribute called "email" of type String. </span>
<span class="comment"># Since :unique => true is set, "email" must be unique.</span>
<span class="ident">field</span> <span class="symbol">:email</span><span class="punct">,</span> <span class="constant">String</span><span class="punct">,</span> <span class="symbol">:unique</span> <span class="punct">=></span> <span class="constant">true</span>
<span class="comment"># Notifies Stone of a relationship between People and Jewels.</span>
<span class="comment"># This allows for @person.jewels retrieval.</span>
<span class="ident">has_many</span> <span class="symbol">:jewels</span>
<span class="comment"># both name and email must be present or errors will be added</span>
<span class="ident">validates_presence_of</span> <span class="symbol">:name</span><span class="punct">,</span> <span class="symbol">:email</span>
<span class="keyword">end</span>
</pre></p>
<p>For more validation methods, see <a href="http://validatable.rubyforge.org/classes/Validatable/Macros.html">here</a>.</p>
<h3 id="gppd">Get, Post, Put, and Delete</h3>
<ul>
<li>Getting
<pre class='syntax'>
<span class="constant">Author</span><span class="punct">.</span><span class="ident">get</span><span class="punct">(</span><span class="ident">some_id</span><span class="punct">)</span> <span class="comment"># gets Author with some_id</span>
<span class="constant">Author</span><span class="punct">[</span><span class="ident">some_id</span><span class="punct">]</span> <span class="comment"># same as get()</span>
<span class="comment"># brings back first author whose name is "Nick DeMonner"</span>
<span class="constant">Author</span><span class="punct">.</span><span class="ident">first</span><span class="punct">(</span><span class="symbol">:name</span> <span class="punct">=></span> <span class="punct">"</span><span class="string">Nick DeMonner</span><span class="punct">")</span>
<span class="comment"># brings back first author whose name contains "Nick"</span>
<span class="constant">Author</span><span class="punct">.</span><span class="ident">first</span><span class="punct">(</span><span class="symbol">:name</span><span class="punct">.</span><span class="ident">includes</span> <span class="punct">=></span> <span class="punct">'</span><span class="string">Nick</span><span class="punct">')</span>
<span class="comment"># brings back all authors whose email contains "gmail.com", and who </span>
<span class="comment"># were created before today</span>
<span class="constant">Author</span><span class="punct">.</span><span class="ident">all</span><span class="punct">(</span><span class="symbol">:email</span><span class="punct">.</span><span class="ident">includes</span> <span class="punct">=></span> <span class="punct">"</span><span class="string">gmail.com</span><span class="punct">",</span> <span class="symbol">:created_at</span><span class="punct">.</span><span class="ident">lt</span> <span class="punct">=></span> <span class="constant">DateTime</span><span class="punct">.</span><span class="ident">now</span><span class="punct">)</span>
<span class="comment"># brings back all Authors created before today, and orders them descending</span>
<span class="comment"># from most recent to least</span>
<span class="constant">Author</span><span class="punct">.</span><span class="ident">all</span><span class="punct">(</span><span class="symbol">:created_at</span><span class="punct">.</span><span class="ident">lt</span> <span class="punct">=></span> <span class="constant">DateTime</span><span class="punct">.</span><span class="ident">now</span><span class="punct">,</span> <span class="symbol">:order</span> <span class="punct">=></span> <span class="punct">{</span><span class="symbol">:created_at</span> <span class="punct">=></span> <span class="symbol">:desc</span><span class="punct">})</span>
</pre></li>
</ul>
<ul>
<li>Posting
<pre class='syntax'>
<span class="ident">author</span> <span class="punct">=</span> <span class="constant">Author</span><span class="punct">.</span><span class="ident">new</span>
<span class="ident">author</span><span class="punct">.</span><span class="ident">name</span> <span class="punct">=</span> <span class="punct">"</span><span class="string">Nick DeMonner</span><span class="punct">"</span>
<span class="ident">author</span><span class="punct">.</span><span class="ident">save</span> <span class="comment"># calls Author.post after validations</span>
</pre></li>
</ul>
<ul>
<li>Putting
<pre class='syntax'>
<span class="ident">author</span> <span class="punct">=</span> <span class="constant">Author</span><span class="punct">[</span><span class="ident">some_id</span><span class="punct">]</span> <span class="comment"># gets Author with id of some_id</span>
<span class="comment"># updates name and calls Resource.save (which in turn calls Resource.put </span>
<span class="comment"># because this resource is being updated, not created)</span>
<span class="ident">author</span><span class="punct">.</span><span class="ident">update_attributes</span><span class="punct">(</span><span class="symbol">:name</span> <span class="punct">=></span> <span class="punct">"</span><span class="string">Bob Bobberson</span><span class="punct">")</span>
</pre></li>
</ul>
<ul>
<li>Deleting
<pre class='syntax'>
<span class="constant">Author</span><span class="punct">.</span><span class="ident">delete</span><span class="punct">(</span><span class="ident">some_id</span><span class="punct">)</span> <span class="comment"># deletes Author at some_id</span>
</pre></li>
</ul>
<h3 id="word">A Word About Finding Stuff</h3>
<p>Stone uses a series of unique methods (à la DataMapper) to finding objects.
You may use the following methods when searching:</p>
<ul>
<li>Matches all objects whose <code>field</code> is greater
than <code>thing</code>
<pre class='syntax'>
<span class="symbol">:field</span><span class="punct">.</span><span class="ident">gt</span> <span class="punct">=></span> <span class="ident">thing</span>
</pre></li>
</ul>
<ul>
<li>Matches all objects whose <code>field</code> is greater than
or equal to <code>thing</code>
<pre class='syntax'>
<span class="symbol">:field</span><span class="punct">.</span><span class="ident">gte</span> <span class="punct">=></span> <span class="ident">thing</span>
</pre></li>
</ul>
<ul>
<li>Matches all objects whose <code>field</code> is less than <code>thing</code>
<pre class='syntax'>
<span class="symbol">:field</span><span class="punct">.</span><span class="ident">lt</span> <span class="punct">=></span> <span class="ident">thing</span>
</pre></li>
</ul>
<ul>
<li>Matches all objects whose <code>field</code> is less than or
equal to <code>thing</code>
<pre class='syntax'>
<span class="symbol">:field</span><span class="punct">.</span><span class="ident">lte</span> <span class="punct">=></span> <span class="ident">thing</span>
</pre></li>
</ul>
<ul>
<li>Matches all objects whose <code>field</code> includes <code>thing</code>
<pre class='syntax'>
<span class="symbol">:field</span><span class="punct">.</span><span class="ident">includes</span> <span class="punct">=></span> <span class="ident">thing</span>
</pre></li>
</ul>
<ul>
<li>Matches all objects whose <code>field</code> is equal to <code>thing</code>
<pre class='syntax'>
<span class="symbol">:field</span><span class="punct">.</span><span class="ident">equals</span> <span class="punct">=></span> <span class="ident">thing</span>
</pre></li>
</ul>
<ul>
<li>Matches all objects whose <code>field</code> Regexp matches <code>thing</code>
<pre class='syntax'>
<span class="symbol">:field</span><span class="punct">.</span><span class="ident">matches</span> <span class="punct">=></span> <span class="ident">regexp</span>
</pre></li>
</ul>
<ul>
<li>Matches all objects whose <code>field</code> does not equal <code>thing</code>
<pre class='syntax'>
<span class="symbol">:field</span><span class="punct">.</span><span class="ident">not</span> <span class="punct">=></span> <span class="ident">thing</span>
</pre></li>
</ul>
<h2 id="license">License</h2>
<p>This code is free to use under the terms of the <span class="caps">MIT</span> license.</p>
<h2 id="contrib">Contributing</h2>
<p><span class="caps">PLEASE</span>. Stone is extremely immature at this point—“stable” is
the watchword for the moment.</p>
<ul>
<li>You can grab the source using Git:
<pre class='syntax'>
git clone git://github.com/ndemonner/stone.git
</pre></li>
</ul>
<p>The code is pretty well specced out, so make sure you don’t break anything
by running <code>rake ok</code> every once in a while.</p>
<p>Please add specs for any new functionality you might add, and hit me up to
commit. =D</p>
<h2 id="contact">Contact</h2>
<p>Comments are welcome. Join me in the <span class="caps">IRC</span> channel #stone on freenode.</p>
<p class="coda">
<a href="http://theprestigio.us">Nick DeMonner</a>, 17th April 2008<br>
Theme extended from <a href="http://rb2js.rubyforge.org/">Paul Battley</a>
</p>
</div>
<!-- insert site tracking codes here, like Google Urchin -->
<script type="text/javascript">
var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
</script>
<script type="text/javascript">
var pageTracker = _gat._getTracker("UA-2831521-3");
pageTracker._initData();
pageTracker._trackPageview();
</script>
</body>
</html>