From 1325a3632c379e928d4667a17633b0ecc51e1c74 Mon Sep 17 00:00:00 2001
From: ahoward <ara.t.howard@gmail.com>
Date: Mon, 23 Jul 2012 00:29:15 -0600
Subject: [PATCH] first commit

---
 .README.md.swp                    | Bin 0 -> 12288 bytes
 .Rakefile.swp                     | Bin 0 -> 45056 bytes
 .a.rb.swp                         | Bin 0 -> 12288 bytes
 README.md                         |  52 ++++
 Rakefile                          | 446 ++++++++++++++++++++++++++++++
 lib/.mongoid-grid_fs.rb.swp       | Bin 0 -> 32768 bytes
 lib/mongoid-grid_fs.rb            | 419 ++++++++++++++++++++++++++++
 mongoid-grid_fs.gemspec           |  36 +++
 pkg/mongoid-grid_fs-1.0.0.gem     | Bin 0 -> 12288 bytes
 test/.helper.rb.swp               | Bin 0 -> 12288 bytes
 test/.mongoid-grid_fs_test.rb.swp | Bin 0 -> 12288 bytes
 test/.testing.rb.swp              | Bin 0 -> 16384 bytes
 test/helper.rb                    |  18 ++
 test/mongoid-grid_fs_test.rb      | 147 ++++++++++
 test/testing.rb                   | 196 +++++++++++++
 15 files changed, 1314 insertions(+)
 create mode 100644 .README.md.swp
 create mode 100644 .Rakefile.swp
 create mode 100644 .a.rb.swp
 create mode 100644 README.md
 create mode 100644 Rakefile
 create mode 100644 lib/.mongoid-grid_fs.rb.swp
 create mode 100644 lib/mongoid-grid_fs.rb
 create mode 100644 mongoid-grid_fs.gemspec
 create mode 100644 pkg/mongoid-grid_fs-1.0.0.gem
 create mode 100644 test/.helper.rb.swp
 create mode 100644 test/.mongoid-grid_fs_test.rb.swp
 create mode 100644 test/.testing.rb.swp
 create mode 100644 test/helper.rb
 create mode 100644 test/mongoid-grid_fs_test.rb
 create mode 100644 test/testing.rb

