mongomapper_ext 0.1.5 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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