validates_timeliness 3.0.0.beta.4 → 3.0.0.beta.5

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG CHANGED
@@ -2,7 +2,9 @@
2
2
  - Rails 3 and ActiveModel compatibility
3
3
  - Uses ActiveModel::EachValidator as validator base class.
4
4
  - Configuration settings stored in ValidatesTimeliness module only. ValidatesTimeliness.setup block to configure.
5
- - Plugin parser is off by default.
5
+ - Parser extracted to the Timeliness gem http://github.com/adzap/timeliness
6
+ - Parser is disabled by default. See initializer for enabling it.
7
+ - Removed RSpec matcher. Encouraged poor specs by copy-pasting from spec to model, or worse, the other way round.
6
8
  - Method override for parsing and before type cast values is on validated attributes only. Old version handled all date/datetime columns, validates or not. Too intrusive.
7
9
  - Add validation helpers to classes using extend_orms config setting. e.g. conf.extend_orms = [ :active_record ]
8
10
  - Changed :between option so it is split into :on_or_after and :on_or_before option values. The error message for either failing check will be used instead of a between error message.
@@ -14,11 +14,13 @@ If you a looking for the old version for Rails 2.x go here[http://github.com/adz
14
14
 
15
15
  * Adds validation for dates, times and datetimes to ActiveModel
16
16
 
17
- * Adds extensions to fix Rails date/time select issues
17
+ * Handles timezones and type casting of values for you
18
+
19
+ * Only Rails date/time validation plugin offering complete validation (See ORM/ODM support)
18
20
 
19
- * Includes extensible date/time parser
21
+ * Adds extensions to fix Rails date/time select issues
20
22
 
21
- * Supports timezone handling
23
+ * Uses extensible date/time parser ({timeliness gem}[http://github.com/adzap/timeliness])
22
24
 
23
25
  * Supports I18n for the error messages
24
26
 
@@ -32,7 +34,7 @@ As plugin (from master)
32
34
  As gem (in beta)
33
35
 
34
36
  # in Gemfile
35
- gem 'validates_timeliness', '>= 3.0.0.beta'
37
+ gem 'validates_timeliness', '>= 3.0.5.beta'
36
38
 
37
39
  # Run bundler
38
40
  $ bundle install
@@ -69,14 +71,14 @@ To validate a model with a date, time or datetime attribute you just use the
69
71
  validation method
70
72
 
71
73
  class Person < ActiveRecord::Base
72
- validates_date :date_of_birth, :on_or_before => lambda { Date.today }
74
+ validates_date :date_of_birth, :on_or_before => lambda { Date.current }
73
75
  # or
74
- validates :date_of_birth, :timeliness => {:on_or_before => lambda { Date.today }, :type => date}
76
+ validates :date_of_birth, :timeliness => {:on_or_before => lambda { Date.current }, :type => :date}
75
77
  end
76
78
 
77
79
  # or even on a specific record, per ActiveModel API.
78
80
 
79
- @person.validates_date :date_of_birth, :on_or_before => lambda { Date.today }
81
+ @person.validates_date :date_of_birth, :on_or_before => lambda { Date.current }
80
82
 
81
83
 
82
84
  The list of validation methods available are as follows:
@@ -180,22 +182,23 @@ It is highly recommended you use the I18n system for error messages.
180
182
 
181
183
  === Plugin Parser
182
184
 
183
- The plugin comes with a customisable date and time parser. You can add or remove valid formats
184
- for dates, times, and datetimes. It is also more strict than the Ruby parser, which means it
185
- won't accept day of the month if it's not a valid number for that month.
185
+ The uses the {timeliness gem}[http://github.com/adzap/timeliness] as a fast, configurable and extensible date and time parser.
186
+ You can add or remove valid formats for dates, times, and datetimes. It is also more strict than the
187
+ Ruby parser, which means it won't accept day of the month if it's not a valid number for the month.
186
188
 
187
- By default the parser is switched off. To switch it on:
189
+ By default the parser is disabled. To enable it:
188
190
 
189
191
  # in the setup block
190
192
  config.use_plugin_parser = true
191
193
 
192
- See the wiki[http://github.com/adzap/validates_timeliness/wiki/Plugin-Parser] for all the details about the parser.
194
+ Enabling the parser will mean that strings assigned to attributes validated with the plugin will be parsed
195
+ using the gem. See the wiki[http://github.com/adzap/validates_timeliness/wiki/Plugin-Parser] for more details about the parser configuration.
193
196
 
194
197
 
195
198
  === Restriction Shorthand
196
199
 
197
200
  It is common to restrict an attribute to being on or before the current time or current day.
198
- To specify this you need to use a lambda as an option value e.g. <tt>lambda { Time.now }</tt>.
201
+ To specify this you need to use a lambda as an option value e.g. <tt>lambda { Time.current }</tt>.
199
202
  This can be tedious noise amongst your validations for something so common. To combat this the
200
203
  plugin allows you to use shorthand symbols for often used relative times or dates.
201
204
 
data/Rakefile CHANGED
@@ -22,6 +22,7 @@ spec = Gem::Specification.new do |s|
22
22
  s.homepage = "http://github.com/adzap/validates_timeliness"
23
23
  s.require_path = 'lib'
24
24
  s.files = %w(validates_timeliness.gemspec LICENSE CHANGELOG README.rdoc Rakefile) + Dir.glob("{lib,spec}/**/*")
25
+ s.add_runtime_dependency 'timeliness', '~> 0.1.1'
25
26
  end
26
27
 
27
28
  desc 'Default: run specs.'
@@ -2,8 +2,8 @@ ValidatesTimeliness.setup do |config|
2
2
  # Extend ORM/ODMs for full support (:active_record, :mongoid).
3
3
  # config.extend_orms = [ :active_record ]
4
4
  #
5
- # User the plugin date/time parser which is stricter and extendable
6
- # config.use_plugin_parser = false
5
+ # Default timezone
6
+ # config.default_timezone = :utc
7
7
  #
8
8
  # Set the dummy date part for a time type values.
9
9
  # config.dummy_date_for_time_type = [ 2000, 1, 1 ]
@@ -19,10 +19,13 @@ ValidatesTimeliness.setup do |config|
19
19
  #
20
20
  # Shorthand date and time symbols for restrictions
21
21
  # config.restriction_shorthand_symbols.update(
22
- # :now => lambda { Time.now },
23
- # :today => lambda { Date.today }
22
+ # :now => lambda { Time.current },
23
+ # :today => lambda { Date.current }
24
24
  # )
25
25
  #
26
+ # Use the plugin date/time parser which is stricter and extendable
27
+ # config.use_plugin_parser = false
28
+ #
26
29
  # Add one or more formats making them valid. e.g. add_formats(:date, 'd(st|rd|th) of mmm, yyyy')
27
30
  # config.parser.add_formats()
28
31
  #
@@ -1,4 +1,6 @@
1
1
  require 'date'
2
+ require 'active_support/concern'
3
+ require 'active_support/core_ext/module'
2
4
  require 'active_support/core_ext/hash/except'
3
5
  require 'active_support/core_ext/string/conversions'
4
6
  require 'active_support/core_ext/date/acts_like'
@@ -7,41 +9,42 @@ require 'active_support/core_ext/time/acts_like'
7
9
  require 'active_support/core_ext/time/conversions'
8
10
  require 'active_support/core_ext/date_time/acts_like'
9
11
  require 'active_support/core_ext/date_time/conversions'
12
+ require 'timeliness'
10
13
 
11
14
  module ValidatesTimeliness
12
- autoload :Parser, 'validates_timeliness/parser'
13
15
  autoload :VERSION, 'validates_timeliness/version'
14
16
 
17
+ class << self
18
+ delegate :parser, :default_timezone, :default_timezone=, :dummy_date_for_time_type, :to => Timeliness
19
+ end
20
+
15
21
  # Extend ORM/ODMs for full support (:active_record, :mongoid).
16
22
  mattr_accessor :extend_orms
17
- @@extend_orms = [ defined?(ActiveRecord) && :active_record ].compact
18
-
19
- # User the plugin date/time parser which is stricter and extendable
20
- mattr_accessor :use_plugin_parser
21
- @@use_plugin_parser = false
22
-
23
- # Default timezone
24
- mattr_accessor :default_timezone
25
- @@default_timezone = defined?(ActiveRecord) ? ActiveRecord::Base.default_timezone : :utc
26
-
27
- # Set the dummy date part for a time type values.
28
- mattr_accessor :dummy_date_for_time_type
29
- @@dummy_date_for_time_type = [ 2000, 1, 1 ]
23
+ @@extend_orms = []
30
24
 
31
25
  # Ignore errors when restriction options are evaluated
32
26
  mattr_accessor :ignore_restriction_errors
33
- @@ignore_restriction_errors = defined?(Rails) ? !Rails.env.test? : false
27
+ @@ignore_restriction_errors = false
34
28
 
35
29
  # Shorthand time and date symbols for restrictions
36
30
  mattr_accessor :restriction_shorthand_symbols
37
31
  @@restriction_shorthand_symbols = {
38
- :now => lambda { Time.now },
39
- :today => lambda { Date.today }
32
+ :now => lambda { Time.current },
33
+ :today => lambda { Date.current }
40
34
  }
41
35
 
42
- def self.parser
43
- Parser
36
+ # Use the plugin date/time parser which is stricter and extensible
37
+ mattr_accessor :use_plugin_parser
38
+ @@use_plugin_parser = false
39
+
40
+ # Default timezone
41
+ self.default_timezone = :utc
42
+
43
+ # Set the dummy date part for a time type values.
44
+ def self.dummy_date_for_time_type=(array)
45
+ Timeliness.date_for_time_type = array
44
46
  end
47
+ self.dummy_date_for_time_type = [ 2000, 1, 1 ]
45
48
 
46
49
  # Setup method for plugin configuration
47
50
  def self.setup
@@ -55,3 +58,4 @@ require 'validates_timeliness/validator'
55
58
  require 'validates_timeliness/helper_methods'
56
59
  require 'validates_timeliness/attribute_methods'
57
60
  require 'validates_timeliness/extensions'
61
+ require 'validates_timeliness/railtie' if defined?(Rails)
@@ -38,7 +38,7 @@ module ValidatesTimeliness
38
38
  def #{attr_name}=(value)
39
39
  @timeliness_cache ||= {}
40
40
  @timeliness_cache["#{attr_name}"] = value
41
- #{ "value = ValidatesTimeliness::Parser.parse(value, :#{type}, :timezone_aware => #{timezone_aware}) if value.is_a?(String)" if ValidatesTimeliness.use_plugin_parser }
41
+ #{ "value = Timeliness::Parser.parse(value, :#{type}, :zone => (:current if #{timezone_aware})) if value.is_a?(String)" if ValidatesTimeliness.use_plugin_parser }
42
42
  super
43
43
  end
44
44
  EOV
@@ -11,10 +11,10 @@ module ValidatesTimeliness
11
11
  when :date
12
12
  value.to_date
13
13
  when :datetime
14
- value.to_time
14
+ value.is_a?(Time) ? value : value.to_time
15
15
  end
16
16
  if options[:ignore_usec] && value.is_a?(Time)
17
- ValidatesTimeliness::Parser.make_time(Array(value).reverse[4..9], @timezone_aware)
17
+ Timeliness::Parser.make_time(Array(value).reverse[4..9], (:current if @timezone_aware))
18
18
  else
19
19
  value
20
20
  end
@@ -28,7 +28,7 @@ module ValidatesTimeliness
28
28
  [0,0,0]
29
29
  end
30
30
  values = ValidatesTimeliness.dummy_date_for_time_type + time
31
- ValidatesTimeliness::Parser.make_time(values, @timezone_aware)
31
+ Timeliness::Parser.make_time(values, (:current if @timezone_aware))
32
32
  end
33
33
 
34
34
  def evaluate_option_value(value, record)
@@ -57,7 +57,7 @@ module ValidatesTimeliness
57
57
 
58
58
  def parse(value)
59
59
  if ValidatesTimeliness.use_plugin_parser
60
- ValidatesTimeliness::Parser.parse(value, @type, :timezone_aware => @timezone_aware, :format => options[:format], :strict => false)
60
+ Timeliness::Parser.parse(value, @type, :zone => (:current if @timezone_aware), :format => options[:format], :strict => false)
61
61
  else
62
62
  @timezone_aware ? Time.zone.parse(value) : value.to_time(ValidatesTimeliness.default_timezone)
63
63
  end
@@ -22,7 +22,7 @@ module ValidatesTimeliness
22
22
  def #{attr_name}=(value)
23
23
  @timeliness_cache ||= {}
24
24
  @timeliness_cache["#{attr_name}"] = value
25
- #{ "value = ValidatesTimeliness::Parser.parse(value, :#{type}) if value.is_a?(String)" if ValidatesTimeliness.use_plugin_parser }
25
+ #{ "value = Timeliness::Parser.parse(value, :#{type}) if value.is_a?(String)" if ValidatesTimeliness.use_plugin_parser }
26
26
  write_attribute(:#{attr_name}, value)
27
27
  end
28
28
  EOV
@@ -0,0 +1,14 @@
1
+ module ValidatesTimeliness
2
+ class Railtie < Rails::Railtie
3
+ initializer "validates_timeliness.initialize_active_record", :after => 'active_record.initialize_timezone' do
4
+ ActiveSupport.on_load(:active_record) do
5
+ ValidatesTimeliness.default_timezone = ActiveRecord::Base.default_timezone
6
+ ValidatesTimeliness.extend_orms = [ :active_record ]
7
+ end
8
+ end
9
+
10
+ initializer "validates_timeliness.initialize_restriction_errors" do
11
+ ValidatesTimeliness.ignore_restriction_errors = !Rails.env.test?
12
+ end
13
+ end
14
+ end
@@ -44,23 +44,28 @@ module ValidatesTimeliness
44
44
  value = parse(raw_value) if value.is_a?(String) || options[:format]
45
45
  value = type_cast_value(value, @type)
46
46
 
47
- return record.errors.add(attr_name, :"invalid_#{@type}") if value.blank?
47
+ return add_error(record, attr_name, :"invalid_#{@type}") if value.blank?
48
48
 
49
49
  @restrictions_to_check.each do |restriction|
50
50
  begin
51
51
  restriction_value = type_cast_value(evaluate_option_value(options[restriction], record), @type)
52
-
53
52
  unless value.send(RESTRICTIONS[restriction], restriction_value)
54
- return record.errors.add(attr_name, restriction, :message => options[:"#{restriction}_message"], :restriction => format_error_value(restriction_value))
53
+ return add_error(record, attr_name, restriction, restriction_value)
55
54
  end
56
55
  rescue => e
57
56
  unless ValidatesTimeliness.ignore_restriction_errors
58
- record.errors[attr_name] = "Error occurred validating #{attr_name} for #{restriction.inspect} restriction:\n#{e.message}"
57
+ add_error(record, attr_name, "Error occurred validating #{attr_name} for #{restriction.inspect} restriction:\n#{e.message}")
59
58
  end
60
59
  end
61
60
  end
62
61
  end
63
62
 
63
+ def add_error(record, attr_name, message, value=nil)
64
+ value = format_error_value(value) if value
65
+ message_options = { :message => options[:"#{message}_message"], :restriction => value }
66
+ record.errors.add(attr_name, message, message_options)
67
+ end
68
+
64
69
  def format_error_value(value)
65
70
  format = I18n.t(@type, :default => DEFAULT_ERROR_VALUE_FORMATS[@type], :scope => 'validates_timeliness.error_value_formats')
66
71
  value.strftime(format)
@@ -1,3 +1,3 @@
1
1
  module ValidatesTimeliness
2
- VERSION = '3.0.0.beta.4'
2
+ VERSION = '3.0.0.beta.5'
3
3
  end
@@ -2,7 +2,7 @@ require 'spec_helper'
2
2
 
3
3
  describe ValidatesTimeliness::AttributeMethods do
4
4
  it 'should define _timeliness_raw_value_for instance method' do
5
- PersonWithShim.instance_methods.should include('_timeliness_raw_value_for')
5
+ PersonWithShim.new.should respond_to(:_timeliness_raw_value_for)
6
6
  end
7
7
 
8
8
  describe ".timeliness_validated_attributes" do
@@ -51,7 +51,7 @@ describe ValidatesTimeliness::AttributeMethods do
51
51
  end
52
52
 
53
53
  it 'should parse a string value' do
54
- ValidatesTimeliness::Parser.should_receive(:parse)
54
+ Timeliness::Parser.should_receive(:parse)
55
55
  r = PersonWithParser.new
56
56
  r.birth_date = '2010-01-01'
57
57
  end
@@ -70,7 +70,7 @@ describe ValidatesTimeliness::AttributeMethods do
70
70
 
71
71
  context "before_type_cast method" do
72
72
  it 'should not be defined if ORM does not support it' do
73
- PersonWithShim.instance_methods(false).should_not include("birth_datetime_before_type_cast")
73
+ PersonWithShim.new.should_not respond_to(:birth_datetime_before_type_cast)
74
74
  end
75
75
  end
76
76
  end
@@ -102,8 +102,8 @@ describe ValidatesTimeliness::Conversion do
102
102
  end
103
103
 
104
104
  describe "with custom dummy date" do
105
- before(:all) do
106
- @@original_dummy_date = ValidatesTimeliness.dummy_date_for_time_type
105
+ before do
106
+ @original_dummy_date = ValidatesTimeliness.dummy_date_for_time_type
107
107
  ValidatesTimeliness.dummy_date_for_time_type = [2010, 1, 1]
108
108
  end
109
109
 
@@ -111,8 +111,8 @@ describe ValidatesTimeliness::Conversion do
111
111
  dummy_time(Time.utc(1999, 11, 22, 12, 34, 56)).should == Time.utc(2010, 1, 1, 12, 34, 56)
112
112
  end
113
113
 
114
- after(:all) do
115
- ValidatesTimeliness.dummy_date_for_time_type = @@original_dummy_date
114
+ after do
115
+ ValidatesTimeliness.dummy_date_for_time_type = @original_dummy_date
116
116
  end
117
117
  end
118
118
  end
@@ -8,9 +8,9 @@ describe ValidatesTimeliness, 'HelperMethods' do
8
8
  end
9
9
 
10
10
  it 'should define instance validation methods' do
11
- Person.instance_methods.should include('validates_date')
12
- Person.instance_methods.should include('validates_time')
13
- Person.instance_methods.should include('validates_datetime')
11
+ Person.new.should respond_to(:validates_date)
12
+ Person.new.should respond_to(:validates_time)
13
+ Person.new.should respond_to(:validates_datetime)
14
14
  end
15
15
 
16
16
  it 'should validate instance when validation method called' do
@@ -10,9 +10,9 @@ describe ValidatesTimeliness, 'ActiveRecord' do
10
10
  end
11
11
 
12
12
  it 'should defines for the instance' do
13
- ActiveRecord::Base.instance_methods.should include('validates_date')
14
- ActiveRecord::Base.instance_methods.should include('validates_time')
15
- ActiveRecord::Base.instance_methods.should include('validates_datetime')
13
+ Employee.new.should respond_to(:validates_date)
14
+ Employee.new.should respond_to(:validates_time)
15
+ Employee.new.should respond_to(:validates_datetime)
16
16
  end
17
17
  end
18
18
 
@@ -44,7 +44,7 @@ describe ValidatesTimeliness, 'ActiveRecord' do
44
44
  end
45
45
 
46
46
  it 'should parse a string value' do
47
- ValidatesTimeliness::Parser.should_receive(:parse)
47
+ Timeliness::Parser.should_receive(:parse)
48
48
  r = EmployeeWithParser.new
49
49
  r.birth_date = '2010-01-01'
50
50
  end
@@ -73,7 +73,7 @@ describe ValidatesTimeliness, 'ActiveRecord' do
73
73
 
74
74
  context "before_type_cast method" do
75
75
  it 'should be defined on class if ORM supports it' do
76
- Employee.instance_methods(false).should include("birth_datetime_before_type_cast")
76
+ Employee.new.should respond_to(:birth_datetime_before_type_cast)
77
77
  end
78
78
 
79
79
  it 'should return original value' do
@@ -1,8 +1,10 @@
1
1
  require 'spec_helper'
2
2
 
3
+ # Try loading mongoid and connecting. Otherwise, abort and skip spec.
4
+ begin
5
+
3
6
  require 'mongoid'
4
7
  require 'validates_timeliness/orm/mongoid'
5
-
6
8
  Mongoid.configure do |config|
7
9
  name = "validates_timeliness_test"
8
10
  host = "localhost"
@@ -32,9 +34,9 @@ describe ValidatesTimeliness, 'Mongoid' do
32
34
  end
33
35
 
34
36
  it 'should be defined on the instance' do
35
- Article.instance_methods.should include('validates_date')
36
- Article.instance_methods.should include('validates_time')
37
- Article.instance_methods.should include('validates_datetime')
37
+ Article.new.should respond_to(:validates_date)
38
+ Article.new.should respond_to(:validates_time)
39
+ Article.new.should respond_to(:validates_datetime)
38
40
  end
39
41
  end
40
42
 
@@ -55,7 +57,7 @@ describe ValidatesTimeliness, 'Mongoid' do
55
57
  end
56
58
 
57
59
  it 'should parse a string value' do
58
- ValidatesTimeliness::Parser.should_receive(:parse)
60
+ Timeliness::Parser.should_receive(:parse)
59
61
  r = Article.new
60
62
  r.publish_date = '2010-01-01'
61
63
  end
@@ -83,7 +85,13 @@ describe ValidatesTimeliness, 'Mongoid' do
83
85
 
84
86
  context "before_type_cast method" do
85
87
  it 'should not be defined if ORM does not support it' do
86
- Article.instance_methods(false).should_not include("birth_datetime_before_type_cast")
88
+ Article.new.should_not respond_to(:birth_datetime_before_type_cast)
87
89
  end
88
90
  end
89
91
  end
92
+
93
+ rescue LoadError
94
+ puts "Mongoid specs skipped. Mongoid not installed"
95
+ rescue StandardError
96
+ puts "Mongoid specs skipped. MongoDB connection failed."
97
+ end
@@ -190,11 +190,14 @@ describe ValidatesTimeliness::Validator do
190
190
  end
191
191
 
192
192
  context "custom error message" do
193
+ it 'should be used for invalid type' do
194
+ Person.validates_date :birth_date, :invalid_date_message => 'custom invalid message'
195
+ invalid!(:birth_date, 'asdf', 'custom invalid message')
196
+ end
193
197
 
194
- it 'should be used for failing restriction' do
198
+ it 'should be used for invalid restriction' do
195
199
  Person.validates_date :birth_date, :before => Time.now, :before_message => 'custom before message'
196
200
  invalid!(:birth_date, Time.now, 'custom before message')
197
201
  end
198
-
199
202
  end
200
203
  end