Improving handling of mime types, instanciation of documents from the
database, and more dependencies on active_support.
This commit is contained in:
parent
303f0cd1cf
commit
b0d2258bd3
12
history.txt
12
history.txt
|
@ -4,6 +4,15 @@
|
|||
|
||||
* Minor enhancements
|
||||
|
||||
== 1.0.3
|
||||
|
||||
* Minor enhancements
|
||||
* Removed Validation by default, requires too many structure changes (FAIL)
|
||||
* Added support for instantiation of documents read from database as couchrest-type provided (Sam Lown)
|
||||
* Improved attachment handling for detecting file type (Sam Lown)
|
||||
* Removing some monkey patches and relying on active_support for constantize and humanize (Sam Lown)
|
||||
|
||||
|
||||
== 1.0.2
|
||||
|
||||
* Minor enhancements
|
||||
|
@ -14,6 +23,9 @@
|
|||
* Major enhancements
|
||||
* Separated ExtendedDocument from main CouchRest gem (Sam Lown)
|
||||
|
||||
* Minor enhancements
|
||||
* active_support included by default
|
||||
|
||||
== 0.37
|
||||
|
||||
* Minor enhancements
|
||||
|
|
|
@ -8,7 +8,7 @@ module CouchRest
|
|||
# Same as CouchRest::Document but with properties and validations
|
||||
class ExtendedDocument < Document
|
||||
|
||||
VERSION = "1.0.2"
|
||||
VERSION = "1.0.3"
|
||||
|
||||
include CouchRest::Mixins::Callbacks
|
||||
include CouchRest::Mixins::DocumentQueries
|
||||
|
@ -19,7 +19,8 @@ module CouchRest
|
|||
include CouchRest::Mixins::Collection
|
||||
include CouchRest::Mixins::AttributeProtection
|
||||
|
||||
include CouchRest::Validation
|
||||
# Including validation here does not work due to the way inheritance is handled.
|
||||
#include CouchRest::Validation
|
||||
|
||||
def self.subclasses
|
||||
@subclasses ||= []
|
||||
|
@ -48,17 +49,19 @@ module CouchRest
|
|||
|
||||
# Creates a new instance, bypassing attribute protection
|
||||
#
|
||||
#
|
||||
# ==== Returns
|
||||
# a document instance
|
||||
def self.create_from_database(passed_keys={})
|
||||
new(passed_keys, :directly_set_attributes => true)
|
||||
def self.create_from_database(doc = {})
|
||||
base = (doc['couchrest-type'].blank? || doc['couchrest-type'] == self.to_s) ? self : doc['couchrest-type'].constantize
|
||||
base.new(doc, :directly_set_attributes => true)
|
||||
end
|
||||
|
||||
def initialize(passed_keys={}, options={})
|
||||
def initialize(doc = {}, options = {})
|
||||
apply_defaults # defined in CouchRest::Mixins::Properties
|
||||
remove_protected_attributes(passed_keys) unless options[:directly_set_attributes]
|
||||
directly_set_attributes(passed_keys) unless passed_keys.nil?
|
||||
super(passed_keys)
|
||||
remove_protected_attributes(doc) unless options[:directly_set_attributes]
|
||||
directly_set_attributes(doc) unless doc.nil?
|
||||
super(doc)
|
||||
cast_keys # defined in CouchRest::Mixins::Properties
|
||||
unless self['_id'] && self['_rev']
|
||||
self['couchrest-type'] = self.class.to_s
|
||||
|
|
|
@ -2,7 +2,8 @@ module CouchRest
|
|||
module Mixins
|
||||
module ExtendedAttachments
|
||||
|
||||
# creates a file attachment to the current doc
|
||||
# Add a file attachment to the current document. Expects
|
||||
# :file and :name to be included in the arguments.
|
||||
def create_attachment(args={})
|
||||
raise ArgumentError unless args[:file] && args[:name]
|
||||
return if has_attachment?(args[:name])
|
||||
|
@ -52,13 +53,14 @@ module CouchRest
|
|||
|
||||
private
|
||||
|
||||
def get_mime_type(file)
|
||||
::MIME::Types.type_for(file.path).empty? ?
|
||||
'text\/plain' : MIME::Types.type_for(file.path).first.content_type.gsub(/\//,'\/')
|
||||
def get_mime_type(path)
|
||||
type = ::MIME::Types.type_for(path)
|
||||
type.empty? ? nil : type.first.content_type
|
||||
end
|
||||
|
||||
def set_attachment_attr(args)
|
||||
content_type = args[:content_type] ? args[:content_type] : get_mime_type(args[:file])
|
||||
content_type = args[:content_type] ? args[:content_type] : get_mime_type(args[:file].path)
|
||||
content_type ||= (get_mime_type(args[:name]) || 'text/plain')
|
||||
self['_attachments'][args[:name]] = {
|
||||
'content_type' => content_type,
|
||||
'data' => args[:file].read
|
||||
|
|
|
@ -26,7 +26,7 @@ module CouchRest
|
|||
base_type = TrueClass
|
||||
else
|
||||
begin
|
||||
base_type = ::CouchRest.constantize(base_type)
|
||||
base_type = base_type.constantize
|
||||
rescue # leave base type as a string and convert in more/typecast
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,43 +1,6 @@
|
|||
|
||||
module CouchRest
|
||||
|
||||
|
||||
# The CouchRest module methods handle the basic JSON serialization
|
||||
# and deserialization, as well as query parameters. The module also includes
|
||||
# some helpers for tasks like instantiating a new Database or Server instance.
|
||||
class << self
|
||||
|
||||
# extracted from Extlib
|
||||
#
|
||||
# Constantize tries to find a declared constant with the name specified
|
||||
# in the string. It raises a NameError when the name is not in CamelCase
|
||||
# or is not initialized.
|
||||
#
|
||||
# @example
|
||||
# "Module".constantize #=> Module
|
||||
# "Class".constantize #=> Class
|
||||
def constantize(camel_cased_word)
|
||||
unless /\A(?:::)?([A-Z]\w*(?:::[A-Z]\w*)*)\z/ =~ camel_cased_word
|
||||
raise NameError, "#{camel_cased_word.inspect} is not a valid constant name!"
|
||||
end
|
||||
|
||||
Object.module_eval("::#{$1}", __FILE__, __LINE__)
|
||||
end
|
||||
|
||||
# extracted from Extlib
|
||||
#
|
||||
# Capitalizes the first word and turns underscores into spaces and strips _id.
|
||||
# Like titleize, this is meant for creating pretty output.
|
||||
#
|
||||
# @example
|
||||
# "employee_salary" #=> "Employee salary"
|
||||
# "author_id" #=> "Author"
|
||||
def humanize(lower_case_and_underscored_word)
|
||||
lower_case_and_underscored_word.to_s.gsub(/_id$/, "").gsub(/_/, " ").capitalize
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
class Database
|
||||
|
||||
alias :delete_old! :delete!
|
||||
|
|
|
@ -28,7 +28,7 @@ module CouchRest
|
|||
|
||||
def typecast_value(value, klass, init_method)
|
||||
return nil if value.nil?
|
||||
klass = ::CouchRest.constantize(klass) unless klass.is_a?(Class)
|
||||
klass = klass.constantize unless klass.is_a?(Class)
|
||||
if value.instance_of?(klass) || klass == Object
|
||||
value
|
||||
elsif [String, TrueClass, Integer, Float, BigDecimal, DateTime, Time, Date, Class].include?(klass)
|
||||
|
@ -164,7 +164,7 @@ module CouchRest
|
|||
|
||||
# Typecast a value to a Class
|
||||
def typecast_to_class(value)
|
||||
::CouchRest.constantize(value.to_s)
|
||||
value.to_s.constantize
|
||||
rescue NameError
|
||||
value
|
||||
end
|
||||
|
|
|
@ -60,7 +60,7 @@ module CouchRest
|
|||
cattr_writer :default_error_messages
|
||||
|
||||
def self.default_error_message(key, field, *values)
|
||||
field = CouchRest.humanize(field)
|
||||
field = field.to_s.humanize
|
||||
@@default_error_messages[key] % [field, *values].flatten
|
||||
end
|
||||
|
||||
|
|
|
@ -64,7 +64,7 @@ module CouchRest
|
|||
|
||||
error_message = @options[:message] || ValidationErrors.default_error_message(:invalid, field_name)
|
||||
|
||||
field = CouchRest.humanize(field_name)
|
||||
field = field_name.to_s.humanize
|
||||
error_message = error_message.call(field, value) if error_message.respond_to?(:call)
|
||||
|
||||
add_error(target, error_message, field_name)
|
||||
|
|
|
@ -54,7 +54,7 @@ module CouchRest
|
|||
|
||||
# XXX: HACK seems hacky to do this on every validation, probably should
|
||||
# do this elsewhere?
|
||||
field = CouchRest.humanize(field_name)
|
||||
field = field_name.to_s.humanize
|
||||
min = @range ? @range.min : @min
|
||||
max = @range ? @range.max : @max
|
||||
equal = @equal
|
||||
|
|
|
@ -68,6 +68,19 @@ describe "ExtendedDocument attachments" do
|
|||
@obj.create_attachment(:file => @file_ext, :name => @attachment_name, :content_type => @content_type)
|
||||
@obj['_attachments'][@attachment_name]['content_type'].should == @content_type
|
||||
end
|
||||
|
||||
it "should detect the content-type automatically" do
|
||||
@obj.create_attachment(:file => File.open(FIXTURE_PATH + '/attachments/couchdb.png'), :name => "couchdb.png")
|
||||
@obj['_attachments']['couchdb.png']['content_type'].should == "image/png"
|
||||
end
|
||||
|
||||
it "should use name to detect the content-type automatically if no file" do
|
||||
file = File.open(FIXTURE_PATH + '/attachments/couchdb.png')
|
||||
file.stub!(:path).and_return("badfilname")
|
||||
@obj.create_attachment(:file => File.open(FIXTURE_PATH + '/attachments/couchdb.png'), :name => "couchdb.png")
|
||||
@obj['_attachments']['couchdb.png']['content_type'].should == "image/png"
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
describe 'reading, updating, and deleting an attachment' do
|
||||
|
@ -96,7 +109,7 @@ describe "ExtendedDocument attachments" do
|
|||
reloaded_obj.read_attachment(@attachment_name).should == file.read
|
||||
end
|
||||
|
||||
it 'should se the content-type if passed' do
|
||||
it 'should set the content-type if passed' do
|
||||
file = File.open(FIXTURE_PATH + '/attachments/README')
|
||||
@file.should_not == file
|
||||
@obj.update_attachment(:file => file, :name => @attachment_name, :content_type => @content_type)
|
||||
|
|
|
@ -164,6 +164,25 @@ describe "ExtendedDocument" do
|
|||
doc.run_after_save.should be_true
|
||||
end
|
||||
end
|
||||
|
||||
describe "creating a new document from database" do
|
||||
|
||||
it "should instantialize" do
|
||||
doc = Article.create_from_database({'_id' => 'testitem1', '_rev' => 123, 'couchrest-type' => 'Article', 'name' => 'my test'})
|
||||
doc.class.should eql(Article)
|
||||
end
|
||||
|
||||
it "should instantialize of same class if no couchrest-type included from DB" do
|
||||
doc = Article.create_from_database({'_id' => 'testitem1', '_rev' => 123, 'name' => 'my test'})
|
||||
doc.class.should eql(Article)
|
||||
end
|
||||
|
||||
it "should instantialize document of different type" do
|
||||
doc = Article.create_from_database({'_id' => 'testitem2', '_rev' => 123, 'couchrest-type' => 'WithCallBacks', 'name' => 'my test'})
|
||||
doc.class.should eql(WithCallBacks)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
describe "update attributes without saving" do
|
||||
before(:each) do
|
||||
|
|
Loading…
Reference in a new issue