fixed some serious issues but left some for tomorrow (validations aren't working right)

This commit is contained in:
Matt Aimonetti 2009-02-10 02:15:39 -08:00
parent bc47e72ae0
commit e448112ff6
8 changed files with 89 additions and 48 deletions

View file

@ -48,6 +48,19 @@ module CouchRest
module Validation module Validation
def self.included(base) def self.included(base)
base.cattr_accessor(:auto_validation)
base.class_eval <<-EOS, __FILE__, __LINE__
# Turn off auto validation by default
@@auto_validation = false
# Force the auto validation for the class properties
# This feature is still not fully ported over,
# test are lacking, so please use with caution
def self.auto_validate!
self.auto_validation = true
end
EOS
base.extend(ClassMethods) base.extend(ClassMethods)
base.class_eval <<-EOS, __FILE__, __LINE__ base.class_eval <<-EOS, __FILE__, __LINE__
if method_defined?(:_run_save_callbacks) if method_defined?(:_run_save_callbacks)
@ -164,7 +177,7 @@ module CouchRest
context = opts.delete(:when) if opts.has_key?(:when) context = opts.delete(:when) if opts.has_key?(:when)
context = opts.delete(:group) if opts.has_key?(:group) context = opts.delete(:group) if opts.has_key?(:group)
opts[:context] = context opts[:context] = context
opts.mergs!(defaults) unless defaults.nil? opts.merge!(defaults) unless defaults.nil?
opts opts
end end
@ -197,7 +210,7 @@ module CouchRest
# #
def add_validator_to_context(opts, fields, klazz) def add_validator_to_context(opts, fields, klazz)
fields.each do |field| fields.each do |field|
validator = klazz.new(field, opts) validator = klazz.new(field.to_sym, opts)
if opts[:context].is_a?(Symbol) if opts[:context].is_a?(Symbol)
unless validators.context(opts[:context]).include?(validator) unless validators.context(opts[:context]).include?(validator)
validators.context(opts[:context]) << validator validators.context(opts[:context]) << validator

View file

@ -14,11 +14,14 @@ module CouchRest
# Same as CouchRest::Document but with properties and validations # Same as CouchRest::Document but with properties and validations
class ExtendedDocument < Document class ExtendedDocument < Document
include CouchRest::Callbacks include CouchRest::Callbacks
include CouchRest::Mixins::DocumentQueries include CouchRest::Mixins::DocumentQueries
include CouchRest::Mixins::Properties
include CouchRest::Mixins::Views include CouchRest::Mixins::Views
include CouchRest::Mixins::DesignDoc include CouchRest::Mixins::DesignDoc
def self.inherited(subklass)
subklass.send(:include, CouchRest::Mixins::Properties)
end
# Callbacks # Callbacks
define_callbacks :save define_callbacks :save
define_callbacks :destroy define_callbacks :destroy
@ -38,8 +41,8 @@ module CouchRest
# decent time format by default. See Time#to_json # decent time format by default. See Time#to_json
def self.timestamps! def self.timestamps!
class_eval <<-EOS, __FILE__, __LINE__ class_eval <<-EOS, __FILE__, __LINE__
property(:updated_at, :read_only => true, :cast_as => 'Time') property(:updated_at, :read_only => true, :cast_as => 'Time', :auto_validation => false)
property(:created_at, :read_only => true, :cast_as => 'Time') property(:created_at, :read_only => true, :cast_as => 'Time', :auto_validation => false)
save_callback :before do |object| save_callback :before do |object|
object['updated_at'] = Time.now object['updated_at'] = Time.now
@ -115,7 +118,7 @@ module CouchRest
# Overridden to set the unique ID. # Overridden to set the unique ID.
# Returns a boolean value # Returns a boolean value
def save_without_callbacks(bulk = false) def save_without_callbacks(bulk = false)
raise ArgumentError, "a document requires database to be saved to" unless database raise ArgumentError, "a document requires a database to be saved to" unless database
set_unique_id if new_document? && self.respond_to?(:set_unique_id) set_unique_id if new_document? && self.respond_to?(:set_unique_id)
result = database.save_doc(self, bulk) result = database.save_doc(self, bulk)
result["ok"] == true result["ok"] == true

View file

@ -6,22 +6,20 @@ module CouchRest
class Property class Property
# flag letting us know if we already checked the autovalidation settings # flag letting us know if we already checked the autovalidation settings
attr_accessor :autovalidation_check attr_accessor :autovalidation_check
@@autovalidation_check = false
end end
module Validation module Validation
module AutoValidate module AutoValidate
# Turn off auto validation by default # # Force the auto validation for the class properties
def auto_validation # # This feature is still not fully ported over,
@@auto_validation ||= false # # test are lacking, so please use with caution
end # def auto_validate!
# require 'ruby-debug'
# Force the auto validation for the class properties # debugger
# This feature is still not fully ported over, # auto_validation = true
# test are lacking, so please use with caution # end
def auto_validate!
@@auto_validation = true
end
# adds message for validator # adds message for validator
def options_with_message(base_options, property, validator_name) def options_with_message(base_options, property, validator_name)
@ -93,9 +91,7 @@ module CouchRest
# It is just shortcut if only one validation option is set # It is just shortcut if only one validation option is set
# #
def auto_generate_validations(property) def auto_generate_validations(property)
return unless property.options return unless (property.autovalidation_check && self.auto_validation && (property.options && property.options.has_key?(:auto_validation) && property.options[:auto_validation]))
return unless property.autovalidation_check || auto_validation || (property.options && property.options.has_key?(:auto_validation) && property.options[:auto_validation])
# value is set by the storage system # value is set by the storage system
opts = {} opts = {}
opts[:context] = property.options[:validates] if property.options.has_key?(:validates) opts[:context] = property.options[:validates] if property.options.has_key?(:validates)

View file

@ -40,7 +40,7 @@ module CouchRest
value = target.send(field_name) value = target.send(field_name)
return true if @options[:allow_nil] && value.nil? return true if @options[:allow_nil] && value.nil?
value = value.kind_of?(BigDecimal) ? value.to_s('F') : value.to_s value = value.kind_of?(Float) ? value.to_s('F') : value.to_s
error_message = @options[:message] error_message = @options[:message]
precision = @options[:precision] precision = @options[:precision]

View file

@ -1,19 +1,21 @@
require File.join(File.dirname(__FILE__), '..', '..', 'spec_helper') require File.join(File.dirname(__FILE__), '..', '..', 'spec_helper')
require File.join(FIXTURE_PATH, 'more', 'card') require File.join(FIXTURE_PATH, 'more', 'card')
class WithCastedModelMixin < Hash
include CouchRest::CastedModel
property :name
end
class DummyModel < CouchRest::ExtendedDocument
use_database TEST_SERVER.default_database
raise "Default DB not set" if TEST_SERVER.default_database.nil?
property :casted_attribute, :cast_as => 'WithCastedModelMixin'
end
describe CouchRest::CastedModel do describe CouchRest::CastedModel do
class WithCastedModelMixin < Hash
include CouchRest::CastedModel
property :name
end
class DummyModel < CouchRest::ExtendedDocument
property :casted_attribute, :cast_as => 'WithCastedModelMixin'
end
describe "A non hash class including CastedModel" do describe "A non hash class including CastedModel" do
it "should fail raising and include error" do it "should fail raising and include error" do
lambda do lambda do
class NotAHashButWithCastedModelMixin class NotAHashButWithCastedModelMixin
@ -23,7 +25,6 @@ describe CouchRest::CastedModel do
end.should raise_error end.should raise_error
end end
end end
describe "isolated" do describe "isolated" do
@ -37,7 +38,6 @@ describe CouchRest::CastedModel do
end end
describe "casted as attribute" do describe "casted as attribute" do
before(:each) do before(:each) do
@obj = DummyModel.new(:casted_attribute => {:name => 'whatever'}) @obj = DummyModel.new(:casted_attribute => {:name => 'whatever'})
@casted_obj = @obj.casted_attribute @casted_obj = @obj.casted_attribute
@ -54,6 +54,30 @@ describe CouchRest::CastedModel do
it "should know who casted it" do it "should know who casted it" do
@casted_obj.casted_by.should == @obj @casted_obj.casted_by.should == @obj
end end
end
describe "saved document with casted models" do
before(:each) do
@obj = DummyModel.new(:casted_attribute => {:name => 'whatever'})
@obj.save
end
it "should be able to load with the casted models" do
casted_obj = @obj.casted_attribute
casted_obj.should_not be_nil
casted_obj.should be_an_instance_of(WithCastedModelMixin)
end
it "should have defined getters for the casted model" do
casted_obj = @obj.casted_attribute
casted_obj.name.should == "whatever"
end
it "should have defined setters for the casted model" do
casted_obj = @obj.casted_attribute
casted_obj.name = "test"
casted_obj.name.should == "test"
end
end end

View file

@ -1,15 +1,15 @@
require File.dirname(__FILE__) + '/../../spec_helper' require File.dirname(__FILE__) + '/../../spec_helper'
class WithDefaultValues < CouchRest::ExtendedDocument
use_database TEST_SERVER.default_database
property :preset, :default => {:right => 10, :top_align => false}
property :set_by_proc, :default => Proc.new{Time.now}, :cast_as => 'Time'
property :name
timestamps!
end
describe "ExtendedDocument" do describe "ExtendedDocument" do
class WithDefaultValues < CouchRest::ExtendedDocument
use_database TEST_SERVER.default_database
property :preset, :default => {:right => 10, :top_align => false}
property :set_by_proc, :default => Proc.new{Time.now}, :cast_as => 'Time'
property :name
timestamps!
end
before(:each) do before(:each) do
@obj = WithDefaultValues.new @obj = WithDefaultValues.new
end end
@ -32,6 +32,7 @@ describe "ExtendedDocument" do
it "should define the updated_at and created_at getters and set the values" do it "should define the updated_at and created_at getters and set the values" do
@obj.save @obj.save
obj = WithDefaultValues.get(@obj.id) obj = WithDefaultValues.get(@obj.id)
obj.should be_an_instance_of(WithDefaultValues)
obj.created_at.should be_an_instance_of(Time) obj.created_at.should be_an_instance_of(Time)
obj.updated_at.should be_an_instance_of(Time) obj.updated_at.should be_an_instance_of(Time)
obj.created_at.to_s.should == @obj.updated_at.to_s obj.created_at.to_s.should == @obj.updated_at.to_s

View file

@ -39,7 +39,8 @@ describe "ExtendedDocument properties" do
@card.updated_at.should be_nil @card.updated_at.should be_nil
# :emo: hack for autospec # :emo: hack for autospec
Card.use_database(TEST_SERVER.default_database) if @card.database.nil? Card.use_database(TEST_SERVER.default_database) if @card.database.nil?
@card.save @card.save #.should be_true
p @card.errors
@card.created_at.should_not be_nil @card.created_at.should_not be_nil
@card.updated_at.should_not be_nil @card.updated_at.should_not be_nil
end end
@ -65,14 +66,17 @@ describe "ExtendedDocument properties" do
@invoice.clear @invoice.clear
@invoice.should_not be_valid @invoice.should_not be_valid
@invoice.errors.should_not be_empty @invoice.errors.should_not be_empty
@invoice.errors.on(:client_name).should == ["Client name must not be blank"] @invoice.errors.on(:client_name).first.should == "Client name must not be blank"
@invoice.errors.on(:employee_name).should_not be_empty @invoice.errors.on(:employee_name).should_not be_empty
end end
it "should let you set an error message" do it "should let you set an error message" do
@invoice.location = nil @invoice.location = nil
@invoice.valid? @invoice.valid?
@invoice.errors.on(:location).first.should == "Hey stupid!, you forgot the location" # require 'ruby-debug'
# debugger
# p @invoice.class.validators.map{|v| v.message}.inspect
@invoice.errors.on(:location).should == ["Hey stupid!, you forgot the location"]
end end
it "should validate before saving" do it "should validate before saving" do

View file

@ -1,6 +1,8 @@
class Card < CouchRest::ExtendedDocument class Card < CouchRest::ExtendedDocument
# Include the validation module to get access to the validation methods # Include the validation module to get access to the validation methods
include CouchRest::Validation include CouchRest::Validation
# set the auto_validation before defining the properties
auto_validate!
# Set the default database to use # Set the default database to use
use_database TEST_SERVER.default_database use_database TEST_SERVER.default_database
@ -15,6 +17,4 @@ class Card < CouchRest::ExtendedDocument
# Validation # Validation
validates_present :first_name validates_present :first_name
auto_validate!
end end