<?xml version="1.0" encoding="UTF-8"?>
<commit>
  <added type="array">
    <added>
      <filename>test/soup_test.rb</filename>
    </added>
  </added>
  <modified type="array">
    <modified>
      <diff>@@ -4,4 +4,6 @@ doc
 *.db
 .DS_Store
 *~
-meta
\ No newline at end of file
+meta
+tmp
+soup
\ No newline at end of file</diff>
      <filename>.gitignore</filename>
    </modified>
    <modified>
      <diff>@@ -2,100 +2,115 @@
 $LOAD_PATH.unshift(File.dirname(__FILE__)).uniq!
 
 require 'soup/snip'
+require 'yaml'
+require 'fileutils'
 
-module Soup
-  VERSION = &quot;0.2.2&quot;
-  
-  DEFAULT_CONFIG = {
-    :adapter  =&gt; 'sqlite3',
-    :database =&gt; 'soup.db'
-  }
-  
-  DEFAULT_TUPLE_IMPLEMENTATION = &quot;active_record_tuple&quot;
-  
-  # Set the base of this soup, i.e. where to get the data. This is the
-  # database configuration, i.e.
-  #
-  #   Soup.base = {:database =&gt; 'my_soup.db'}
-  #
-  def self.base=(database_config)
-    @database_config = database_config
+class Soup
+  VERSION = &quot;0.9.9&quot;
+
+  # You can access a default soup using this methods.
+
+  def self.default_instance #:nodoc:
+    @@instance ||= new
   end
-  
-  # Call this to set which tuple implementation to use, i.e.
-  #
-  #   Soup.flavour = :active_record
-  #
-  def self.flavour=(tuple_implementation)
-    @tuple_implementation = &quot;#{tuple_implementation}_tuple&quot;
-    # We want to reset the tuple class if we re-flavour the soup.
-    @tuple_class = nil
+
+  def self.[](*args)
+    default_instance[*args]
   end
-  
-  def self.tuple_class
-    @tuple_class ||= case (@tuple_implementation || DEFAULT_TUPLE_IMPLEMENTATION)
-    when &quot;active_record_tuple&quot;, nil
-      Soup::Tuples::ActiveRecordTuple
-    when &quot;data_mapper_tuple&quot;
-      Soup::Tuples::DataMapperTuple
-    when &quot;sequel_tuple&quot;
-      Soup::Tuples::SequelTuple
-    end
+
+  def self.&lt;&lt;(attributes)
+    default_instance &lt;&lt; attributes
+  end
+
+  def self.sieve(*args)
+    default_instance.sieve(*args)
   end
   
+  def self.destroy(*args)
+    default_instance.destroy(*args)
+  end
+
+  attr_reader :base_path
+
   # Get the soup ready!
-  def self.prepare
-    require &quot;soup/tuples/#{@tuple_implementation || DEFAULT_TUPLE_IMPLEMENTATION}&quot;
-    tuple_class.prepare_database(DEFAULT_CONFIG.merge(@database_config || {}))
+  def initialize(base_path=&quot;soup&quot;)
+    @base_path = base_path
+    FileUtils.mkdir_p(base_path)
   end
-  
+
   # The main interface
   # ==================
-  
-  # Finds bits in the soup that make the given attribute hash.
-  # This method should eventually be delegated to the underlying persistence
-  # layers (i.e. Snips and Tuples, or another document database). The expected
-  # behaviour is 
-  def self.sieve(*args)
-    Snip.sieve(*args)
+
+  # A shorthand for #sieve, with the addition that only a name may be
+  # supplied (i.e. Soup['my snip'])
+  def [](conditions)
+    conditions = {:name =&gt; conditions} unless conditions.respond_to?(:keys)
+    sieve(conditions)
   end
-  
+
   # Puts some data into the soup, and returns an object that contains
   # that data. The object should respond to accessing and setting its
   # attributes as if they were defined using attr_accessor on the object's
   # class.
-  def self.&lt;&lt;(attributes)
-    s = Snip.new(attributes)
-    s.save
-    s
+  def &lt;&lt;(attributes)
+    save_snip(attributes)
+    Snip.new(attributes, self)
   end
-  
-  # A shortcut to sieve by name attribute only
-  def self.[](*args)
-    results = if args[0].is_a?(Hash) || args.length &gt; 1
-      sieve(*args)
+
+  # Finds bits in the soup that make the given attribute hash.
+  # This method should eventually be delegated to the underlying persistence
+  # layers (i.e. Snips and Tuples, or another document database). The expected
+  # behaviour is
+  def sieve(conditions)
+    if conditions.keys == [:name]
+      load_snip(conditions[:name])
     else
-      sieve(:name =&gt; args[0])
+      all_snips.select do |s|
+        conditions.inject(true) do |matches, (key, value)|
+          matches &amp;&amp; (s.__send__(key) == value)
+        end
+      end
     end