diff --git a/.README.md.swp b/.README.md.swp
new file mode 100644
index 0000000000000000000000000000000000000000..8b608506b25780781f7965c80afbedb4fab13078
GIT binary patch
literal 12288
zcmeI2J&)W(7{@1cKoStCpnAv=Z33(vI0Wd#ofPg4w1IokZ2&=pHe-8i5Ak{&&-hl`
zKm#S;0Sfp4d<I@x5M3xBf)0t227&mGUyg7^Qc*-amVWECXYBbuzws8<PIU3j$qu~`
ztO{%o3-Rl3C-?35Z;4x92qAN`kagl)?zqKi6%;0x#T|PI@qT~9(AII7X%`O1b5mwU
zC*!Qv$t<<u!S<!Co$X+L_o44HA~&-EHqaVqTsnU7lvsWCnT!5-<?Q2h=8-p84jW(t
zY=8~00XDz}*Z><~1OFoft~wz;K)v_%H9yzyPaNC#hrDA0Y=8~00XDz}*Z><~18jf|
zumLu}2JS%v692KEeNc$gClMb1{}1o~e>^0_@8B2kGq?%91K)zLz?a~2@EK@;0}+tm
zb?_Rv3^u{b;Cb*Q`0=z5-+-^dN8m#c0SV54zfKA9C%6TE0-u6UfCSgT1K@t}1M=Pk
zAA<!r1Xsa3;4+wi$H1eYt?eG18;;Bd*Z><~18jf|umLu}2L4+E)Na?X3DJEgdg<Ic
z>AB3*%*l+_uy&W$Hz?JG3KHq$tf>n+w=wkh*Q&aSmfeXl*`}&$N2#f)@2>68IhQsk
zU6RWc+3U-8$T6*4eV1gJ`29M~mCH?HX_4zVCs`C`(RTMsg~=I;6g5^QROsu9BxPEb
z7!2WtF^EQ$ba|-D)PypqqY;faX!L}M-czxg>7+Y3#FdRR<EGR%8b$uPQqGknSu4s^
zscPvk*7;~jiArTtxC=gmJjCK<icL{yt4(Q<NS7I{RE-;Md)uv0nKt7#Z<oPREK6U=
zqSnqS=rBhm4%d5&rq>uZ)|olA$toEm-ucu9zGh2@Hs~g+JHBvqy`EQvdYTTlr&qeM
zWu?1DB5f%`g~hT}+0R0I!CaM2I@IL*;M19kOiKNF?RHXqEE(xSyJbLVsk|URp-HU|
zRTn@z!c@0KrLbfcUQeo|YiecJ+8DJ;*C=<cS_{L)ViB}MBvD}MEKIbm3b_oo_BN;C
ztC;v#rcX^P73);TZ90F4e(gBfe>M0-?b`C$(2hbX3_F~sRidzueXL{@>g(u}i19z0
z*xH_M9!&PHO!jvD*#4o%50kKU@q$DZ$|=%#yT0vgrrgn~jMlr(Ho$X&2j1ndGIP0f
zGgztc9L=1;SO13Y?@_B8jYjZMU(v8yel#TLesx1iF@1Y?Z+|+O`sQO2+FHc!rJZf@
EH-WN&EC2ui

literal 0
HcmV?d00001

diff --git a/.Rakefile.swp b/.Rakefile.swp
new file mode 100644
index 0000000000000000000000000000000000000000..e81b2243f3f435af0af14097fd3bd4bd43828d8f
GIT binary patch
literal 45056
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
RrWXYKU}yAG&MRJ-{y&Pof=U1Y

literal 0
HcmV?d00001

diff --git a/.a.rb.swp b/.a.rb.swp
new file mode 100644
index 0000000000000000000000000000000000000000..99d516cdba2b8b691e0e05de18c4d45702cd882e
GIT binary patch
literal 12288
zcmeI%y~@Hc6oBFAE{fhj)Y;abK@m3>9UT4EkJ#E;s8*Vao8FT*;dMAWcnh}Jj3SQ3
zH_#mNcj$SxkX83@zK}y}AktRLx>vhhgixF4sAAVly^W5yx5CI#;oBXrg;So;*0E#z
zL1LTnHrn}7;CB2taQ{7RD=S`o$i*@O2z()MNW9LdvK;h#-RxAm)s&6;@{0s)MF0T=
z5I_I{1Q0*~fuai}`;s`PMU?YGOf2PN6N_Fa|BnCy2q1s}0tg_000IagfWR*csPuXN
zS{34+e%brKx&J@R+%Mx$I|2wGfB*srAb<b@2q1s}0>u+p?_A-8N^3cl6FDBwl-`IZ
D6i_Qy

literal 0
HcmV?d00001

diff --git a/README.md b/README.md
new file mode 100644
index 0000000..7841edf
--- /dev/null
+++ b/README.md
@@ -0,0 +1,52 @@
+NAME
+----
+  mongoid_grid_fs
+
+SYNOPSIS
+--------
+
+  ````ruby
+
+    require 'mongoid-grid_fs'
+
+    g = GridFs.put anthing_that_respons_to_read
+
+    GridFS.get id
+
+    GridFS.delete id
+
+
+  ````
+
+DESCRIPTION
+-----------
+  mongoid_grid_fs is pure mongoid 3  / moped implementation of the mongodb
+  grid_fs specification
+
+   ref: http://www.mongodb.org/display/DOCS/GridFS+Specification
+
+   it has the following features:
+
+    - implementation is on top of mongoid for portability.  moped (the drive)
+      is barely used
+
+    - simple, REST-like api
+
+    - support for custom namespaces (fs.files vs. image.files)
+
+    - pathnames and io-like objects can be written to the grid
+
+    - auto-unique pathnames are generated (by default) to avoid collisions using #put
+
+        'path/info/a.rb' -> '$object_id/a.rb'
+
+    - #[] and #[]= methods which allow the grid to be used like a giant file
+      hash in the sky
+
+    - supprt for data_uris
+
+      ````eruby
+
+        <%= image_tag :src => file.data_url %>
+
+      ````
diff --git a/Rakefile b/Rakefile
new file mode 100644
index 0000000..eefe0b0
--- /dev/null
+++ b/Rakefile
@@ -0,0 +1,446 @@
+This.name =
+  "GridFs"
+
+This.synopsis =
+  "a mongoid 3/moped compatible implementation of the grid_fs specification"
+
+This.rubyforge_project = 'codeforpeople'
+This.author            = "Ara T. Howard"
+This.email             = "ara.t.howard@gmail.com"
+This.homepage          = "https://github.com/ahoward/#{ This.lib }"
+
+This.setup!
+
+
+
+task :default do
+  puts((Rake::Task.tasks.map{|task| task.name.gsub(/::/,':')} - ['default']).sort)
+end
+
+task :test do
+  This.run_tests!
+end
+
+namespace :test do
+  task(:unit){ This.run_tests!(:unit) }
+  task(:functional){ This.run_tests!(:functional) }
+  task(:integration){ This.run_tests!(:integration) }
+end
+
+def This.run_tests!(which = nil)
+  which ||= '**'
+  test_dir = File.join(This.dir, "test")
+  test_glob ||= File.join(test_dir, "#{ which }/**_test.rb")
+  test_rbs = Dir.glob(test_glob).sort
+        
+  div = ('=' * 119)
+  line = ('-' * 119)
+
+  test_rbs.each_with_index do |test_rb, index|
+    testno = index + 1
+    command = "#{ File.basename(This.ruby) } -I ./lib -I ./test/lib #{ test_rb }"
+
+    puts
+    This.say(div, :color => :cyan, :bold => true)
+    This.say("@#{ testno } => ", :bold => true, :method => :print)
+    This.say(command, :color => :cyan, :bold => true)
+    This.say(line, :color => :cyan, :bold => true)
+
+    system(command)
+
+    This.say(line, :color => :cyan, :bold => true)
+
+    status = $?.exitstatus
+
+    if status.zero? 
+      This.say("@#{ testno } <= ", :bold => true, :color => :white, :method => :print)
+      This.say("SUCCESS", :color => :green, :bold => true)
+    else
+      This.say("@#{ testno } <= ", :bold => true, :color => :white, :method => :print)
+      This.say("FAILURE", :color => :red, :bold => true)
+    end
+    This.say(line, :color => :cyan, :bold => true)
+
+    exit(status) unless status.zero?
+  end
+end
+
+
+task :gemspec do
+  ignore_extensions = ['git', 'svn', 'tmp', /sw./, 'bak', 'gem']
+  ignore_directories = ['pkg', 'db']
+  ignore_files = ['test/log', 'test/db.yml', 'a.rb', 'b.rb'] + Dir['db/*'] + %w'db'
+
+  shiteless = 
+    lambda do |list|
+      list.delete_if do |entry|
+        next unless test(?e, entry)
+        extension = File.basename(entry).split(%r/[.]/).last
+        ignore_extensions.any?{|ext| ext === extension}
+      end
+      list.delete_if do |entry|
+        next unless test(?d, entry)
+        dirname = File.expand_path(entry)
+        ignore_directories.any?{|dir| File.expand_path(dir) == dirname}
+      end
+      list.delete_if do |entry|
+        next unless test(?f, entry)
+        filename = File.expand_path(entry)
+        ignore_files.any?{|file| File.expand_path(file) == filename}
+      end
+    end
+
+  lib         = This.lib
+  object      = This.object
+  version     = This.version
+  files       = shiteless[Dir::glob("**/**")]
+  executables = shiteless[Dir::glob("bin/*")].map{|exe| File.basename(exe)}
+  #has_rdoc    = true #File.exist?('doc')
+  test_files  = test(?e, "test/#{ lib }.rb") ? "test/#{ lib }.rb" : nil
+  summary     = This.summary || This.synopsis || "#{ lib } kicks the ass"
+  description = This.description || summary
+
+  if This.extensions.nil?
+    This.extensions = []
+    extensions = This.extensions
+    %w( Makefile configure extconf.rb ).each do |ext|
+      extensions << ext if File.exists?(ext)
+    end
+  end
+  extensions = [extensions].flatten.compact
+
+# TODO
+  if This.dependencies.nil?
+    dependencies = []
+  else
+    case This.dependencies
+      when Hash
+        dependencies = This.dependencies.values
+      when Array
+        dependencies = This.dependencies
+    end
+  end
+
+  template = 
+    if test(?e, 'gemspec.erb')
+      This.template_for{ IO.read('gemspec.erb') }
+    else
+      This.template_for {
+        <<-__
+          ## <%= lib %>.gemspec
+          #
+
+          Gem::Specification::new do |spec|
+            spec.name = <%= lib.inspect %>
+            spec.version = <%= version.inspect %>
+            spec.platform = Gem::Platform::RUBY
+            spec.summary = <%= lib.inspect %>
+            spec.description = <%= description.inspect %>
+
+            spec.files =\n<%= files.sort.pretty_inspect %>
+            spec.executables = <%= executables.inspect %>
+            
+            spec.require_path = "lib"
+
+            spec.test_files = <%= test_files.inspect %>
+
+            <% dependencies.each do |lib_version| %>
+              spec.add_dependency(*<%= Array(lib_version).flatten.inspect %>)
+            <% end %>
+
+            spec.extensions.push(*<%= extensions.inspect %>)
+
+            spec.rubyforge_project = <%= This.rubyforge_project.inspect %>
+            spec.author = <%= This.author.inspect %>
+            spec.email = <%= This.email.inspect %>
+            spec.homepage = <%= This.homepage.inspect %>
+          end
+        __
+      }
+    end
+
+  FileUtils.mkdir_p(This.pkgdir)
+  gemspec = "#{ lib }.gemspec"
+  open(gemspec, "w"){|fd| fd.puts(template)}
+  This.gemspec = gemspec
+end
+
+task :gem => [:clean, :gemspec] do
+  FileUtils.mkdir_p(This.pkgdir)
+  before = Dir['*.gem']
+  cmd = "gem build #{ This.gemspec }"
+  `#{ cmd }`
+  after = Dir['*.gem']
+  gem = ((after - before).first || after.first) or abort('no gem!')
+  FileUtils.mv(gem, This.pkgdir)
+  This.gem = File.join(This.pkgdir, File.basename(gem))
+end
+
+task :readme do
+  samples = ''
+  prompt = '~ > '
+  lib = This.lib
+  version = This.version
+
+  Dir['sample*/*'].sort.each do |sample|
+    samples << "\n" << "  <========< #{ sample } >========>" << "\n\n"
+
+    cmd = "cat #{ sample }"
+    samples << This.util.indent(prompt + cmd, 2) << "\n\n"
+    samples << This.util.indent(`#{ cmd }`, 4) << "\n"
+
+    cmd = "ruby #{ sample }"
+    samples << This.util.indent(prompt + cmd, 2) << "\n\n"
+
+    cmd = "ruby -e'STDOUT.sync=true; exec %(ruby -I ./lib #{ sample })'"
+    samples << This.util.indent(`#{ cmd } 2>&1`, 4) << "\n"
+  end
+
+  template = 
+    if test(?e, 'readme.erb')
+      This.template_for{ IO.read('readme.erb') }
+    else
+      This.template_for {
+        <<-__
+          NAME
+            #{ lib }
+
+          DESCRIPTION
+
+          INSTALL
+            gem install #{ lib }
+
+          SAMPLES
+            #{ samples }
+        __
+      }
+    end
+
+  open("README", "w"){|fd| fd.puts template}
+end
+
+
+task :clean do
+  Dir[File.join(This.pkgdir, '**/**')].each{|entry| FileUtils.rm_rf(entry)}
+end
+
+
+task :release => [:clean, :gemspec, :gem] do
+  gems = Dir[File.join(This.pkgdir, '*.gem')].flatten
+  raise "which one? : #{ gems.inspect }" if gems.size > 1
+  raise "no gems?" if gems.size < 1
+
+  cmd = "gem push #{ This.gem }"
+  puts cmd
+  puts
+  system(cmd)
+  abort("cmd(#{ cmd }) failed with (#{ $?.inspect })") unless $?.exitstatus.zero?
+
+  #cmd = "rubyforge login && rubyforge add_release #{ This.rubyforge_project } #{ This.lib } #{ This.version } #{ This.gem }"
+  #puts cmd
+  #puts
+  #system(cmd)
+  #abort("cmd(#{ cmd }) failed with (#{ $?.inspect })") unless $?.exitstatus.zero?
+end
+
+
+
+
+
+BEGIN {
+# support for this rakefile
+#
+  $VERBOSE = nil
+
+  require 'erb'
+  require 'fileutils'
+  require 'rbconfig'
+  require 'pp'
+
+# cache a bunch of stuff about this rakefile/environment
+#
+
+  This =
+    Class.new(Hash) do
+
+      def method_missing(method, *args, &block)
+        if method.to_s =~ /=/
+          key = method.to_s.chomp('=')
+          value = block ? block : args.shift
+          self[key] = value
+        else
+          key = method.to_s
+          if block
+            value = block
+            self[key] = value
+          else
+            value = self[key]
+
+            if value.respond_to?(:call)
+              self[key] = value.call()
+            else
+              value
+            end
+          end
+        end
+      end
+
+      def inspect
+        expand!
+        PP.pp(self, '')
+      end
+
+      def expand!
+        keys.each do |key|
+          value = self[key]
+          if value.respond_to?(:call)
+            self[key] = value.call()
+          end
+        end
+      end
+
+    end.new()
+
+  This.file = File.expand_path(__FILE__)
+  This.dir = File.dirname(This.file)
+  This.pkgdir = File.join(This.dir, 'pkg')
+
+# defaults 
+#
+  This.lib do
+    File.basename(Dir.pwd)
+  end
+
+  def This.setup!
+    begin
+      require "./lib/#{ This.lib }"
+    rescue LoadError
+      abort("could not load #{ This.lib }")
+    end
+  end
+
+  This.name do
+    This.name = This.lib.capitalize
+  end
+
+  This.object do
+    begin
+      This.object = eval(This.name)
+    rescue Object
+      abort("could not determine object from #{ This.name }")
+    end
+  end
+
+  This.version do
+    This.object.send(:version)
+  end
+
+  This.dependencies do
+    if This.object.respond_to?(:dependencies)
+      This.object.dependencies
+    end
+  end
+
+  This.ruby do
+    c = Config::CONFIG
+    bindir = c["bindir"] || c['BINDIR']
+    ruby_install_name = c['ruby_install_name'] || c['RUBY_INSTALL_NAME'] || 'ruby'
+    ruby_ext = c['EXEEXT'] || ''
+    File.join(bindir, (ruby_install_name + ruby_ext))
+  end
+
+# some utils
+#
+  This.util = Module.new do
+    def indent(s, n = 2)
+      s = unindent(s)
+      ws = ' ' * n
+      s.gsub(%r/^/, ws)
+    end
+
+    def unindent(s)
+      indent = nil
+      s.each_line do |line|
+        next if line =~ %r/^\s*$/
+        indent = line[%r/^\s*/] and break
+      end
+      indent ? s.gsub(%r/^#{ indent }/, "") : s
+    end
+
+    extend self
+  end
+
+# template support
+#
+  This.template = Class.new do
+    def initialize(&block)
+      @block = block
+      @template = block.call.to_s
+    end
+
+    def expand(b=nil)
+      ERB.new(This.util.unindent(@template)).result((b||@block).binding)
+    end
+
+    alias_method 'to_s', 'expand'
+  end
+
+  def This.template_for(*args, &block)
+    This.template.new(*args, &block)
+  end
+
+# colored console output support
+#
+  This.ansi = {
+    :clear      => "\e[0m",
+    :reset      => "\e[0m",
+    :erase_line => "\e[K",
+    :erase_char => "\e[P",
+    :bold       => "\e[1m",
+    :dark       => "\e[2m",
+    :underline  => "\e[4m",
+    :underscore => "\e[4m",
+    :blink      => "\e[5m",
+    :reverse    => "\e[7m",
+    :concealed  => "\e[8m",
+    :black      => "\e[30m",
+    :red        => "\e[31m",
+    :green      => "\e[32m",
+    :yellow     => "\e[33m",
+    :blue       => "\e[34m",
+    :magenta    => "\e[35m",
+    :cyan       => "\e[36m",
+    :white      => "\e[37m",
+    :on_black   => "\e[40m",
+    :on_red     => "\e[41m",
+    :on_green   => "\e[42m",
+    :on_yellow  => "\e[43m",
+    :on_blue    => "\e[44m",
+    :on_magenta => "\e[45m",
+    :on_cyan    => "\e[46m",
+    :on_white   => "\e[47m"
+  }
+
+  def This.say(something, *args)
+    options = args.last.is_a?(Hash) ? args.pop : {}
+    options[:color] = args.shift.to_s.to_sym unless args.empty?
+    keys = options.keys
+    keys.each{|key| options[key.to_s.to_sym] = options.delete(key)}
+
+    color = options[:color]
+    bold = options.has_key?(:bold)
+
+    parts = [something]
+    parts.unshift(This.ansi[color]) if color
+    parts.unshift(This.ansi[:bold]) if bold
+    parts.push(This.ansi[:clear]) if parts.size > 1
+
+    method = options[:method] || :puts
+
+    Kernel.send(method, parts.join)
+  end
+
+# always run out of the project dir
+#
+  Dir.chdir(This.dir)
+}
diff --git a/lib/.mongoid-grid_fs.rb.swp b/lib/.mongoid-grid_fs.rb.swp
new file mode 100644
index 0000000000000000000000000000000000000000..24c6bf7d9c3c0d08e14569721c919a33d29e3607
GIT binary patch
literal 32768
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

literal 0
HcmV?d00001

diff --git a/lib/mongoid-grid_fs.rb b/lib/mongoid-grid_fs.rb
new file mode 100644
index 0000000..ddb50a5
--- /dev/null
+++ b/lib/mongoid-grid_fs.rb
@@ -0,0 +1,419 @@
+require "mongoid"
+require "mime/types"
+require "digest/md5"
+require "cgi"
+
+class GridFS
+##
+#
+  class << GridFS
+    def version
+      "1.0.0"
+    end
+
+    attr_accessor :namespace
+    attr_accessor :file_model
+    attr_accessor :chunk_model
+
+    def init!
+      GridFS.build_namespace_for(:Fs)
+
+      GridFS.namespace = Fs
+      GridFS.file_model = Fs.file_model
+      GridFS.chunk_model = Fs.chunk_model
+
+      const_set(:File, Fs.file_model)
+      const_set(:Chunk, Fs.chunk_model)
+
+      to_delegate = %w(
+        put
+        get
+        delete
+        find
+        []
+        []=
+      )
+      
+      to_delegate.each do |method|
+        class_eval <<-__
+          def GridFS.#{ method }(*args, &block)
+            ::GridFS::Fs::#{ method }(*args, &block)
+          end
+        __
+      end
+    end
+  end
+
+##
+#
+  def GridFS.namespace_for(prefix)
+    prefix = prefix.to_s.downcase
+    const = "::GridFS::#{ prefix.to_s.camelize }"
+    namespace = const.split(/::/).last
+    const_defined?(namespace) ? const_get(namespace) : build_namespace_for(namespace)
+  end
+
+##
+#
+  def GridFS.build_namespace_for(prefix)
+    prefix = prefix.to_s.downcase
+    const = prefix.camelize
+
+    namespace =
+      Module.new do
+        module_eval(&NamespaceMixin)
+        self
+      end
+
+    const_set(const, namespace)
+
+    file_model = build_file_model_for(namespace)
+    chunk_model = build_chunk_model_for(namespace)
+
+    file_model.namespace = namespace
+    chunk_model.namespace = namespace
+
+    file_model.chunk_model = chunk_model
+    chunk_model.file_model = file_model
+
+    namespace.prefix = prefix
+    namespace.file_model = file_model
+    namespace.chunk_model = chunk_model
+
+    namespace.send(:const_set, :File, file_model)
+    namespace.send(:const_set, :Chunk, chunk_model)
+
+    #at_exit{ file_model.create_indexes rescue nil }
+    #at_exit{ chunk_model.create_indexes rescue nil }
+
+    const_get(const)
+  end
+
+  NamespaceMixin = proc do
+    class << self
+      attr_accessor :prefix
+      attr_accessor :file_model
+      attr_accessor :chunk_model
+
+      def to_s
+        prefix
+      end
+
+      def namespace
+        prefix
+      end
+
+      def put(readable, attributes = {})
+        chunks = []
+        file = file_model.new
+        attributes.to_options!
+
+        if attributes.has_key?(:id)
+          file.id = attributes.delete(:id)
+        end
+
+        if attributes.has_key?(:_id)
+          file.id = attributes.delete(:_id)
+        end
+
+        if attributes.has_key?(:content_type)
+          attributes[:contentType] = attributes.delete(:content_type)
+        end
+
+        if attributes.has_key?(:upload_date)
+          attributes[:uploadDate] = attributes.delete(:upload_date)
+        end
+
+        md5 = Digest::MD5.new
+        length = 0
+        chunkSize = file.chunkSize
+        n = 0
+
+        GridFS.reading(readable) do |io|
+
+          filename =
+            attributes[:filename] ||=
+              [file.id.to_s, GridFS.extract_basename(io)].join('/').squeeze('/')
+
+          content_type =
+            attributes[:contentType] ||=
+              GridFS.extract_content_type(filename) || file.contentType
+
+          while((buf = io.read(chunkSize)))
+            md5 << buf
+            length += buf.size
+            chunk = file.chunks.build
+            chunk.data = binary_for(buf)
+            chunk.n = n
+            n += 1
+            chunk.save!
+            chunks.push(chunk)
+          end
+
+        end
+
+        attributes[:length] ||= length
+        attributes[:uploadDate] ||= Time.now.utc
+        attributes[:md5] ||= md5.hexdigest
+
+        file.update_attributes(attributes)
+
+        file.save!
+        file
+      ensure
+        chunks.each{|chunk| chunk.destroy rescue nil} if $!
+      end
+
+      if defined?(Moped)
+        def binary_for(*buf)
+          Moped::BSON::Binary.new(:generic, buf.join)
+        end
+      else
+        def binary_for(buf)
+          BSON::Binary.new(buf.bytes.to_a)
+        end
+      end
+
+      def get(id)
+        file_model.find(id)
+      end
+
+      def delete(id)
+        file_model.find(id).destroy
+      rescue
+        nil
+      end
+
+      def where(conditions = {})
+        case conditions
+          when String
+            file_model.where(:filename => conditions)
+          else
+            file_model.where(conditions)
+        end
+      end
+
+      def find(*args)
+        where(*args).first
+      end
+
+      def [](filename)
+        file_model.where(:filename => filename.to_s).first
+      end
+
+      def []=(filename, readable)
+        file = self[filename]
+        file.destroy if file
+        put(readable, :filename => filename.to_s)
+      end
+
+    # TODO - opening with a mode = 'w' should return a GridIO::IOProxy
+    # implementing a StringIO-like interface
+    #
+      def open(filename, mode = 'r', &block)
+        raise NotImplementedError
+      end
+    end
+  end
+
+##
+#
+  def GridFS.build_file_model_for(namespace)
+    prefix = namespace.name.split(/::/).last.downcase
+    file_model_name = "#{ namespace.name }::File"
+    chunk_model_name = "#{ namespace.name }::Chunk"
+
+    Class.new do
+      include Mongoid::Document
+
+      singleton_class = class << self; self; end
+
+      singleton_class.instance_eval do
+        define_method(:name){ file_model_name }
+        attr_accessor :chunk_model
+        attr_accessor :namespace
+      end
+
+      self.default_collection_name = "#{ prefix }.files"
+
+      field(:filename, :type => String)
+      field(:contentType, :type => String, :default => 'application/octet-stream')
+
+      field(:length, :type => Integer, :default => 0)
+      field(:chunkSize, :type => Integer, :default => (256 * (2 ** 20)))
+      field(:uploadDate, :type => Date, :default => Time.now.utc)
+      field(:md5, :type => String, :default => Digest::MD5.hexdigest(''))
+
+      %w( filename contentType length chunkSize uploadDate md5 ).each do |f|
+        validates_presence_of(f)
+      end
+      validates_uniqueness_of(:filename)
+
+      has_many(:chunks, :class_name => chunk_model_name, :inverse_of => :files, :dependent => :destroy, :order => [:n, :asc])
+
+      index({:filename => 1}, :unique => true) 
+
+      def path
+        filename
+      end
+
+      def basename
+        ::File.basename(filename)
+      end
+
+      def prefix
+        self.class.namespace.prefix
+      end
+
+      def each(&block)
+        chunks.all.order_by([:n, :asc]).each do |chunk|
+          block.call(chunk.to_s)
+        end
+      end
+
+      def data
+        data = ''
+        each{|chunk| data << chunk}
+        data
+      end
+
+      def base64
+        Array(to_s).pack('m')
+      end
+
+      def data_uri(options = {})
+        data = base64.chomp
+        "data:#{ content_type };base64,".concat(data)
+      end
+
+      def bytes(&block)
+        if block
+          each{|data| block.call(data)}
+          length
+        else
+          bytes = []
+          each{|data| bytes.push(*data)}
+          bytes
+        end
+      end
+
+      def close
+        self
+      end
+
+      def content_type
+        contentType
+      end
+
+      def update_date 
+        updateDate
+      end
+
+      def created_at
+        updateDate
+      end
+
+      def namespace
+        self.class.namespace
+      end
+    end
+  end
+
+##
+#
+  def GridFS.build_chunk_model_for(namespace)
+    prefix = namespace.name.split(/::/).last.downcase
+    file_model_name = "#{ namespace.name }::File"
+    chunk_model_name = "#{ namespace.name }::Chunk"
+
+    Class.new do
+      include Mongoid::Document
+
+      singleton_class = class << self; self; end
+
+      singleton_class.instance_eval do
+        define_method(:name){ chunk_model_name }
+        attr_accessor :file_model
+        attr_accessor :namespace
+      end
+
+      self.default_collection_name = "#{ prefix }.chunks"
+
+      field(:n, :type => Integer, :default => 0)
+      field(:data, :type => Moped::BSON::Binary)
+
+      belongs_to(:file, :foreign_key => :files_id, :class_name => file_model_name)
+
+      index({:files_id => 1, :n => -1}, :unique => true) 
+
+      def namespace
+        self.class.namespace
+      end
+
+      def to_s
+        data.data
+      end
+
+      alias_method 'to_str', 'to_s'
+    end
+  end
+
+##
+#
+  def GridFS.reading(arg, &block)
+    if arg.respond_to?(:read)
+      rewind(arg) do |io|
+        block.call(io)
+      end
+    else
+      open(arg.to_s) do |io|
+        block.call(io)
+      end
+    end
+  end
+
+  def GridFS.rewind(io, &block)
+    begin
+      pos = io.pos
+      io.flush
+      io.rewind
+    rescue
+      nil
+    end
+
+    begin
+      block.call(io)
+    ensure
+      begin
+        io.pos = pos
+      rescue
+        nil
+      end
+    end
+  end
+
+  def GridFS.extract_basename(object)
+    filename = nil
+    [:original_path, :original_filename, :path, :filename, :pathname].each do |msg|
+      if object.respond_to?(msg)
+        filename = object.send(msg)
+        break
+      end
+    end
+    filename ? cleanname(filename) : nil
+  end
+
+  def GridFS.extract_content_type(filename)
+    content_type = MIME::Types.type_for(::File.basename(filename.to_s)).first
+    content_type.to_s if content_type
+  end
+
+  def GridFS.cleanname(pathname)
+    basename = ::File.basename(pathname.to_s)
+    CGI.unescape(basename).gsub(%r/[^0-9a-zA-Z_@)(~.-]/, '_').gsub(%r/_+/,'_')
+  end
+end
+
+GridFs = GridFS
+
+GridFS.init!
diff --git a/mongoid-grid_fs.gemspec b/mongoid-grid_fs.gemspec
new file mode 100644
index 0000000..235c966
--- /dev/null
+++ b/mongoid-grid_fs.gemspec
@@ -0,0 +1,36 @@
+## mongoid-grid_fs.gemspec
+#
+
+Gem::Specification::new do |spec|
+  spec.name = "mongoid-grid_fs"
+  spec.version = "1.0.0"
+  spec.platform = Gem::Platform::RUBY
+  spec.summary = "mongoid-grid_fs"
+  spec.description = "a mongoid 3/moped compatible implementation of the grid_fs specification"
+
+  spec.files =
+["README.md",
+ "Rakefile",
+ "lib",
+ "lib/mongoid-grid_fs.rb",
+ "mongoid-grid_fs.gemspec",
+ "test",
+ "test/helper.rb",
+ "test/mongoid-grid_fs_test.rb",
+ "test/testing.rb"]
+
+  spec.executables = []
+  
+  spec.require_path = "lib"
+
+  spec.test_files = nil
+
+  
+
+  spec.extensions.push(*[])
+
+  spec.rubyforge_project = "codeforpeople"
+  spec.author = "Ara T. Howard"
+  spec.email = "ara.t.howard@gmail.com"
+  spec.homepage = "https://github.com/ahoward/mongoid-grid_fs"
+end
diff --git a/pkg/mongoid-grid_fs-1.0.0.gem b/pkg/mongoid-grid_fs-1.0.0.gem
new file mode 100644
index 0000000000000000000000000000000000000000..1e59dcbdf284d712f84fc45131ed4dd6f274d483
GIT binary patch
literal 12288
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
aAn^a%7W&)!Zv_5E;BN%}M&SQL1pW<RcQpzC

literal 0
HcmV?d00001

diff --git a/test/.helper.rb.swp b/test/.helper.rb.swp
new file mode 100644
index 0000000000000000000000000000000000000000..181a7a3b499448d9a6f12023c797b62d92ac7b65
GIT binary patch
literal 12288
zcmeI&v2N2q7zgmLY#=D8yub&oa9TBXp%R4%1Z##+L<Nl2**?1`Twl1mfP|{@A}}#9
zvG5QK@DPXro`cUxj8KMVL`8o~|6I=Z`F#FumM`0RHXQL@yi0OiA-etR;^XYwbNca_
zNFCbO$`$R%sYhOp<J#t`KDCPIWIkcyU7l1XBwhc=HkCC+zjCHXOP>VoLvpC=v39Y`
zmduJ_2tZ(|z$BFYJC|tp*3F%^cK!M_zPk2w>18N@00bZa0SG_<0uX=z1pXg^FkYdz
z@;K+_kF+*#R~FiN7Yzg;009U<00Izz00bZa0SG_<0%uS_$>;qCt3)3p?f3ug{r~4>
zqOX$ol6R65$rH&V$w)Gg+?8xdE=bNxzRMh6B%dT7CDS?2pb3@?0SG_<0uX=z1Rwwb
z2tWV=|3pAH1u@Tlnf*j|h4;3UtNb?K$YkI7i%l73eps4XH|j|9eeV9sK%q-EjR{88
z=8f)kBip<%g_NogT&nV1dv6^Nx>Cw(<vkw^_xT<l1ZSFRxKHHt%ZYKCBR@T5Y(z9$
zWNw?%RIxOT&O;h(FIw2)p0+#OqfHvkHomu|a>YbuD=Z(+ddGimkvd(gU|z|+;y9^I
mmMlyso8+TzJ%1IqH<86gw9fslz6j>FkUkH1x*51VNxuOXE2h!_

literal 0
HcmV?d00001

diff --git a/test/.mongoid-grid_fs_test.rb.swp b/test/.mongoid-grid_fs_test.rb.swp
new file mode 100644
index 0000000000000000000000000000000000000000..d1922d9468b5d1f58eac10d630470c018a0a06f9
GIT binary patch
literal 12288
zcmeI2U5MON6vyu>wY499>!aT8ATuM~%(m6Gj83bzU0JYQaa*O`t|2qInN6F?jY+0E
z?e4Zdh#-nSNCgopN<ZEde9}k378De*iav<6h1M3V;DfK~|0cPa%txn1L{#p;k0dwu
z<DCCJ=OoLfI{M7`Ho9J0OYpmmkQ;wl{?xiN&ysT=5@O8oS;IHQoq@la<!KJD8P337
zgd9pHECqh8RJX&Dyl!x}&TVs~?%Sqr1*MP$VX3Q87mb=<y~Y~qwo*VT&_{u0XpL-G
zLDsHWJu2?zhF8)%@7UR=qiRwLC<T-PN&%&SQa~x76i^B%1^%xJgx(N24Cii09DE}=
z4s{)qOLb5RC<T-PN&%&SQa~x76i^B%1(X6x0i}Ra;6JE<fq(D6g+Km>7QuM@|6l(7
zfALmAE`T%OEAS=w1RMh|ffvAGFb@s_3otMN9s<k3GI0JDLe7CB;5o1cJOGMdDY&$P
zke|RwZ~`0#vtU2)00%DE2W+qt>;N0VUEtT{gj@!fz<F>E{0M#kr@*J+eefbMz$Wn9
zGD5C^pTR|N0h|YC!D(;`d;s1C^I#6_2D`vYK*13Bd?_KHfs^0_;NUUvD7X*Y3;wv7
zkl(>s@ICkrd;`7)AA^s;d!Pk&f*oKKECGwb=_RlS90hNJBj9!L8h8b~3^>>Yis15M
z*aO}HN5QM04lJ+*YzDW3Z*PJf;9XDyRj>i92ls%x!4<^B7vMNJ23o)adw~sVpbB&_
z4fcSi!6vW_ECNwn;i!H}fq#ht%ryz6tn(1HQF^~WPxs8u<>u()lM~y^<%#NERtv{X
z&1JJ%$n`)A?1PLhEYNwIH(Hp-WESO7FC8B*`HXlz4>5+Ju;xfEhjKy1Qpthh7q2YN
zj38isI7e%|>4vmYp-<oosIj129<v>$#jOissQAgwZlGDXtv9&IoTL+mu3jKfw`@PJ
z8B$#z8-H@EuG2pE`^__&E|^%=$Ed+3nfOx6=LdAdaj<BwRkfL>yDv50aiEsXUEMVr
zOlXjYgHe|t-_PdEX!;1<7JoWcE^pzrW`jY+ek*qP*>^$FqyKvCvDdwv=QGQ0CB6tJ
z5)Isd$}QG}w}EHWm~L^uP<Df2)Jc5h1_jt`o|-%!*BdTzl*A$p(9ycOj>!yd-w;Q=
zx?qB<=#q?2ozOBaTd9t*GsqC5>4cF(6rt{htR;Mu0-!rw?aGyYSyI<bBQ*4;ZwqPD
z^Hkonr9y|rc^PROE$4=Mc)&y2K3p{dw(h}I!*JKF8DSy5F3JsxFR@8e^(fn?HSEy7
zLcWnNLT%pgl8x+`wL<G+x)8w^Eh8tZV;-5aiC%RU7HqSahP7>W_nAy`-!bsDBW}k@
z+bbjtiPjWK3STKy=@hb`f;FERs7%^H=JQSMxJ;UbEmp{UIzp=qQOTqyajOj7Y;{U|
zB!w*YbILQqndxY^q9m|5uNr=DHfMWd@yYQCQD+Nc^eUQ9MhUeN*<-8FGafj|kj^a;
zRty`S=h)bE)S6Oj#BWv)45u3*_bCoB8D8y`d-pQ-5w-+2r-o}LHYLre$>MIeXJWsK
zR5}&yUWLMUY>ruw<vK10lnOC0L*Br*ulY=g$YxbG7^bEpYo?|v*OykhZ`c6~3hhd|
z)%UrNXOOI@+j%&K=aX5SOMKM2!&s`9L^&QyEMy&l-m72FB!5pX<l@Dz<@-Np546e{
zgPjuPJle<Jx?YdUt$YrO(i@$p!PH~*q=qMa8ZxVBIUQ5kNacAZfn<{iC=pmC+qHP9
zJG5qPgq+cyEVBQqCdcvH4q&-PyUNM%_{%vdr=*ob(Hk1-diIrzF3=K1o2cHgV06#!
zdAq?|0}?ovPR^XsD4nH3$HZHhye_1DBPnRAFT|8d8{HXPtaI40OhB}&bd)?O|C`0z
zk(POfiYAqJBa=FB;?e6FK1&~>JMao&yY(blqt^(ZJ>Rr_hSyUE^>06;`5EST%+HfQ
E0kL)3^#A|>

literal 0
HcmV?d00001

diff --git a/test/.testing.rb.swp b/test/.testing.rb.swp
new file mode 100644
index 0000000000000000000000000000000000000000..871665bfcf65fcd13b45c3f10c89fd887297f4b4
GIT binary patch
literal 16384
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

literal 0
HcmV?d00001

diff --git a/test/helper.rb b/test/helper.rb
new file mode 100644
index 0000000..03da677
--- /dev/null
+++ b/test/helper.rb
@@ -0,0 +1,18 @@
+# -*- encoding : utf-8 -*-
+require_relative 'testing'
+require_relative '../lib/mongoid-grid_fs.rb'
+
+Mongoid.configure do |config|
+  config.connect_to('mongoid-grid_fs_test')
+end
+
+require 'stringio'
+
+class SIO < StringIO
+  attr_accessor :filename
+
+  def initialize(filename, *args, &block)
+    @filename = filename
+    super(*args, &block)
+  end
+end
diff --git a/test/mongoid-grid_fs_test.rb b/test/mongoid-grid_fs_test.rb
new file mode 100644
index 0000000..60f63c7
--- /dev/null
+++ b/test/mongoid-grid_fs_test.rb
@@ -0,0 +1,147 @@
+require_relative 'helper'
+
+Testing GridFs do
+##
+#
+  prepare do
+    GridFS::File.destroy_all
+    GridFS::Chunk.destroy_all
+  end
+
+##
+#
+  context '#put' do
+
+    test 'default' do
+      filename = __FILE__
+      basename = File.basename(filename)
+
+      g = assert{ GridFS.put(filename) }
+
+      assert{ g.filename =~ %r| #{ object_id_re } / #{ basename } \Z|imox }
+      assert{ g.content_type == "application/x-ruby" }
+      assert{ g.data == IO.read(filename) }
+    end
+
+    test 'with a :filename' do
+      filename = 'path/info/a.rb'
+
+      g = assert{ GridFS.put(__FILE__, :filename => filename) }
+
+      assert{ g.filename == filename }
+    end
+
+  end
+
+
+##
+#
+  context '#get' do
+
+    test 'default' do
+      id = assert{ GridFS::File.last.id }
+      g = assert{ GridFs.get(id) }
+    end
+
+  end
+
+##
+#
+  context '#delete' do
+
+    test 'default' do
+      id = assert{ GridFS::File.last.id }
+      g = assert{ GridFs.get(id) }
+      assert{ GridFs.delete(id) }
+      assert_raises( Mongoid::Errors::DocumentNotFound){ GridFs.get(id) }
+    end
+
+  end
+
+##
+#
+  context '[] and []=' do
+
+    test 'default' do
+      path = 'a.rb'
+      data = IO.read(__FILE__)
+
+      sio = SIO.new(path, data) 
+
+      g = assert{ GridFs[path] = sio and GridFs[path] }
+
+      assert{ g.data == data }
+      assert{ g.content_type == "application/x-ruby" }
+
+      before = GridFs::File.count
+
+      assert{ GridFs[path] = SIO.new(path, 'foobar') }
+      assert{ GridFs[path].data == 'foobar' }
+
+      after = GridFs::File.count
+
+      created = after - before
+
+      assert{ created.zero? }
+    end
+
+##
+#
+  context 'data uris' do
+
+    test 'default' do
+      id = assert{ GridFS::File.last.id }
+      g = assert{ GridFs.get(id) }
+
+      content_type = g.content_type
+      base64 = [g.to_s].pack('m').chomp
+
+      data_uri = "data:#{ content_type };base64,".concat(base64)
+
+      assert{ g.data_uri == data_uri }
+    end
+
+  end
+
+##
+#
+  context 'namespaces' do
+    test 'default' do
+      assert{ GridFs.namespace.prefix == 'fs' }
+      assert{ GridFs.file_model.collection_name == 'fs.files' }
+      assert{ GridFs.chunk_model.collection_name == 'fs.chunks' }
+    end
+
+    test 'new' do
+      ns = GridFs.namespace_for(:ns)
+
+      assert{ ns.prefix == 'ns' }
+
+      assert{ ns.file_model < Mongoid::Document }
+      assert{ ns.file_model.collection_name == 'ns.files' }
+
+      assert{ ns.chunk_model < Mongoid::Document }
+      assert{ ns.chunk_model.collection_name == 'ns.chunks' }
+
+      assert{ ns.file_model.destroy_all }
+
+      count = GridFs::File.count
+
+      assert{ ns.file_model.count == 0}
+      assert{ ns.put __FILE__ }
+      assert{ ns.file_model.count == 1}
+
+      assert{ count == GridFs::File.count }
+    end
+  end
+
+  end
+
+##
+#
+
+protected
+  def object_id_re
+    %r| \w{#{ BSON::ObjectId.new.to_s.size }} |iomx
+  end
+end
diff --git a/test/testing.rb b/test/testing.rb
new file mode 100644
index 0000000..945d01e
--- /dev/null
+++ b/test/testing.rb
@@ -0,0 +1,196 @@
+# -*- encoding : utf-8 -*-
+require 'test/unit'
+
+testdir = File.expand_path(File.dirname(__FILE__))
+rootdir = File.dirname(testdir)
+libdir = File.join(rootdir, 'lib')
+
+STDOUT.sync = true
+
+$:.unshift(testdir) unless $:.include?(testdir)
+$:.unshift(libdir) unless $:.include?(libdir)
+$:.unshift(rootdir) unless $:.include?(rootdir)
+
+class Testing
+  class Slug < ::String
+    def Slug.for(*args)
+      string = args.flatten.compact.join('-')
+      words = string.to_s.scan(%r/\w+/)
+      words.map!{|word| word.gsub %r/[^0-9a-zA-Z_-]/, ''}
+      words.delete_if{|word| word.nil? or word.strip.empty?}
+      new(words.join('-').downcase)
+    end
+  end
+  
+  class Context
+    attr_accessor :name
+
+    def initialize(name, *args)
+      @name = name
+    end
+
+    def to_s
+      Slug.for(name)
+    end
+  end
+end
+
+def Testing(*args, &block)
+  Class.new(::Test::Unit::TestCase) do
+
+  ## class methods
+  #
+    class << self
+      def contexts
+        @contexts ||= []
+      end
+
+      def context(*args, &block)
+        return contexts.last if(args.empty? and block.nil?)
+
+        context = Testing::Context.new(*args)
+        contexts.push(context)
+
+        begin
+          block.call(context)
+        ensure
+          contexts.pop
+        end
+      end
+
+      def slug_for(*args)
+        string = [context, args].flatten.compact.join('-')
+        words = string.to_s.scan(%r/\w+/)
+        words.map!{|word| word.gsub %r/[^0-9a-zA-Z_-]/, ''}
+        words.delete_if{|word| word.nil? or word.strip.empty?}
+        words.join('-').downcase.sub(/_$/, '')
+      end
+
+      def name() const_get(:Name) end
+
+      def testno()
+        '%05d' % (@testno ||= 0)
+      ensure
+        @testno += 1
+      end
+
+      def testing(*args, &block)
+        method = ["test", testno, slug_for(*args)].delete_if{|part| part.empty?}.join('_')
+        define_method(method, &block)
+      end
+
+      def test(*args, &block)
+        testing(*args, &block)
+      end
+
+      def setup(&block)
+        define_method(:setup, &block) if block
+      end
+
+      def teardown(&block)
+        define_method(:teardown, &block) if block
+      end
+
+      def prepare(&block)
+        @prepare ||= []
+        @prepare.push(block) if block
+        @prepare
+      end
+
+      def cleanup(&block)
+        @cleanup ||= []
+        @cleanup.push(block) if block
+        @cleanup
+      end
+    end
+
+  ## configure the subclass!
+  #
+    const_set(:Testno, '0')
+    slug = slug_for(*args).gsub(%r/-/,'_')
+    name = ['TESTING', '%03d' % const_get(:Testno), slug].delete_if{|part| part.empty?}.join('_')
+    name = name.upcase!
+    const_set(:Name, name)
+    const_set(:Missing, Object.new.freeze)
+
+  ## instance methods
+  #
+    alias_method('__assert__', 'assert')
+
+    def assert(*args, &block)
+      if args.size == 1 and args.first.is_a?(Hash)
+        options = args.first
+        expected = getopt(:expected, options){ missing }
+        actual = getopt(:actual, options){ missing }
+        if expected == missing and actual == missing
+          actual, expected, *ignored = options.to_a.flatten
+        end
+        expected = expected.call() if expected.respond_to?(:call)
+        actual = actual.call() if actual.respond_to?(:call)
+        assert_equal(expected, actual)
+      end
+
+      if block
+        label = "assert(#{ args.join(' ') })"
+        result = nil
+        assert_nothing_raised{ result = block.call }
+        __assert__(result, label)
+        result
+      else
+        result = args.shift
+        label = "assert(#{ args.join(' ') })"
+        __assert__(result, label)
+        result
+      end
+    end
+
+    def missing
+      self.class.const_get(:Missing)
+    end
+
+    def getopt(opt, hash, options = nil, &block)
+      [opt.to_s, opt.to_s.to_sym].each do |key|
+        return hash[key] if hash.has_key?(key)
+      end
+      default =
+        if block
+          block.call
+        else
+          options.is_a?(Hash) ? options[:default] : nil
+        end
+      return default
+    end
+
+    def subclass_of exception
+      class << exception
+        def ==(other) super or self > other end
+      end
+      exception
+    end
+
+  ##
+  #
+    module_eval(&block)
+
+    self.setup()
+    self.prepare.each{|b| b.call()}
+
+    at_exit{ 
+      self.teardown()
+      self.cleanup.each{|b| b.call()}
+    }
+
+    self
+  end
+end
+
+
+if $0 == __FILE__
+
+  Testing 'Testing' do
+    testing('foo'){ assert true }
+    test{ assert true }
+    p instance_methods.grep(/test/)
+  end
+
+end