mongomapper_ext 0.1.5 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
data/Rakefile CHANGED
@@ -11,7 +11,7 @@ begin
11
11
  gem.homepage = "http://github.com/dcu/mongomapper_ext"
12
12
  gem.authors = ["David A. Cuadrado"]
13
13
 
14
- gem.add_dependency('mongo_mapper', '>= 0.6.10')
14
+ gem.add_dependency('mongo_mapper', '>= 0.7.3')
15
15
  gem.add_dependency('uuidtools', '>= 2.0.0')
16
16
 
17
17
  gem.add_development_dependency("shoulda", ">= 2.10.2")
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.5
1
+ 0.2.0
data/examples/i18n.rb ADDED
@@ -0,0 +1,32 @@
1
+ require './helper'
2
+ require 'mongomapper_ext/types/translation'
3
+
4
+ class TranslationEx
5
+ include MongoMapper::Document
6
+
7
+ key :title, Translation, :default => Translation.build({"es" => "titulo", "en" => "title"}, "en")
8
+ key :body, Translation, :default => Translation.build({"es" => "contenido", "en" => "content"}, "en")
9
+ end
10
+
11
+ TranslationEx.delete_all
12
+ o1 = TranslationEx.create
13
+ o2 = TranslationEx.create
14
+
15
+
16
+ o1.title = "my new title"
17
+ puts o1.title[:es]
18
+
19
+ o1.title[:es] = "mi nuevo titulo"
20
+ o1.save
21
+
22
+ puts "languages: #{o1.title.languages.inspect}"
23
+ puts "default text: #{o1.title}"
24
+
25
+ o1 = TranslationEx.find(o1.id)
26
+ o2 = TranslationEx.find(o2.id)
27
+
28
+ puts o1.to_mongo.inspect
29
+
30
+
31
+ TranslationEx.delete_all
32
+
data/examples/storage.rb CHANGED
@@ -4,19 +4,36 @@ class StorageEx
4
4
  include MongoMapper::Document
5
5
  include MongoMapperExt::Storage
6
6
 
7
- file_key :my_file
7
+ file_key :default_file
8
+
9
+ file_list :attachments
10
+ file_key :an_attachment, :in => :attachments
8
11
  end
9
12
 
10
- file = StringIO.new("file content")
11
- file2 = StringIO.new("file content 2")
13
+ default_file = StringIO.new("default file content")
14
+ custom_attachment = StringIO.new("custom attachment content")
15
+
16
+ attachment = File.open(__FILE__)
17
+
18
+ StorageEx.destroy_all
12
19
 
13
20
  s = StorageEx.new
14
- s.put_file("filename.txt", file)
15
- s.my_file = file2
21
+
22
+ s.default_file = default_file
23
+ s.attachments.put("custom_attachment.txt", custom_attachment)
24
+ s.an_attachment = attachment
16
25
 
17
26
  s.save
18
27
 
28
+
19
29
  from_db = StorageEx.find(s.id)
20
30
 
21
- puts from_db.fetch_file("filename.txt").read
22
- puts from_db.my_file.read
31
+ puts "READ DEFAULT FILE"
32
+ puts from_db.default_file.read
33
+
34
+ puts "READ CUSTOM ATTACHMENT"
35
+ puts from_db.attachments.get("custom_attachment.txt").read
36
+
37
+ puts "READ NAMED ATTACHMENT"
38
+ puts from_db.an_attachment.read.inspect
39
+ puts "MIME TYPE: #{from_db.an_attachment.mime_type}"
@@ -1,42 +1,81 @@
1
1
  module MongoMapperExt