-    results.length == 1 ? results.first : results
   end
-  
-  def self.destroy(snip_name)
-    snip = sieve(:name =&gt; snip_name)[0]
-    snip.destroy
+
+  def destroy(name)
+    File.delete(path_for(name))
   end
-  
-  # ==== (interface ends) =====
-  
-  # Save the current state of the soup into a YAML file.
-  def self.preserve(filename='soup.yml')
-    snips = {}
-    1.upto(Soup.tuple_class.next_snip_id) do |id|
-      snip = Snip.find(id) rescue nil
-      snips[snip.id] = snip if snip
+
+  private
+
+  def save_snip(attributes)
+    File.open(path_for(attributes[:name]), 'w') do |f| 
+      content = attributes.delete(:content)
+      f.write content
+      f.write attributes.to_yaml.gsub(/^---\s/, attribute_token)
+    end
+  end
+
+  def load_snip(name)
+    path = path_for(name)
+    if File.exist?(path)
+      file = File.read(path)
+      attribute_start = file.index(attribute_token)
+      content = file.slice(0...attribute_start)
+      attributes = YAML.load(file.slice(attribute_start..-1)).merge(:content =&gt; content)
+      Snip.new(attributes, self)
+    else
+      nil
     end
-    File.open(filename, 'w') do |f|
-      f.puts snips.to_yaml
+  end
+
+  def all_snips
+    Dir[path_for(&quot;*&quot;)].map do |path|
+      load_snip(File.basename(path, &quot;.yml&quot;))
     end
   end
-end
\ No newline at end of file
+
+  def path_for(filename)
+    File.join(base_path, filename + &quot;.yml&quot;)
+  end
+  
+  def attribute_token
+    &quot;--- # Soup attributes&quot;
+  end
+end</diff>
      <filename>lib/soup.rb</filename>
    </modified>
    <modified>
      <diff>@@ -1,5 +1,5 @@
 # Based on Builder's BlankSlate object
-module Soup
+class Soup
   class EmptyClass
     instance_methods.each { |m| undef_method(m) unless m =~ /^(__|instance_eval|respond_to\?)/ }
   end</diff>
      <filename>lib/soup/empty_class.rb</filename>
    </modified>
    <modified>
      <diff>@@ -1,148 +1,37 @@
-require 'rubygems'
 require 'soup/empty_class'
 
-# methods called on Tuple:
-# Tuple.for_snip(id)
-# Tuple.find_matching(tuple_name, tuple_value_conditions)
-# Tuple.find_matching_hash(key =&gt; value, key2 =&gt; value2, ...)
-# Tuple.next_snip_id
-# Tuple#save
-# Tuple#name
-# Tuple#value
-# Tuple#destroy
-
 class Snip &lt; Soup::EmptyClass
-  
-  # Returns all snips which match the given criteria, i.e. which have a tuple that
-  # matches the given conditions. For example:
-  #
-  #   Snip.sieve(:created_at, &quot;&gt; '2007-01-01'&quot;)
-  #
-  # should return all Snips who have a 'created_at' value greater than '2007-01-01'.
-  #
-  def self.sieve(*args)
-    if args.length &gt; 1
-      name = args[0]
-      tuple_value_conditions = args[1]
-      matching_tuples = Soup.tuple_class.find_matching(name, tuple_value_conditions)
-      matching_tuples.map { |t| t.snip_id }.uniq.map { |snip_id| find(snip_id) }
-    else
-      pairs = args[0].inject([]) { |ary, (name, value)| ary &lt;&lt; [name, value] }
-      matching_tuples = pairs.map { |(name, value)| Soup.tuple_class.find_matching(name, &quot;='#{value}'&quot;) }.flatten
-      snips = matching_tuples.map { |t| t.snip_id }.uniq.map { |snip_id| find(snip_id) }
-      snips.reject { |s| pairs.map { |(name, value)| s.get_value(name) == value }.include?(false) }
-    end
-  end
-  
-  # Returns the snip with the given ID (i.e. the collection of all tuples
-  # with the matching snip_id, gathered into a magical snip.)
-  #
-  def self.find(id)
-    raise &quot;not found&quot; unless (tuples = Soup.tuple_class.for_snip(id)).any?
-    snip = Snip.new(:__id =&gt; id)
-    snip.replace_tuples(tuples)
-    snip
-  end
-  
-  attr_reader :tuples
-  
-  def initialize(attributes = {})
-    set_id(attributes.delete(:__id))
-    @tuples = {}
-    attributes.each { |name, value| set_value(name, value) }
-  end
-  
-  def respond_to?(method)
-    attributes.keys.include?(method.to_s)
+
+  def initialize(attributes = {}, soup = Soup)
+    @attributes = attributes
+    @soup = soup
   end
