Compare commits

...

24 Commits

Author SHA1 Message Date
Adam Meehan
00ce472d3e Merge pull request #99 from softace/fixing_build
Fix for running tests in non-Australian timezones
2013-06-16 15:22:33 -07:00
Jarl Friis
0d2c7ce554 Fix for running tests in non-Australian timezones 2013-04-30 19:56:19 +02:00
Adam Meehan
3d798697e1 Merge pull request #98 from 907th/master
Range with excluded end passed to :between option should be split into :on_or_after and :before options
2013-04-30 04:45:54 -07:00
Alexey Chernenkov
dc0fdc0340 Range with excluded end passed to :between option should be split into :on_or_after and :before options 2013-04-30 15:37:44 +06:00
Adam Meehan
dd3b6b5514 Merge pull request #95 from will-ob/fix/require-active-model
Require 'active_model'
2013-04-25 22:01:51 -07:00
Will O'Brien
609fafe7bb Require 'active_model'
Apparently classes are lazily required when using autoload. Prompted by
'uninitialized constant ActiveModel::Validations'
2013-04-25 22:42:28 -04:00
Adam Meehan
df9677f5bf timeliness minimum dep 0.3.7 2012-10-15 20:37:05 +11:00
Adam Meehan
b463b4356a Update rdoc require 2012-10-15 08:46:11 +11:00
Adam Meehan
7dd579b0e0 Get rid of this silly constant for nil array value 2012-10-15 08:45:57 +11:00
Adam Meehan
5becd7886b Removing silly class variables from config module 2012-09-14 18:44:35 +10:00
Adam Meehan
2225c747e1 DRYing up some specs 2012-08-26 16:38:00 +10:00
Adam Meehan
a1dfbf5d7d v3.0.14 2012-08-23 18:40:47 +10:00
Adam Meehan
02fbdc6028 Fix for validates :timeliness form to add attributes to plugin set 2012-08-23 18:38:33 +10:00
Adam Meehan
4fe22458d3 Add mongoid appraisals 2012-08-23 18:37:38 +10:00
Adam Meehan
8c698be4c4 v3.0.13 2012-08-21 10:56:46 +10:00
Adam Meehan
091e7ecfa0 Tweak AR specs 2012-08-21 10:53:54 +10:00
Adam Meehan
8168bcbd3a Ignore more lock files 2012-08-19 22:59:40 +10:00
Adam Meehan
973bbfa82c Moving back to plugin cache for ActiveRecord
This simplifies the code a lot and fixes the issues with date and time
colummns when using the plugin parser.

Add appraisals for all rails 3 versions
2012-08-19 22:57:19 +10:00
Adam Meehan
62557e7e04 Allow any validated attribute to pass timezone aware check in AR 2012-08-09 12:53:29 +10:00
Adam Meehan
fd73c4eccd README touch ups 2012-08-09 11:55:53 +10:00
Adam Meehan
7bcdea1738 RSpec config cleanup 2012-07-13 21:43:29 +10:00
Adam Meehan
8898b8686c v3.0.12 2012-06-23 19:06:38 +10:00
Adam Meehan
aad2db8662 Remove unused cargo culted generator method 2012-06-23 18:58:33 +10:00
Adam Meehan
8e08cbf6e4 Fix load order issue for AR extension using Railite 2012-06-23 18:58:01 +10:00
28 changed files with 490 additions and 219 deletions

1
.gitignore vendored
View File

