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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�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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