2
- class File < GridFS::GridStore
3
- attr_reader :id, :attributes
4
-
5
- def initialize(owner, attrs = {})
6
- @owner = owner
7
- @id = attrs.delete("_id")
8
-
9
- class_eval do
10
- attrs.each do |k,v|
11
- define_method(k) do
12
- v
13
- end
2
+ class File
3
+ include MongoMapper::EmbeddedDocument
4
+
5
+ key :_id, String
6
+ key :name, String
7
+ key :extension, String
8
+ key :content_type, String
9
+
10
+ alias :filename :name
11
+
12
+ def put(filename, io, options = {})
13
+ options[:_id] = grid_filename
14
+
15
+ options[:metadata] ||= {}
16
+ options[:metadata][:collection] = _root_document.collection.name
17
+
18
+ self.name = filename
19
+ if filename =~ /\.([\w]{2,4})$/
20
+ self.extension = $1
21
+ end
22
+
23
+ if io.kind_of?(String)
24
+ io = StringIO.new(io)
25
+ end
26
+
27
+ if defined?(Magic)
28
+ data = io.read(256) # be nice with memory usage
29
+ self.content_type = options[:content_type] = Magic.guess_string_mime_type(data.to_s)
30
+ self.extension ||= options[:content_type].to_s.split("/").last.split("-").last
31
+
32
+ if io.respond_to?(:rewind)
33
+ io.rewind
34
+ else
35
+ io.seek(0)
14
36
  end
15
37
  end
16
38
 
17
- super(@owner.class.database, attrs["filename"], "r", :root => @owner.collection.name)
39
+ gridfs.delete(grid_filename)
40
+ gridfs.put(io, grid_filename, options).inspect
18
41
  end
19
42
 
20
- def [](name)
21
- @attributes[name.to_s]
43
+ def get
44
+ gridfs.get(grid_filename)
22
45
  end
23
46
 
24
- def self.fetch(owner, filename)
25
- db = owner.class.database
26
- finder = nil
27
- if defined?(MongoMapper::FinderOptions)
28
- finder = MongoMapper::FinderOptions
29
- else
30
- finder = MongoMapper::Query
31
- end
47
+ def grid_filename
48
+ @grid_filename ||= "#{_root_document.collection.name}/#{self.id}"
49
+ end
50
+
51
+ def mime_type
52
+ self.content_type || get.content_type
53
+ end
32
54
 
33
- criteria, options = finder.new(owner.class, :filename => filename, :metadata => {:_id => owner.id}, :limit => 1).to_a
55
+ def size
56
+ get.file_length
57
+ end
34
58
 
35
- obj = db.collection("#{owner.collection.name}.files").find(criteria, options).next_document
59
+ def read(size = nil)
60
+ self.get.read(size)
61
+ end
36
62
 
37
- if obj
38
- self.new(owner, obj)
63
+ def delete
64
+ gridfs.delete(grid_filename)
65
+ end
66
+
67
+ def method_missing(name, *args, &block)
68
+ f = self.get rescue nil
69
+ if f && f.respond_to?(name)
70
+ f.send(name, *args, &block)
71
+ else
72
+ super(name, *args, &block)
39
73
  end
40
74
  end
75
+
76
+ protected
77
+ def gridfs
78
+ _root_document.class.gridfs
79
+ end
41
80
  end
42
81
  end