@@ -2,3 +2,4 @@ pkg/
.bundle/ .bundle/
.rvmrc .rvmrc
Gemfile.lock Gemfile.lock
gemfiles/*.lock

27
Appraisals Normal file
View File

@@ -0,0 +1,27 @@
appraise "rails_3_0" do
gem "rails", "~> 3.0.0"
end
appraise "rails_3_1" do
gem "rails", "~> 3.1.0"
end
appraise "rails_3_2" do
gem "rails", "~> 3.2.0"
end
appraise "mongoid_2_1" do
gem "mongoid", "~> 2.1.0"
end
appraise "mongoid_2_2" do
gem "mongoid", "~> 2.2.0"
end
appraise "mongoid_2_3" do
gem "mongoid", "~> 2.3.0"
end
appraise "mongoid_2_4" do
gem "mongoid", "~> 2.4.0"
end

View File

@@ -1,3 +1,13 @@
= 3.0.14 [2012-08-23]
* Fix for using validates :timeliness => {} form to correctly add attributes to timeliness validated attributes.
= 3.0.13 [2012-08-21]
* Fix ActiveRecord issues with using plugin parser by using old way of caching values.
* Allow any ActiveRecord non-column attribute to be validated
= 3.0.12 [2012-06-23]
* Fix load order issue when relying on Railtie to load ActiveRecord extension
= 3.0.11 [2012-04-01] = 3.0.11 [2012-04-01]
* Change dependency on Timeliness version due to a broken release * Change dependency on Timeliness version due to a broken release

View File

@@ -2,13 +2,15 @@ source 'http://rubygems.org'
gemspec gemspec
gem 'rails', '~> 3.2.1' gem 'rails', '~> 3.2.6'
gem 'rspec', '~> 2.8' gem 'rspec', '~> 2.8'
gem 'rspec-rails', '~> 2.8' gem 'rspec-rails', '~> 2.8'
gem 'timecop' gem 'timecop'
gem 'rspec_tag_matchers' gem 'rspec_tag_matchers'
gem 'ruby-debug', :platforms => [:ruby_18, :jruby] gem 'ruby-debug', :platforms => [:ruby_18, :jruby]
gem 'ruby-debug19', :platforms => [:ruby_19] gem 'debugger', :platforms => [:ruby_19]
gem 'appraisal'
gem 'sqlite3'
group :mongoid do group :mongoid do
gem 'mongoid', '~> 2.3.0' gem 'mongoid', '~> 2.3.0'

View File

@@ -1,7 +1,7 @@
= ValidatesTimeliness = ValidatesTimeliness
* Source: http://github.com/adzap/validates_timeliness * Source: http://github.com/adzap/validates_timeliness
* Bugs: http://github.com/adzap/validates_timeliness/issues * Issues: http://github.com/adzap/validates_timeliness/issues
== Description == Description
@@ -18,24 +18,19 @@ If you a looking for the old version for Rails 2.x go here[http://github.com/adz
* Only Rails date/time validation plugin offering complete validation (See ORM/ODM support) * Only Rails date/time validation plugin offering complete validation (See ORM/ODM support)
* Adds extensions to fix Rails date/time select issues (See Extensions)
* Uses extensible date/time parser (Using {timeliness gem}[http://github.com/adzap/timeliness]. See Plugin Parser) * Uses extensible date/time parser (Using {timeliness gem}[http://github.com/adzap/timeliness]. See Plugin Parser)
* Adds extensions to fix Rails date/time select issues (See Extensions)
* Supports I18n for the error messages * Supports I18n for the error messages
* Supports Ruby 1.8.x, 1.9.x and Rubinius. * Supports all the Rubies (that any sane person would be using in production).
== Installation == Installation
As plugin (from master)
rails plugin install git://github.com/adzap/validates_timeliness.git
As gem
# in Gemfile # in Gemfile
gem 'validates_timeliness', '~> 3.0.2' gem 'validates_timeliness', '~> 3.0'
# Run bundler # Run bundler
$ bundle install $ bundle install
@@ -55,12 +50,15 @@ NOTE: You may wish to enable the plugin parser and the extensions to start. Plea
validates_datetime :occurred_at validates_datetime :occurred_at
validates_date :date_of_birth, :before => lambda { 18.years.ago }, validates_date :date_of_birth, :before => lambda { 18.years.ago },
:before_message => "must be at least 18 years old" :before_message => "must be at least 18 years old"
validates_datetime :finish_time, :after => :start_time # Method symbol validates_datetime :finish_time, :after => :start_time # Method symbol
validates_date :booked_at, :on => :create, :on_or_after => :today # See Restriction Shorthand. validates_date :booked_at, :on => :create, :on_or_after => :today # See Restriction Shorthand.
validates_time :booked_at, :between => ['9.00am', '5:00pm']
validates_time :booked_at, :between => ['9:00am', '5:00pm'] # On or after 9:00AM and on or before 5:00PM
validates_time :booked_at, :between => '9:00am'..'5:00pm' # The same as previous example
validates_time :booked_at, :between => '9:00am'...'5:00pm' # On or after 9:00AM and strictly before 5:00PM
validates_time :breakfast_time, :on_or_after => '6:00am', validates_time :breakfast_time, :on_or_after => '6:00am',
:on_or_after_message => 'must be after opening time', :on_or_after_message => 'must be after opening time',
@@ -79,7 +77,7 @@ validation method
validates :date_of_birth, :timeliness => {:on_or_before => lambda { Date.current }, :type => :date} validates :date_of_birth, :timeliness => {:on_or_before => lambda { Date.current }, :type => :date}
end end
# or even on a specific record, per ActiveModel API. or even on a specific record, per ActiveModel API.
@person.validates_date :date_of_birth, :on_or_before => lambda { Date.current } @person.validates_date :date_of_birth, :on_or_before => lambda { Date.current }
@@ -178,8 +176,8 @@ You can also use validation options for custom error messages. The following opt
:after_message :after_message
:on_or_after_message :on_or_after_message
Note: There is no :between_message option. The between error message should be defined using the Note: There is no :between_message option. The between error message should be defined using the :on_or_after and :on_or_before
:on_or_before and :on_or_after messages. (:before in case when :between argument is a Range with excluded high value, see Examples) messages.
It is highly recommended you use the I18n system for error messages. It is highly recommended you use the I18n system for error messages.
@@ -298,4 +296,4 @@ To see the generous people who have contributed code, take a look at the {contri
== License == License
Copyright (c) 2008-2010 Adam Meehan, released under the MIT license Copyright (c) 2008 Adam Meehan, released under the MIT license

View File

@@ -1,9 +1,11 @@
require 'bundler' require 'bundler'
require 'bundler/setup'
require 'appraisal'
Bundler::GemHelper.install_tasks Bundler::GemHelper.install_tasks
Bundler.setup require 'rdoc/task'
require 'rake/rdoctask'
require 'rspec/core/rake_task' require 'rspec/core/rake_task'
desc "Run specs" desc "Run specs"

View File

@@ -0,0 +1,16 @@
# This file was generated by Appraisal
source "http://rubygems.org"
gem "rails", "~> 3.2.6"
gem "rspec", "~> 2.8"
gem "rspec-rails", "~> 2.8"
gem "timecop"
gem "rspec_tag_matchers"
gem "ruby-debug", :platforms=>[:ruby_18, :jruby]
gem "debugger", :platforms=>[:ruby_19]
gem "appraisal"
gem "sqlite3"
gem "mongoid", "~> 2.1.0"
gemspec :path=>"../"

View File

@@ -0,0 +1,16 @@
# This file was generated by Appraisal
source "http://rubygems.org"
gem "rails", "~> 3.2.6"
gem "rspec", "~> 2.8"
gem "rspec-rails", "~> 2.8"
gem "timecop"
gem "rspec_tag_matchers"
gem "ruby-debug", :platforms=>[:ruby_18, :jruby]
gem "debugger", :platforms=>[:ruby_19]
gem "appraisal"
gem "sqlite3"
gem "mongoid", "~> 2.2.0"
gemspec :path=>"../"

View File

@@ -0,0 +1,16 @@
# This file was generated by Appraisal
source "http://rubygems.org"
gem "rails", "~> 3.2.6"
gem "rspec", "~> 2.8"
gem "rspec-rails", "~> 2.8"
gem "timecop"
gem "rspec_tag_matchers"
gem "ruby-debug", :platforms=>[:ruby_18, :jruby]
gem "debugger", :platforms=>[:ruby_19]
gem "appraisal"
gem "sqlite3"
gem "mongoid", "~> 2.3.0"
gemspec :path=>"../"

View File

@@ -0,0 +1,16 @@
# This file was generated by Appraisal
source "http://rubygems.org"
gem "rails", "~> 3.2.6"
gem "rspec", "~> 2.8"
gem "rspec-rails", "~> 2.8"
gem "timecop"
gem "rspec_tag_matchers"
gem "ruby-debug", :platforms=>[:ruby_18, :jruby]
gem "debugger", :platforms=>[:ruby_19]
gem "appraisal"
gem "sqlite3"
gem "mongoid", "~> 2.4.0"
gemspec :path=>"../"

View File

@@ -0,0 +1,15 @@
# This file was generated by Appraisal
source "http://rubygems.org"
gem "rspec", "~> 2.8"
gem "rspec-rails", "~> 2.8"
gem "timecop"
gem "rspec_tag_matchers"
gem "ruby-debug", :platforms=>[:ruby_18, :jruby]
gem "debugger", :platforms=>[:ruby_19]
gem "appraisal"
gem "sqlite3"
gem "rails", "~> 3.0.0"
gemspec :path=>"../"

View File

@@ -0,0 +1,15 @@
# This file was generated by Appraisal
source "http://rubygems.org"
gem "rspec", "~> 2.8"
gem "rspec-rails", "~> 2.8"
gem "timecop"
gem "rspec_tag_matchers"
gem "ruby-debug", :platforms=>[:ruby_18, :jruby]
gem "debugger", :platforms=>[:ruby_19]
gem "appraisal"
gem "sqlite3"
gem "rails", "~> 3.1.0"
gemspec :path=>"../"

View File

@@ -0,0 +1,15 @@
# This file was generated by Appraisal
source "http://rubygems.org"
gem "rspec", "~> 2.8"
gem "rspec-rails", "~> 2.8"
gem "timecop"
gem "rspec_tag_matchers"
gem "ruby-debug", :platforms=>[:ruby_18, :jruby]
gem "debugger", :platforms=>[:ruby_19]
gem "appraisal"
gem "sqlite3"
gem "rails", "~> 3.2.0"
gemspec :path=>"../"

View File

@@ -3,7 +3,6 @@ module ValidatesTimeliness
class InstallGenerator < Rails::Generators::Base class InstallGenerator < Rails::Generators::Base
desc "Copy ValidatesTimeliness default files" desc "Copy ValidatesTimeliness default files"
source_root File.expand_path('../templates', __FILE__) source_root File.expand_path('../templates', __FILE__)
class_option :template_engine
def copy_initializers def copy_initializers
copy_file 'validates_timeliness.rb', 'config/initializers/validates_timeliness.rb' copy_file 'validates_timeliness.rb', 'config/initializers/validates_timeliness.rb'

View File

@@ -24,26 +24,24 @@ module ValidatesTimeliness
class << self class << self
delegate :default_timezone, :default_timezone=, :dummy_date_for_time_type, :dummy_date_for_time_type=, :to => Timeliness delegate :default_timezone, :default_timezone=, :dummy_date_for_time_type, :dummy_date_for_time_type=, :to => Timeliness
attr_accessor :extend_orms, :ignore_restriction_errors, :restriction_shorthand_symbols, :use_plugin_parser
end end
# Extend ORM/ODMs for full support (:active_record, :mongoid). # Extend ORM/ODMs for full support (:active_record, :mongoid).
mattr_accessor :extend_orms self.extend_orms = []
@@extend_orms = []
# Ignore errors when restriction options are evaluated # Ignore errors when restriction options are evaluated
mattr_accessor :ignore_restriction_errors self.ignore_restriction_errors = false
@@ignore_restriction_errors = false
# Shorthand time and date symbols for restrictions # Shorthand time and date symbols for restrictions
mattr_accessor :restriction_shorthand_symbols self.restriction_shorthand_symbols = {
@@restriction_shorthand_symbols = {
:now => lambda { Time.current }, :now => lambda { Time.current },
:today => lambda { Date.current } :today => lambda { Date.current }
} }
# Use the plugin date/time parser which is stricter and extensible # Use the plugin date/time parser which is stricter and extensible
mattr_accessor :use_plugin_parser self.use_plugin_parser = false
@@use_plugin_parser = false
# Default timezone # Default timezone
self.default_timezone = :utc self.default_timezone = :utc
@@ -51,15 +49,17 @@ module ValidatesTimeliness
# Set the dummy date part for a time type values. # Set the dummy date part for a time type values.
self.dummy_date_for_time_type = [ 2000, 1, 1 ] self.dummy_date_for_time_type = [ 2000, 1, 1 ]
def self.parser
Timeliness
end
# Setup method for plugin configuration # Setup method for plugin configuration
def self.setup def self.setup
yield self yield self
load_orms
end
def self.load_orms
extend_orms.each {|orm| require "validates_timeliness/orm/#{orm}" } extend_orms.each {|orm| require "validates_timeliness/orm/#{orm}" }
end end
def self.parser; Timeliness end
end end
require 'validates_timeliness/conversion' require 'validates_timeliness/conversion'

View File

@@ -15,12 +15,7 @@ module ActiveModel
end end
def timeliness_validation_for(attr_names, type) def timeliness_validation_for(attr_names, type)
options = _merge_attributes(attr_names).merge(:type => type) validates_with TimelinessValidator, _merge_attributes(attr_names).merge(:type => type)
if respond_to?(:timeliness_validated_attributes)
self.timeliness_validated_attributes ||= []
self.timeliness_validated_attributes += (attr_names - self.timeliness_validated_attributes)
end
validates_with TimelinessValidator, options
end end
end end

View File

@@ -3,61 +3,32 @@ module ValidatesTimeliness
module ActiveRecord module ActiveRecord
extend ActiveSupport::Concern extend ActiveSupport::Concern
def self.use_plugin_cache?
::ActiveRecord::VERSION::STRING < '3.1.0'
end
included do
if ValidatesTimeliness::ORM::ActiveRecord.use_plugin_cache?
include Reload
else
# Just use the built-in before_type_cast retrieval
alias_method :_timeliness_raw_value_for, :read_attribute_before_type_cast
end
end
module ClassMethods module ClassMethods
public public
def timeliness_attribute_timezone_aware?(attr_name) def timeliness_attribute_timezone_aware?(attr_name)
attr_name = attr_name.to_s create_time_zone_conversion_attribute?(attr_name, timeliness_column_for_attribute(attr_name))
create_time_zone_conversion_attribute?(attr_name, columns_hash[attr_name])
end end
def timeliness_attribute_type(attr_name) def timeliness_attribute_type(attr_name)
columns_hash[attr_name.to_s].type timeliness_column_for_attribute(attr_name).type
end
def timeliness_column_for_attribute(attr_name)
columns_hash.fetch(attr_name.to_s) do |attr_name|
validation_type = _validators[attr_name.to_sym].find {|v| v.kind == :timeliness }.type
::ActiveRecord::ConnectionAdapters::Column.new(attr_name, nil, validation_type.to_s)
end
end end
def define_attribute_methods def define_attribute_methods
super.tap do |attribute_methods_generated| super.tap do |attribute_methods_generated|
use_before_type_cast = ValidatesTimeliness::ORM::ActiveRecord.use_plugin_cache? define_timeliness_methods true
define_timeliness_methods use_before_type_cast
end end
end end
protected protected
def define_attribute_timeliness_methods(attr_name, before_type_cast=false)
if before_type_cast
define_timeliness_write_method(attr_name)
define_timeliness_before_type_cast_method(attr_name)
elsif ValidatesTimeliness.use_plugin_parser
define_timeliness_write_method_without_cache(attr_name)
end
end
def define_timeliness_write_method_without_cache(attr_name)
method_body, line = <<-EOV, __LINE__ + 1
def #{attr_name}=(value)
original_value = value
if value.is_a?(String)\n#{timeliness_type_cast_code(attr_name, 'value')}\nend
super(value)
@attributes['#{attr_name}'] = original_value
end
EOV
generated_timeliness_methods.module_eval(method_body, __FILE__, line)
end
def timeliness_type_cast_code(attr_name, var_name) def timeliness_type_cast_code(attr_name, var_name)
type = timeliness_attribute_type(attr_name) type = timeliness_attribute_type(attr_name)
@@ -67,11 +38,9 @@ module ValidatesTimeliness
end end
end end
module Reload def reload(*args)
def reload(*args) _clear_timeliness_cache
_clear_timeliness_cache super
super
end
end end
end end

View File

@@ -21,7 +21,7 @@ module ValidatesTimeliness
def timeliness_attribute_type(attr_name) def timeliness_attribute_type(attr_name)
{ {
Date => :date, Date => :date,
Time => :datetime, Time => :time,
DateTime => :datetime DateTime => :datetime
}[fields[attr_name.to_s].type] || :datetime }[fields[attr_name.to_s].type] || :datetime
end end

View File

@@ -3,7 +3,8 @@ module ValidatesTimeliness
initializer "validates_timeliness.initialize_active_record", :after => 'active_record.initialize_timezone' do initializer "validates_timeliness.initialize_active_record", :after => 'active_record.initialize_timezone' do
ActiveSupport.on_load(:active_record) do ActiveSupport.on_load(:active_record) do
ValidatesTimeliness.default_timezone = ActiveRecord::Base.default_timezone ValidatesTimeliness.default_timezone = ActiveRecord::Base.default_timezone
ValidatesTimeliness.extend_orms = [ :active_record ] ValidatesTimeliness.extend_orms << :active_record
ValidatesTimeliness.load_orms
end end
end end

View File

@@ -1,3 +1,4 @@
require 'active_model'
require 'active_model/validator' require 'active_model/validator'
module ValidatesTimeliness module ValidatesTimeliness
@@ -22,19 +23,35 @@ module ValidatesTimeliness
RESTRICTION_ERROR_MESSAGE = "Error occurred validating %s for %s restriction:\n%s" RESTRICTION_ERROR_MESSAGE = "Error occurred validating %s for %s restriction:\n%s"
def self.kind
:timeliness
end
def initialize(options) def initialize(options)
@type = options.delete(:type) || :datetime @type = options.delete(:type) || :datetime
@allow_nil, @allow_blank = options.delete(:allow_nil), options.delete(:allow_blank) @allow_nil, @allow_blank = options.delete(:allow_nil), options.delete(:allow_blank)
if range = options.delete(:between) if range = options.delete(:between)
raise ArgumentError, ":between must be a Range or an Array" unless range.is_a?(Range) || range.is_a?(Array) raise ArgumentError, ":between must be a Range or an Array" unless range.is_a?(Range) || range.is_a?(Array)
options[:on_or_after], options[:on_or_before] = range.first, range.last options[:on_or_after] = range.first
if range.is_a?(Range) && range.exclude_end?
options[:before] = range.last
else
options[:on_or_before] = range.last
end
end end
@restrictions_to_check = RESTRICTIONS.keys & options.keys @restrictions_to_check = RESTRICTIONS.keys & options.keys
super super
end end
def setup(model)
if model.respond_to?(:timeliness_validated_attributes)
model.timeliness_validated_attributes ||= []
model.timeliness_validated_attributes |= @attributes
end
end
def validate_each(record, attr_name, value) def validate_each(record, attr_name, value)
raw_value = attribute_raw_value(record, attr_name) || value raw_value = attribute_raw_value(record, attr_name) || value
return if (@allow_nil && raw_value.nil?) || (@allow_blank && raw_value.blank?) return if (@allow_nil && raw_value.nil?) || (@allow_blank && raw_value.blank?)

View File

@@ -1,3 +1,3 @@
module ValidatesTimeliness module ValidatesTimeliness
VERSION = '3.0.11' VERSION = '3.0.14'
end end

View File

@@ -57,6 +57,7 @@ class PersonWithShim < Person
include TestModelShim include TestModelShim
end end
ActiveRecord::Base.default_timezone = :utc
ActiveRecord::Base.time_zone_aware_attributes = true ActiveRecord::Base.time_zone_aware_attributes = true
ActiveRecord::Base.establish_connection({:adapter => 'sqlite3', :database => ':memory:'}) ActiveRecord::Base.establish_connection({:adapter => 'sqlite3', :database => ':memory:'})
ActiveRecord::Migration.verbose = false ActiveRecord::Migration.verbose = false
@@ -92,10 +93,7 @@ RSpec.configure do |c|
reset_validation_setup_for(PersonWithShim) reset_validation_setup_for(PersonWithShim)
end end
RSpec.configure do |c| c.filter_run_excluding :active_record => lambda {|version|
c.filter_run_excluding :active_record => lambda {|version| !(::ActiveRecord::VERSION::STRING.to_s =~ /^#{version.to_s}/)
!(::ActiveRecord::VERSION::STRING.to_s =~ /^#{version.to_s}/) }
}
end
end end

View File

@@ -10,7 +10,7 @@ describe ValidatesTimeliness::Extensions::MultiparameterHandler do
it 'should assign a Time value for valid datetimes' do it 'should assign a Time value for valid datetimes' do
employee = record_with_multiparameter_attribute(:birth_datetime, [2000, 2, 28, 12, 0, 0]) employee = record_with_multiparameter_attribute(:birth_datetime, [2000, 2, 28, 12, 0, 0])
employee.birth_datetime_before_type_cast.should eq Time.local(2000, 2, 28, 12, 0, 0) employee.birth_datetime_before_type_cast.should eq Time.zone.local(2000, 2, 28, 12, 0, 0)
end end
it 'should assign a string value for incomplete time' do it 'should assign a string value for incomplete time' do

View File

@@ -1,6 +1,8 @@
require 'spec_helper' require 'spec_helper'
describe ValidatesTimeliness, 'HelperMethods' do describe ValidatesTimeliness, 'HelperMethods' do
let(:record) { Person.new }
it 'should define class validation methods' do it 'should define class validation methods' do
Person.should respond_to(:validates_date) Person.should respond_to(:validates_date)
Person.should respond_to(:validates_time) Person.should respond_to(:validates_time)
@@ -8,23 +10,21 @@ describe ValidatesTimeliness, 'HelperMethods' do
end end
it 'should define instance validation methods' do it 'should define instance validation methods' do
Person.new.should respond_to(:validates_date) record.should respond_to(:validates_date)
Person.new.should respond_to(:validates_time) record.should respond_to(:validates_time)
Person.new.should respond_to(:validates_datetime) record.should respond_to(:validates_datetime)
end end
it 'should validate instance using class validation defined' do it 'should validate instance using class validation defined' do
Person.validates_date :birth_date Person.validates_date :birth_date
r = Person.new record.valid?
r.valid?
r.errors[:birth_date].should_not be_empty record.errors[:birth_date].should_not be_empty
end end
it 'should validate instance using instance valiation method' do it 'should validate instance using instance valiation method' do
r = Person.new record.validates_date :birth_date
r.validates_date :birth_date
r.errors[:birth_date].should_not be_empty record.errors[:birth_date].should_not be_empty
end end
end end

View File

@@ -3,6 +3,8 @@ require 'spec_helper'
describe ValidatesTimeliness, 'ActiveRecord' do describe ValidatesTimeliness, 'ActiveRecord' do
context "validation methods" do context "validation methods" do
let(:record) { Employee.new }
it 'should be defined for the class' do it 'should be defined for the class' do
ActiveRecord::Base.should respond_to(:validates_date) ActiveRecord::Base.should respond_to(:validates_date)
ActiveRecord::Base.should respond_to(:validates_time) ActiveRecord::Base.should respond_to(:validates_time)
@@ -10,111 +12,181 @@ describe ValidatesTimeliness, 'ActiveRecord' do
end end
it 'should defines for the instance' do it 'should defines for the instance' do
Employee.new.should respond_to(:validates_date) record.should respond_to(:validates_date)
Employee.new.should respond_to(:validates_time) record.should respond_to(:validates_time)
Employee.new.should respond_to(:validates_datetime) record.should respond_to(:validates_datetime)
end end
it "should validate a valid value string" do it "should validate a valid value string" do
r = Employee.new record.birth_date = '2012-01-01'
r.birth_date = '2012-01-01'
r.valid? record.valid?
r.errors[:birth_date].should be_empty record.errors[:birth_date].should be_empty
end end
it "should validate a invalid value string" do it "should validate a invalid value string" do
r = Employee.new record.birth_date = 'not a date'
r.birth_date = 'not a date'
r.valid? record.valid?
r.errors[:birth_date].should_not be_empty record.errors[:birth_date].should_not be_empty
end end
it "should validate a nil value" do it "should validate a nil value" do
r = Employee.new record.birth_date = nil
r.birth_date = nil
r.valid? record.valid?
r.errors[:birth_date].should be_empty record.errors[:birth_date].should be_empty
end end
end end
it 'should determine type for attribute' do it 'should determine type for attribute' do
Employee.timeliness_attribute_type(:birth_date).should == :date Employee.timeliness_attribute_type(:birth_date).should eq :date
end
context 'attribute timezone awareness' do
let(:klass) {
Class.new(ActiveRecord::Base) do
self.table_name = 'employees'
attr_accessor :some_date
attr_accessor :some_time
attr_accessor :some_datetime
validates_date :some_date
validates_time :some_time
validates_datetime :some_datetime
end
}
context 'for column attribute' do
it 'should be detected from column type' do
klass.timeliness_attribute_timezone_aware?(:birth_date).should be_false
klass.timeliness_attribute_timezone_aware?(:birth_time).should be_false
klass.timeliness_attribute_timezone_aware?(:birth_datetime).should be_true
end
end
context 'for non-column attribute' do
it 'should be detected from the validation type' do
klass.timeliness_attribute_timezone_aware?(:some_date).should be_false
klass.timeliness_attribute_timezone_aware?(:some_time).should be_false
klass.timeliness_attribute_timezone_aware?(:some_datetime).should be_true
end
end
end end
context "attribute write method" do context "attribute write method" do
class EmployeeWithCache < ActiveRecord::Base class EmployeeWithCache < ActiveRecord::Base
set_table_name 'employees' self.table_name = 'employees'
validates_date :birth_date, :allow_blank => true validates_date :birth_date, :allow_blank => true
validates_time :birth_time, :allow_blank => true
validates_datetime :birth_datetime, :allow_blank => true validates_datetime :birth_datetime, :allow_blank => true
end end
context 'value cache' do context 'value cache' do
let(:record) { EmployeeWithCache.new }
context 'for datetime column' do context 'for datetime column' do
it 'should store raw value' do it 'should store raw value' do
r = EmployeeWithCache.new record.birth_datetime = datetime_string = '2010-01-01 12:30'
r.birth_datetime = date_string = '2010-01-01'
r._timeliness_raw_value_for('birth_datetime').should == date_string record._timeliness_raw_value_for('birth_datetime').should eq datetime_string
end end
end end
context 'for date column' do context 'for date column' do
it 'should store raw value' do it 'should store raw value' do
r = EmployeeWithCache.new record.birth_date = date_string = '2010-01-01'
r.birth_date = date_string = '2010-01-01'
r._timeliness_raw_value_for('birth_date').should == date_string record._timeliness_raw_value_for('birth_date').should eq date_string
end
end
context 'for time column' do
it 'should store raw value' do
record.birth_time = time_string = '12:12'
record._timeliness_raw_value_for('birth_time').should eq time_string
end end
end end
end end
context "with plugin parser" do context "with plugin parser" do
with_config(:use_plugin_parser, true) with_config(:use_plugin_parser, true)
let(:record) { EmployeeWithParser.new }
class EmployeeWithParser < ActiveRecord::Base class EmployeeWithParser < ActiveRecord::Base
set_table_name 'employees' self.table_name = 'employees'
validates_date :birth_date, :allow_blank => true validates_date :birth_date, :allow_blank => true
validates_time :birth_time, :allow_blank => true
validates_datetime :birth_datetime, :allow_blank => true validates_datetime :birth_datetime, :allow_blank => true
end end
it 'should parse a string value' do
Timeliness::Parser.should_receive(:parse)
r = EmployeeWithParser.new
r.birth_date = '2010-01-01'
end
it 'should parse a invalid string value as nil' do
Timeliness::Parser.should_receive(:parse)
r = EmployeeWithParser.new
r.birth_date = 'not a date'
end
context "for a date column" do context "for a date column" do
it 'should store a date value after parsing string' do it 'should parse a string value' do
r = EmployeeWithParser.new Timeliness::Parser.should_receive(:parse)
r.birth_date = '2010-01-01'
r.birth_date.should be_kind_of(Date) record.birth_date = '2010-01-01'
r.birth_date.should == Date.new(2010, 1, 1) end
it 'should parse a invalid string value as nil' do
Timeliness::Parser.should_receive(:parse)
record.birth_date = 'not valid'
end
it 'should store a Date value after parsing string' do
record.birth_date = '2010-01-01'
record.birth_date.should be_kind_of(Date)
record.birth_date.should eq Date.new(2010, 1, 1)
end
end
context "for a time column" do
it 'should parse a string value' do
Timeliness::Parser.should_receive(:parse)
record.birth_time = '12:30'
end
it 'should parse a invalid string value as nil' do
Timeliness::Parser.should_receive(:parse)
record.birth_time = 'not valid'
end
it 'should store a Time value after parsing string' do
record.birth_time = '12:30'
record.birth_time.should be_kind_of(Time)
record.birth_time.should eq Time.utc(2000, 1, 1, 12, 30)
end end
end end
context "for a datetime column" do context "for a datetime column" do
with_config(:default_timezone, 'Australia/Melbourne') with_config(:default_timezone, 'Australia/Melbourne')
it 'should parse string into Time value' do it 'should parse a string value' do
r = EmployeeWithParser.new Timeliness::Parser.should_receive(:parse)
r.birth_datetime = '2010-01-01 12:00'
r.birth_datetime.should be_kind_of(Time) record.birth_datetime = '2010-01-01 12:00'
end
it 'should parse a invalid string value as nil' do
Timeliness::Parser.should_receive(:parse)
record.birth_datetime = 'not valid'
end
it 'should parse string into Time value' do
record.birth_datetime = '2010-01-01 12:00'
record.birth_datetime.should be_kind_of(Time)
end end
it 'should parse string as current timezone' do it 'should parse string as current timezone' do
r = EmployeeWithParser.new record.birth_datetime = '2010-06-01 12:00'
r.birth_datetime = '2010-06-01 12:00'
r.birth_datetime.utc_offset.should == Time.zone.utc_offset record.birth_datetime.utc_offset.should eq Time.zone.utc_offset
end end
end end
end end
@@ -122,43 +194,43 @@ describe ValidatesTimeliness, 'ActiveRecord' do
context "reload" do context "reload" do
it 'should clear cache value' do it 'should clear cache value' do
r = Employee.create! record = Employee.create!
r.birth_date = '2010-01-01' record.birth_date = '2010-01-01'
r.reload record.reload
r._timeliness_raw_value_for('birth_date').should be_nil record._timeliness_raw_value_for('birth_date').should be_nil
end end
end end
context "before_type_cast method" do context "before_type_cast method" do
let(:record) { Employee.new }
it 'should be defined on class if ORM supports it' do it 'should be defined on class if ORM supports it' do
Employee.new.should respond_to(:birth_datetime_before_type_cast) record.should respond_to(:birth_datetime_before_type_cast)
end end
it 'should return original value' do it 'should return original value' do
r = Employee.new record.birth_datetime = date_string = '2010-01-01'
r.birth_datetime = date_string = '2010-01-01'
r.birth_datetime_before_type_cast.should == date_string record.birth_datetime_before_type_cast.should eq date_string
end end
it 'should return attribute if no attribute assignment has been made' do it 'should return attribute if no attribute assignment has been made' do
datetime = Time.zone.local(2010,01,01) datetime = Time.zone.local(2010,01,01)
Employee.create(:birth_datetime => datetime) Employee.create(:birth_datetime => datetime)
r = Employee.last record = Employee.last
r.birth_datetime_before_type_cast.should match(/2010-01-01 00:00:00/) record.birth_datetime_before_type_cast.should match(/#{datetime.utc.to_s[0...-4]}/)
end end
context "with plugin parser" do context "with plugin parser" do
with_config(:use_plugin_parser, true) with_config(:use_plugin_parser, true)
it 'should return original value' do it 'should return original value' do
r = Employee.new record.birth_datetime = date_string = '2010-01-31'
r.birth_datetime = date_string = '2010-01-31'
r.birth_datetime_before_type_cast.should == date_string record.birth_datetime_before_type_cast.should eq date_string
end end
end end

View File

@@ -5,6 +5,7 @@ begin
require 'mongoid' require 'mongoid'
require 'validates_timeliness/orm/mongoid' require 'validates_timeliness/orm/mongoid'
Mongoid.configure do |config| Mongoid.configure do |config|
name = "validates_timeliness_test" name = "validates_timeliness_test"
host = "localhost" host = "localhost"
@@ -16,17 +17,17 @@ describe ValidatesTimeliness, 'Mongoid' do
class Article class Article
include Mongoid::Document include Mongoid::Document
ValidatesTimeliness.use_plugin_parser = true
field :publish_date, :type => Date field :publish_date, :type => Date
field :publish_time, :type => Time field :publish_time, :type => Time
field :publish_datetime, :type => DateTime field :publish_datetime, :type => DateTime
validates_date :publish_date, :allow_nil => true validates_date :publish_date, :allow_nil => true
validates_time :publish_time, :allow_nil => true validates_time :publish_time, :allow_nil => true
validates_datetime :publish_datetime, :allow_nil => true validates_datetime :publish_datetime, :allow_nil => true
ValidatesTimeliness.use_plugin_parser = false
end end
context "validation methods" do context "validation methods" do
let(:record) { Article.new }
it 'should be defined on the class' do it 'should be defined on the class' do
Article.should respond_to(:validates_date) Article.should respond_to(:validates_date)
Article.should respond_to(:validates_time) Article.should respond_to(:validates_time)
@@ -34,33 +35,33 @@ describe ValidatesTimeliness, 'Mongoid' do
end end
it 'should be defined on the instance' do it 'should be defined on the instance' do
Article.new.should respond_to(:validates_date) record.should respond_to(:validates_date)
Article.new.should respond_to(:validates_time) record.should respond_to(:validates_time)
Article.new.should respond_to(:validates_datetime) record.should respond_to(:validates_datetime)
end end
it "should validate a valid value string" do it "should validate a valid value string" do
r = Article.new record.publish_date = '2012-01-01'
r.publish_date = '2012-01-01'
r.valid? record.valid?
r.errors[:publish_date].should be_empty record.errors[:publish_date].should be_empty
end end
it "should validate a invalid value string" do it "should validate a invalid value string" do
r = Article.new begin
r.publish_date = 'not a date' record.publish_date = 'not a date'
rescue
end
r.valid? record.valid?
r.errors[:publish_date].should_not be_empty record.errors[:publish_date].should_not be_empty
end end
it "should validate a nil value" do it "should validate a nil value" do
r = Article.new record.publish_date = nil
r.publish_date = nil
r.valid? record.valid?
r.errors[:publish_date].should be_empty record.errors[:publish_date].should be_empty
end end
end end
@@ -69,46 +70,97 @@ describe ValidatesTimeliness, 'Mongoid' do
end end
context "attribute write method" do context "attribute write method" do
let(:record) { Article.new }
it 'should cache attribute raw value' do it 'should cache attribute raw value' do
r = Article.new record.publish_datetime = date_string = '2010-01-01'
r.publish_datetime = date_string = '2010-01-01'
r._timeliness_raw_value_for('publish_datetime').should == date_string record._timeliness_raw_value_for('publish_datetime').should == date_string
end end
context "with plugin parser" do context "with plugin parser" do
with_config(:use_plugin_parser, true) let(:record) { ArticleWithParser.new }
it 'should parse a string value' do class ArticleWithParser
Timeliness::Parser.should_receive(:parse) include Mongoid::Document
r = Article.new field :publish_date, :type => Date
r.publish_date = '2010-01-01' field :publish_time, :type => Time
end field :publish_datetime, :type => DateTime
it 'should parse an invalid value as nil' do ValidatesTimeliness.use_plugin_parser = true
Timeliness::Parser.should_receive(:parse) validates_date :publish_date, :allow_nil => true
r = Article.new validates_time :publish_time, :allow_nil => true
r.publish_date = 'bad value' validates_datetime :publish_datetime, :allow_nil => true
ValidatesTimeliness.use_plugin_parser = false
r.publish_date.should be_nil
end end
context "for a date column" do context "for a date column" do
it 'should store a Date value after parsing string' do it 'should parse a string value' do
r = Article.new Timeliness::Parser.should_receive(:parse)
r.publish_date = '2010-01-01'
r.publish_date.should be_kind_of(Date) record.publish_date = '2010-01-01'
r.publish_date.should == Date.new(2010, 1, 1) end
it 'should parse a invalid string value as nil' do
Timeliness::Parser.should_receive(:parse)
record.publish_date = 'not valid'
end
it 'should store a Date value after parsing string' do
record.publish_date = '2010-01-01'
record.publish_date.should be_kind_of(Date)
record.publish_date.should eq Date.new(2010, 1, 1)
end
end
context "for a time column" do
it 'should parse a string value' do
Timeliness::Parser.should_receive(:parse)
record.publish_time = '12:30'
end
it 'should parse a invalid string value as nil' do
Timeliness::Parser.should_receive(:parse)
record.publish_time = 'not valid'
end
it 'should store a Time value after parsing string' do
record.publish_time = '12:30'
record.publish_time.should be_kind_of(Time)
record.publish_time.should eq Time.utc(2000, 1, 1, 12, 30)
end end
end end
context "for a datetime column" do context "for a datetime column" do
it 'should parse string into DateTime value' do with_config(:default_timezone, 'Australia/Melbourne')
r = Article.new
r.publish_datetime = '2010-01-01 12:00'
r.publish_datetime.should be_kind_of(DateTime) it 'should parse a string value' do
r.publish_datetime.should == DateTime.new(2010,1,1,12,0) Timeliness::Parser.should_receive(:parse)
record.publish_datetime = '2010-01-01 12:00'
end
it 'should parse a invalid string value as nil' do
Timeliness::Parser.should_receive(:parse)
record.publish_datetime = 'not valid'
end
it 'should parse string into DateTime value' do
record.publish_datetime = '2010-01-01 12:00'
record.publish_datetime.should be_kind_of(DateTime)
end
pending 'should parse string as current timezone' do
record.publish_datetime = '2010-06-01 12:00'
record.publish_datetime.utc_offset.should eq Time.zone.utc_offset
end end
end end
end end
@@ -116,10 +168,10 @@ describe ValidatesTimeliness, 'Mongoid' do
context "cached value" do context "cached value" do
it 'should be cleared on reload' do it 'should be cleared on reload' do
r = Article.create! record = Article.create!
r.publish_date = '2010-01-01' record.publish_date = '2010-01-01'
r.reload record.reload
r._timeliness_raw_value_for('publish_date').should be_nil record._timeliness_raw_value_for('publish_date').should be_nil
end end
end end

View File

@@ -1,8 +1,6 @@
require 'spec_helper' require 'spec_helper'
describe ValidatesTimeliness::Validator do describe ValidatesTimeliness::Validator do
NIL = [nil]
before do before do
Timecop.freeze(Time.local_time(2010, 1, 1, 0, 0, 0)) Timecop.freeze(Time.local_time(2010, 1, 1, 0, 0, 0))
end end
@@ -19,6 +17,14 @@ describe ValidatesTimeliness::Validator do
Person.validates :birth_datetime, :timeliness => {:is_at => Time.mktime(2010,1,1)} Person.validates :birth_datetime, :timeliness => {:is_at => Time.mktime(2010,1,1)}
Person.validators.first.type.should == :datetime Person.validators.first.type.should == :datetime
end end
it 'should add attribute to timeliness attributes set' do
PersonWithShim.timeliness_validated_attributes.should_not include(:birth_time)
PersonWithShim.validates :birth_time, :timeliness => {:is_at => "12:30"}
PersonWithShim.timeliness_validated_attributes.should include(:birth_time)
end
end end
it 'should not be valid for value which not valid date or time value' do it 'should not be valid for value which not valid date or time value' do
@@ -38,13 +44,13 @@ describe ValidatesTimeliness::Validator do
describe ":allow_nil option" do describe ":allow_nil option" do
it 'should not allow nil by default' do it 'should not allow nil by default' do
Person.validates_date :birth_date Person.validates_date :birth_date
invalid!(:birth_date, NIL, 'is not a valid date') invalid!(:birth_date, [nil], 'is not a valid date')
valid!(:birth_date, Date.today) valid!(:birth_date, Date.today)
end end
it 'should allow nil when true' do it 'should allow nil when true' do
Person.validates_date :birth_date, :allow_nil => true Person.validates_date :birth_date, :allow_nil => true
valid!(:birth_date, NIL) valid!(:birth_date, [nil])
end end
context "with raw value cache" do context "with raw value cache" do
@@ -109,6 +115,19 @@ describe ValidatesTimeliness::Validator do
valid!(:birth_date, on_or_before) valid!(:birth_date, on_or_before)
end end
end end
describe "range with excluded end value" do
it 'should be split option into :on_or_after and :before values' do
on_or_after, before = Date.new(2010,1,1), Date.new(2010,1,3)
Person.validates_date :birth_date, :between => on_or_after...before
Person.validators.first.options[:on_or_after].should == on_or_after
Person.validators.first.options[:before].should == before
invalid!(:birth_date, on_or_after - 1, "must be on or after 2010-01-01")
invalid!(:birth_date, before, "must be before 2010-01-03")
valid!(:birth_date, on_or_after)
valid!(:birth_date, before - 1)
end
end
end end
describe ":ignore_usec option" do describe ":ignore_usec option" do
@@ -218,7 +237,7 @@ describe ValidatesTimeliness::Validator do
Person.validates_date :birth_date, :invalid_date_message => 'custom invalid message' Person.validates_date :birth_date, :invalid_date_message => 'custom invalid message'
invalid!(:birth_date, 'asdf', 'custom invalid message') invalid!(:birth_date, 'asdf', 'custom invalid message')
end end
it 'should be used for invalid restriction' do it 'should be used for invalid restriction' do
Person.validates_date :birth_date, :before => Time.now, :before_message => 'custom before message' Person.validates_date :birth_date, :before => Time.now, :before_message => 'custom before message'
invalid!(:birth_date, Time.now, 'custom before message') invalid!(:birth_date, Time.now, 'custom before message')

View File

@@ -12,9 +12,9 @@ Gem::Specification.new do |s|
s.homepage = %q{http://github.com/adzap/validates_timeliness} s.homepage = %q{http://github.com/adzap/validates_timeliness}
s.require_paths = ["lib"] s.require_paths = ["lib"]
s.files = `git ls-files`.split("\n") - %w{ .gitignore .rspec Gemfile Gemfile.lock autotest/discover.rb } s.files = `git ls-files`.split("\n") - %w{ .gitignore .rspec Gemfile Gemfile.lock autotest/discover.rb Appraisals Travis.yml } - Dir['gemsfiles/*']
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n") s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
s.extra_rdoc_files = ["README.rdoc", "CHANGELOG.rdoc", "LICENSE"] s.extra_rdoc_files = ["README.rdoc", "CHANGELOG.rdoc", "LICENSE"]
s.add_runtime_dependency(%q<timeliness>, ["~> 0.3.6"]) s.add_runtime_dependency(%q<timeliness>, ["~> 0.3.7"])
end end