-  
+
   def save
-    raise &quot;Saving would be pointless - there's no data!&quot; if @tuples.empty?
-    set_id_if_necessary
-    each_tuple { |t| t.save }
+    @soup &lt;&lt; @attributes
     self
   end
-  
+
   def destroy
-    each_tuple { |t| t.destroy }
-  end
-  
-  def reload
-    return self unless self.id
-    replace_tuples(Soup.tuple_class.for_snip(id))
+    @soup.destroy(self.name)
     self
   end
-  
-  def attributes
-    @tuples.inject({}) { |h, (name, t)| h[name] = t.value; h }
-  end
 
-  def replace_tuples(new_tuples)
-    @tuples.clear
-    new_tuples.each { |tuple| @tuples[tuple.name] = tuple }
-  end
-  
-  def to_s
-    &quot;&lt;Snip id:#{self.id || &quot;unset&quot;} #{tuples_as_string}&gt;&quot;
-  end
-  
   def inspect
-    &quot;&lt;Snip id:#{self.id || &quot;unset&quot;} name:#{self.name}&gt;&quot;
+    &quot;&lt;Snip name:#{self.name}&gt;&quot;
   end
-  
-  def to_yaml(*args)
-    attributes.to_yaml(*args)
+
+  def respond_to?(method)
+    @attributes.keys.include?(method.to_s)
   end
-  
+
   def method_missing(method, *args)
     value = args.length &gt; 1 ? args : args.first
-    if method.to_s =~ /(.*)=\Z/ # || value - could be a nice DSL touch.
-      set_value($1, value)
-    else
-      get_value(method.to_s)
-    end
-  end
-  
-  def id #:nodoc: why is ID special?
-    @id
-  end
-  
-  def get_value(name)
-    @tuples[name.to_s] ? @tuples[name.to_s].value : nil
-  end
-  
-  def set_value(name, value)
-    tuple = @tuples[name.to_s] 
-    if tuple
-      tuple.value = value
+    if method.to_s =~ /(.*)=\Z/
+      @attributes[$1] = value
     else
-      attributes = {:snip_id =&gt; self.id, :name =&gt; name.to_s, :value =&gt; value}
-      tuple = @tuples[name.to_s] = Soup.tuple_class.new(attributes)
+      @attributes[method]
     end
-    tuple.value
-  end
-  
-  
-  private
-  
-  def each_tuple
-    @tuples.values.each { |tuple| yield tuple }
-  end
-  
-  def set_id(id)
-    @id = id
-    self
   end
 
-  def set_id_if_necessary
-    if self.id.nil?
-      set_id(Soup.tuple_class.next_snip_id)
-      @tuples.values.each { |tuple| tuple.snip_id = self.id }
-    end
-  end
-  
-  def tuples_as_string
-    @tuples.inject(&quot;&quot;) { |hash, (name, tuple)| hash += &quot; #{name}:'#{tuple.value}'&quot; }.strip
-  end
-  
-end
\ No newline at end of file
+end</diff>
      <filename>lib/soup/snip.rb</filename>
    </modified>
  </modified>
  <removed type="array">
    <removed>
      <filename>lib/soup/tuples/active_record_tuple.rb</filename>
    </removed>
    <removed>
      <filename>lib/soup/tuples/data_mapper_tuple.rb</filename>
    </removed>
    <removed>
      <filename>lib/soup/tuples/sequel_tuple.rb</filename>
    </removed>
    <removed>
      <filename>spec/snip_spec.rb</filename>
    </removed>
    <removed>
      <filename>spec/soup_spec.rb</filename>
    </removed>
    <removed>
      <filename>spec/spec_helper.rb</filename>
    </removed>
    <removed>
      <filename>spec/spec_runner.rb</filename>
    </removed>
  </removed>
  <parents type="array">
    <parent>
      <id>b775ab2b204693788814978b12da53a23c160c38</id>
    </parent>
  </parents>
  <author>
    <name>James Adam</name>
    <email>james@lazyatom.com</email>
  </author>
  <url>http://github.com/lazyatom/soup/commit/cb42a7b8cd1cf9ca6255a7e68a6670b2a051f6d3</url>
  <id>cb42a7b8cd1cf9ca6255a7e68a6670b2a051f6d3</id>
  <committed-date>2009-09-17T10:01:26-07:00</committed-date>
  <authored-date>2009-09-17T10:01:08-07:00</authored-date>
  <message>Turns out I don't care about running soup in databases. I want to be able to edit snips in my own editors, and that means using a file-based storage mechanism. Performance hits abound, but that's not a huge problem.</message>
  <tree>697fbe02356f57f74806fa58c688692a2441db92</tree>
  <committer>
    <name>James Adam</name>
    <email>james@lazyatom.com</email>
  </committer>
</commit>