@@ -0,0 +1,71 @@
1
+ module MongoMapperExt
2
+ class FileList < Hash
3
+ attr_accessor :parent_document
4
+
5
+ def self.to_mongo(value)
6
+ result = {}
7
+ value.each do |k, v|
8
+ result[k] = v.to_mongo
9
+ end
10
+
11
+ result
12
+ end
13
+
14
+ def self.from_mongo(value)
15
+ return value if value.kind_of?(self)
16
+
17
+ result = FileList.new
18
+ (value||{}).each do |k, v|
19
+ result[k] = v.kind_of?(MongoMapperExt::File) ? v : MongoMapperExt::File.new(v)
20
+ end
21
+
22
+ result
23
+ end
24
+
25
+ def put(id, io, metadata = {})
26
+ if !parent_document.new?
27
+ filename = id
28
+ if io.respond_to?(:original_filename)
29
+ filename = io.original_filename
30
+ elsif io.respond_to?(:path) && io.path
31
+ filename = ::File.basename(io.path)
32
+ elsif io.kind_of?(String)
33
+ io = StringIO.new(io)
34
+ end
35
+
36
+ get(id).put(filename, io, metadata)
37
+ else
38
+ (@_pending_files ||= {})[id] = [io, metadata]
39
+ end
40
+ end
41
+
42
+ def files
43
+ self.values
44
+ end
45
+
46
+ def get(id)
47
+ file = self[id]
48
+ if file.nil?
49
+ file = self[id] = MongoMapperExt::File.new
50
+ end
51
+ file._parent_document = parent_document
52
+ file
53
+ end
54
+
55
+ def sync_files
56
+ if @_pending_files
57
+ @_pending_files.each do |filename, data|
58
+ put(filename, data[0], data[1])
59
+ end
60
+ @_pending_files = nil
61
+ end
62
+ end
63
+
64
+ def destroy_files
65
+ self.delete_if do |id, file|
66
+ file._parent_document = parent_document
67
+ file.delete
68
+ end
69
+ end
70
+ end
71
+ end
@@ -1,24 +1,29 @@
1
- function findTags(collection, regex, query, limit) {
2
- var tags = db.eval(
1
+ function find_tags(collection, regex, query, limit) {
2
+ var counts = db.eval(
3
3
  function(collection, regex, query){
4
- var tags = [];
4
+ var counts = {};
5
5
  db[collection].find(query, {"tags":1}).limit(500).forEach(
6
6
  function(p){
7
7
  if ( p.tags ){
8
8
  for ( var i=0; i<p.tags.length; i++ ){
9
9
  var name = p.tags[i];
10
- if(name.match(regex) != null && tags.indexOf(name) == -1)
11
- tags.push(name);
10
+ if(name.match(regex) != null)
11
+ counts[name] = 1 + ( counts[name] || 0 );
12
12
  }
13
13
  }
14
14
  }
15
15
  );
16
- return tags;
16
+ return counts;
17
17
  },
18
18
  collection,
19
19
  regex,
20
20
  query
21
21
  );
22
22
 
23
- return tags.slice(0,limit||30);
23
+ var tags = [];
24
+ for ( var tag in counts ){
25
+ tags.push( { name : tag , count : counts[tag] } )
26
+ }
27
+
28
+ return tags;
24
29
  }
@@ -6,8 +6,6 @@ module MongoMapperExt
6
6
  extend Finder
7
7
 
8
8
  key :slug, String, :index => true
9
-
10
- before_validation_on_create :generate_slug
11
9
  end
12
10
  end
13
11
 
@@ -20,11 +18,16 @@ module MongoMapperExt
20
18
  def generate_slug
21
19
  return false if self[self.class.slug_key].blank?
22
20
  max_length = self.class.slug_options[:max_length]
21
+ min_length = self.class.slug_options[:min_length] || 0
23
22
 
24
23
  slug = self[self.class.slug_key].parameterize.to_s
25
24
  slug = slug[0, max_length] if max_length
26
25
 
27
- if !self.class.slug_options[:unique]
26
+ if slug.size < min_length
27
+ slug = nil
28
+ end
29
+
30
+ if slug && !self.class.slug_options[:unique]
28
31
  key = UUIDTools::UUID.random_create.hexdigest[0,4] #optimize
29
32
  self.slug = key+"-"+slug
30
33
  else
@@ -35,6 +38,14 @@ module MongoMapperExt
35
38
  module ClassMethods
36
39
  def slug_key(key = :name, options = {})
37
40
  @slug_options ||= options
41
+ @@callback_type ||= begin
42
+ type = options[:callback_type] || :before_validation_on_create
43
+
44
+ send(type, :generate_slug)
45
+
46
+ type
47
+ end
48
+
38
49
  @slug_key ||= key
39
50
  end
40
51
  class_eval do
@@ -3,83 +3,144 @@ module MongoMapperExt
3
3
  def self.included(model)
4
4
  model.class_eval do
5
5
  extend ClassMethods
6
- after_create :_sync_pending_files
6
+
7
+ validate :add_mm_storage_errors
8
+ file_list :file_list
7
9
  end
8
10
  end
9
11
 
10
- # FIXME: enable metadata. re http://jira.mongodb.org/browse/SERVER-377
11
- def put_file(filename, io, metadata = {})
12
- if !new?
13
- # :metadata => metadata.deep_merge({:_id => self.id})
14
- GridFS::GridStore.open(self.class.database, filename, "w",
15
- :root => self.collection.name,
16
- :metadata => {:_id => self.id}) do |f|
17
- while data = io.read(256)
18
- f.write(data)
19
- end
20
- io.close
21
- end
22
- else
23
- (@_pending_files ||= {})[filename] = io
24
- end
12
+ def put_file(name, io, options = {})
13
+ file_list = send(options.delete(:in) || :file_list)
14
+ file_list.put(name, io, options)
25
15
  end
26
16
 
27
- def fetch_file(filename)
28
- if !new?
29
- MongoMapperExt::File.fetch(self, filename)
30
- end
17
+ def fetch_file(name, options = {})
18
+ file_list = send(options.delete(:in) || :file_list)
19
+ file_list.get(name)
31
20
  end
32
21
 
33
- def files
34
- finder = nil
35
- if defined?(MongoMapper::FinderOptions)
36
- finder = MongoMapper::FinderOptions
37
- else
38
- finder = MongoMapper::Query
39
- end
22
+ def files(options = {})
23
+ file_list = send(options.delete(:in) || :file_list)
24
+ file_list.files
25
+ end
40
26
 
41
- criteria, options = finder.new(self.class, :metadata => {:_id => self.id}).to_a
42
- coll = self.class.database.collection("#{self.collection.name}.files")
43
- @files = coll.find(criteria, options).map do |a|
44
- MongoMapperExt::File.new(self, a)
45
- end
27
+ def mm_storage_errors
28
+ @mm_storage_errors ||= {}
46
29
  end
47
30
 
48
- protected
49
- def _sync_pending_files
50
- if @_pending_files
51
- @_pending_files.each do |filename, data|
52
- put_file(filename, data)
31
+ def add_mm_storage_errors
32
+ mm_storage_errors.each do |k, msgs|
33
+ msgs.each do |msg|
34
+ self.errors.add(k, msg)
53
35
  end
54
- @_pending_files = nil
55
36
  end
56
37
  end
57
38
 
58
39
  module ClassMethods
59
- def file_key(name)
60
- key "_#{name}", String
40
+ def gridfs
41
+ @gridfs ||= Mongo::Grid.new(self.database)
42
+ end
43
+
44
+ def file_list(name)
45
+ key name, MongoMapperExt::FileList
46
+ define_method(name) do
47
+ list = self[name]
48
+ list.parent_document = self
49
+ list
50
+ end
51
+
52
+ after_create do |doc|
53
+ doc.send(name).sync_files
54
+ doc.save(:validate => false)
55
+ end
56
+
57
+ before_destroy do |doc|
58
+ doc.send(name).destroy_files
59
+ end
60
+ end
61
+
62
+ def file_key(name, opts = {})
63
+ opts[:in] ||= :file_list
64
+
61
65
  define_method("#{name}=") do |file|
62
- file_id = UUIDTools::UUID.random_create.hexdigest
63
- filename = name
66
+ if opts[:max_length] && file.respond_to?(:size) && file.size > opts[:max_length]
67
+ errors.add(name, I18n.t("mongomapper_ext.storage.errors.max_length", :default => "file is too long. max length is #{opts[:max_length]} bytes"))
68
+ end
64
69
 
65
- if file.respond_to?(:original_filename)
66
- filename = file.original_filename
67
- elsif file.respond_to?(:path)
68
- filename = file.path
70
+ if cb = opts[:validate]
71
+ if cb.kind_of?(Symbol)
72
+ send(opts[:validate], file)
73
+ elsif cb.kind_of?(Proc)
74
+ cb.call(file)
75
+ end
69
76
  end
70
77
 
71
- put_file(file_id, file, :original_filename => filename)
72
- self["_#{name}"] = file_id
78
+ if self.errors.on(name).blank?
79
+ send(opts[:in]).get(name.to_s).put(name.to_s, file)
80
+ else
81
+ # we store the errors here because we want to validate before storing the file
82
+ mm_storage_errors.merge!(errors.errors)
83
+ end
73
84
  end
74
85
 
75
86
  define_method(name) do
76
- fetch_file(self["_#{name}"]) if self.class.keys.has_key?("_#{name}")
87
+ send(opts[:in]).get(name.to_s)
77
88
  end
78
89
 
79
90
  define_method("has_#{name}?") do
80
- !self["_#{name}"].blank?
91
+ send(opts[:in]).has_key?(name.to_s)
92
+ end
93
+ end
94
+
95
+ # NOTE: this method will be removed on next release
96
+ def upgrade_file_keys(*keys)
97
+ cname = self.collection_name
98
+
99
+ self.find_each do |object|
100
+ keys.each do |key|
101
+ object.upgrade_file_key(key, false)
102
+ end
103
+
104
+ object.save(:validate => false)
105
+ end
106
+
107
+ self.database.drop_collection(cname+".files")
108
+ self.database.drop_collection(cname+".chunks")
109
+ end
110
+
111
+ private
112
+ end
113
+
114
+ # NOTE: this method will be removed on next release
115
+ def upgrade_file_key(key, save = true)
116
+ cname = self.collection.name
117
+
118
+ files = self.database["#{cname}.files"]
119
+ chunks = self.database["#{cname}.chunks"]
120
+
121
+ fname = self["_#{key}"] rescue nil
122
+ return if fname.blank?
123
+
124
+ begin
125
+ n = Mongo::GridIO.new(files, chunks, fname, "r", :query => {:filename => fname})
126
+
127
+ v = n.read
128
+
129
+ if !v.empty?
130
+ data = StringIO.new(v)
131
+ self.put_file(key, data)
132
+ self["_#{key}"] = nil
133
+
134
+ self.save(:validate => false) if save
81
135
  end
136
+ rescue => e
137
+ puts "ERROR: #{e}"
138
+ puts e.backtrace.join("\t\n")
139
+ return
82
140
  end
141
+
142
+ files.remove(:_id => fname)
143
+ chunks.remove(:_id => fname)
83
144
  end
84
145
  end
85
146
  end
@@ -0,0 +1,51 @@
1
+ class Translation < String
2
+ attr_accessor :keys
3
+
4
+ def initialize(*args)
5
+ super
6
+ @keys = {}
7
+ @keys["default"] = "en"
8
+ end
9
+
10
+ def []=(lang, text)
11
+ @keys[lang.to_s] = text
12
+ end
13
+
14
+ def [](lang)
15
+ @keys[lang.to_s]
16
+ end
17
+
18
+ def languages
19
+ langs = @keys.keys
20
+ langs.delete("default")
21
+ langs
22
+ end
23
+
24
+ def default_language=(lang)
25
+ @keys["default"] = lang
26
+ self.replace(@keys[lang.to_s])
27
+ end
28
+
29
+ def self.build(keys, default = "en")
30
+ tr = self.new
31
+ tr.keys = keys
32
+ tr.default_language = default
33
+ tr
34
+ end
35
+
36
+ def self.to_mongo(value)
37
+ return value.keys if value.kind_of?(self)
38
+
39
+ @keys
40
+ end
41
+
42
+ def self.from_mongo(value)
43
+ return value if value.kind_of?(self)
44
+
45
+ result = self.new
46
+ result.keys = value
47
+ result.default_language = value["default"] || "en"
48
+
49
+ result
50
+ end
51
+ end
@@ -1,17 +1,26 @@
1
1
  $:.unshift File.dirname(__FILE__)
2
2
 
3
- $KCODE = 'u'
3
+ if RUBY_VERSION =~ /^1\.8/
4
+ $KCODE = 'u'
5
+ end
4
6
 
5
7
  require 'mongo_mapper'
6
8
  require 'mongo/gridfs'
7
9
  require 'uuidtools'
8
10
  require 'active_support/inflector'
9
11
 
12
+ begin
13
+ require 'magic'
14
+ rescue LoadError
15
+ $stderr.puts "disabling `magic` support. use 'gem install magic' to enable it"
16
+ end
17
+
10
18
  # types
11
19
  require 'mongomapper_ext/types/open_struct'
12
20
  require 'mongomapper_ext/types/timestamp'
13
21
 
14
22
  # storage
23
+ require 'mongomapper_ext/file_list'
15
24
  require 'mongomapper_ext/file'
16
25
  require 'mongomapper_ext/storage'
17
26
 
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{mongomapper_ext}
8
- s.version = "0.1.5"
8
+ s.version = "0.2.0"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["David A. Cuadrado"]
12
- s.date = %q{2010-03-08}
12
+ s.date = %q{2010-04-11}
13
13
  s.description = %q{MongoMapper extensions}
14
14
  s.email = %q{krawek@gmail.com}
15
15
  s.extra_rdoc_files = [
@@ -25,6 +25,7 @@ Gem::Specification.new do |s|
25
25
  "VERSION",
26
26
  "examples/filter.rb",
27
27
  "examples/helper.rb",
28
+ "examples/i18n.rb",
28
29
  "examples/slugizer.rb",
29
30
  "examples/storage.rb",
30
31
  "examples/tags.rb",
@@ -32,6 +33,7 @@ Gem::Specification.new do |s|
32
33
  "examples/update.rb",
33
34
  "lib/mongomapper_ext.rb",
34
35
  "lib/mongomapper_ext/file.rb",
36
+ "lib/mongomapper_ext/file_list.rb",
35
37
  "lib/mongomapper_ext/filter.rb",
36
38
  "lib/mongomapper_ext/js/find_tags.js",
37
39
  "lib/mongomapper_ext/js/tag_cloud.js",
@@ -40,6 +42,7 @@ Gem::Specification.new do |s|
40
42
  "lib/mongomapper_ext/tags.rb",
41
43
  "lib/mongomapper_ext/types/open_struct.rb",
42
44
  "lib/mongomapper_ext/types/timestamp.rb",
45
+ "lib/mongomapper_ext/types/translation.rb",
43
46
  "lib/mongomapper_ext/update.rb",
44
47
  "mongomapper_ext.gemspec",
45
48
  "test/helper.rb",
@@ -77,6 +80,7 @@ Gem::Specification.new do |s|
77
80
  "examples/tags.rb",
78
81
  "examples/storage.rb",
79
82
  "examples/helper.rb",
83
+ "examples/i18n.rb",
80
84
  "examples/slugizer.rb"
81
85
  ]
82
86
 
@@ -85,20 +89,20 @@ Gem::Specification.new do |s|
85
89
  s.specification_version = 3
86
90
 
87
91
  if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
88
- s.add_runtime_dependency(%q<mongo_mapper>, [">= 0.6.10"])
92
+ s.add_runtime_dependency(%q<mongo_mapper>, [">= 0.7.3"])
89
93
  s.add_runtime_dependency(%q<uuidtools>, [">= 2.0.0"])
90
94
  s.add_development_dependency(%q<shoulda>, [">= 2.10.2"])
91
95
  s.add_development_dependency(%q<jnunemaker-matchy>, ["= 0.4.0"])
92
96
  s.add_development_dependency(%q<mocha>, [">= 0.9.4"])
93
97
  else
94
- s.add_dependency(%q<mongo_mapper>, [">= 0.6.10"])
98
+ s.add_dependency(%q<mongo_mapper>, [">= 0.7.3"])
95
99
  s.add_dependency(%q<uuidtools>, [">= 2.0.0"])
96
100
  s.add_dependency(%q<shoulda>, [">= 2.10.2"])
97
101
  s.add_dependency(%q<jnunemaker-matchy>, ["= 0.4.0"])
98
102
  s.add_dependency(%q<mocha>, [">= 0.9.4"])
99
103
  end
100
104
  else
101
- s.add_dependency(%q<mongo_mapper>, [">= 0.6.10"])
105
+ s.add_dependency(%q<mongo_mapper>, [">= 0.7.3"])
102
106
  s.add_dependency(%q<uuidtools>, [">= 2.0.0"])
103
107
  s.add_dependency(%q<shoulda>, [">= 2.10.2"])
104
108
  s.add_dependency(%q<jnunemaker-matchy>, ["= 0.4.0"])
data/test/models.rb CHANGED
@@ -25,6 +25,9 @@ class Avatar # for Storage and File
25
25
  include MongoMapperExt::Storage
26
26
 
27
27
  file_key :data
28
+
29
+ file_list :alternatives
30
+ file_key :first_alternative, :in => :alternatives
28
31
  end
29
32
 
30
33
  class UserConfig #for OpenStruct
@@ -39,7 +42,7 @@ class BlogPost # for Slug and Filter
39
42
  include MongoMapperExt::Tags
40
43
 
41
44
  filterable_keys :title, :body, :tags, :date
42
- slug_key :title, :max_length => 18
45
+ slug_key :title, :max_length => 18, :min_length => 3, :callback_type => :before_validation
43
46
  language :find_language
44
47
 
45
48
  key :title, String
@@ -31,6 +31,21 @@ class TestSlugizer < Test::Unit::TestCase
31
31
  :body => "HeRe is tHe Body of the bLog pOsT")
32
32
  @blogpost.slug.should =~ /\w+-ultimo-video-canci/
33
33
  end
34
+
35
+ should "not accept slugs with length < :min_length" do
36
+ @blogpost = BlogPost.create(:title => "a",
37
+ :body => "HeRe is tHe Body of the bLog pOsT")
38
+ @blogpost.slug.should be_nil
39
+ end
40
+
41
+ should "update the slug after updating the object" do
42
+ @blogpost = BlogPost.create(:title => "ultimo video/cancion en youtube?",
43
+ :body => "HeRe is tHe Body of the bLog pOsT")
44
+ @blogpost.slug.should =~ /\w+-ultimo-video-canci/
45
+ @blogpost.title = "primer video/cancion en youtube?"
46
+ @blogpost.valid?
47
+ @blogpost.slug.should =~ /\w+-primer-video-canci/
48
+ end
34
49
  end
35
50
 
36
51
  context "finding objects" do
data/test/test_storage.rb CHANGED
@@ -9,13 +9,15 @@ class StorageTest < Test::Unit::TestCase
9
9
 
10
10
  should "store the file" do
11
11
  @avatar.put_file("an_avatar.png", @data)
12
- data = Avatar.find(@avatar.id).fetch_file("an_avatar.png").read
12
+ @avatar.save
13
+ avatar = Avatar.find(@avatar.id)
14
+ data = avatar.fetch_file("an_avatar.png").read
13
15
  data.should == "my avatar image"
14
16
  end
15
17
 
16
- should "close the file after storing" do
18
+ should "not close the file after storing" do
17
19
  @avatar.put_file("an_avatar.png", @data)
18
- @data.should be_closed
20
+ @data.should_not be_closed
19
21
  end
20
22
 
21
23
  context "in attributes" do
@@ -38,9 +40,34 @@ class StorageTest < Test::Unit::TestCase
38
40
  @avatar.fetch_file("an_avatar.png").read.should == "my avatar image"
39
41
  end
40
42
 
41
- should "store not the file if object is new" do
43
+ should "not store the file if object is new" do
42
44
  @avatar.put_file("an_avatar.png", @data)
43
- @avatar.fetch_file("an_avatar.png").should be_nil
45
+ lambda {@avatar.fetch_file("an_avatar.png").read}.should raise_error
46
+ end
47
+ end
48
+
49
+ context "with lists" do
50
+ setup do
51
+ @avatar = Avatar.new
52
+ @alternative = File.new(__FILE__)
53
+ @data = File.read(__FILE__)
54
+ end
55
+ teardown do
56
+ @alternative.close
57
+ end
58
+
59
+ should "store the file" do
60
+ @avatar.first_alternative = @alternative
61
+ @avatar.save
62
+ fromdb = @avatar.reload
63
+ fromdb.first_alternative.read.should == @data
64
+ end
65
+
66
+ should "store the file in the alternative list" do
67
+ @avatar.alternatives.put("an_alternative", @alternative)
68
+ @avatar.save
69
+ @avatar.reload
70
+ @avatar.alternatives.get("an_alternative").read.should == @data
44
71
  end
45
72
  end
46
73
  end
data/test/test_tags.rb CHANGED
@@ -37,8 +37,9 @@ class TestTags < Test::Unit::TestCase
37
37
 
38
38
  should "find tags that start with li" do
39
39
  tags = BlogPost.find_tags(/^li/)
40
- tags.should include("linux")
41
- tags.should include("list")
40
+ [{"name"=>"list", "count"=>2.0}, {"name"=>"linux", "count"=>1.0}].each do |entry|
41
+ tags.should include(entry)
42
+ end
42
43
  tags.size.should == 2
43
44
  end
44
45
 
metadata CHANGED
@@ -4,9 +4,9 @@ version: !ruby/object:Gem::Version
4
4
  prerelease: false
5
5
  segments:
6
6
  - 0
7
- - 1
8
- - 5
9
- version: 0.1.5
7
+ - 2
8
+ - 0
9
+ version: 0.2.0
10
10
  platform: ruby
11
11
  authors:
12
12
  - David A. Cuadrado
@@ -14,7 +14,7 @@ autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
16
 
17
- date: 2010-03-08 00:00:00 -05:00
17
+ date: 2010-04-11 00:00:00 -05:00
18
18
  default_executable:
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
@@ -26,9 +26,9 @@ dependencies:
26
26
  - !ruby/object:Gem::Version
27
27
  segments:
28
28
  - 0
29
- - 6
30
- - 10
31
- version: 0.6.10
29
+ - 7
30
+ - 3
31
+ version: 0.7.3
32
32
  type: :runtime
33
33
  version_requirements: *id001
34
34
  - !ruby/object:Gem::Dependency
@@ -105,6 +105,7 @@ files:
105
105
  - VERSION
106
106
  - examples/filter.rb
107
107
  - examples/helper.rb
108
+ - examples/i18n.rb
108
109
  - examples/slugizer.rb
109
110
  - examples/storage.rb
110
111
  - examples/tags.rb
@@ -112,6 +113,7 @@ files:
112
113
  - examples/update.rb
113
114
  - lib/mongomapper_ext.rb
114
115
  - lib/mongomapper_ext/file.rb
116
+ - lib/mongomapper_ext/file_list.rb
115
117
  - lib/mongomapper_ext/filter.rb
116
118
  - lib/mongomapper_ext/js/find_tags.js
117
119
  - lib/mongomapper_ext/js/tag_cloud.js
@@ -120,6 +122,7 @@ files:
120
122
  - lib/mongomapper_ext/tags.rb
121
123
  - lib/mongomapper_ext/types/open_struct.rb
122
124
  - lib/mongomapper_ext/types/timestamp.rb
125
+ - lib/mongomapper_ext/types/translation.rb
123
126
  - lib/mongomapper_ext/update.rb
124
127
  - mongomapper_ext.gemspec
125
128
  - test/helper.rb
@@ -181,4 +184,5 @@ test_files:
181
184
  - examples/tags.rb
182
185
  - examples/storage.rb
183
186
  - examples/helper.rb
187
+ - examples/i18n.rb
184
188
  - examples/slugizer.rb