From af3e6ff774cc9305fb60ea4ef03685b632d07f41 Mon Sep 17 00:00:00 2001 From: Viktor Fonic Date: Mon, 17 Jun 2019 09:40:46 +0700 Subject: [PATCH] Convert README to markdown Also: - Highlight syntax - Change http to https - Update License - Fix default value of today (Date.current) --- LICENSE | 2 +- README.md | 353 +++++++++++++++++++++++++++++++++++ README.rdoc | 299 ----------------------------- Rakefile | 3 +- validates_timeliness.gemspec | 2 +- 5 files changed, 357 insertions(+), 302 deletions(-) create mode 100644 README.md delete mode 100644 README.rdoc diff --git a/LICENSE b/LICENSE index 290fec0..d2acf90 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2008-2010 Adam Meehan +Copyright (c) 2008-2021 Adam Meehan Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the diff --git a/README.md b/README.md new file mode 100644 index 0000000..d849801 --- /dev/null +++ b/README.md @@ -0,0 +1,353 @@ +# ValidatesTimeliness [![Build Status](https://travis-ci.org/adzap/validates_timeliness.svg?branch=master)](https://travis-ci.org/adzap/validates_timeliness) + +* Source: https://github.com/adzap/validates_timeliness +* Issues: https://github.com/adzap/validates_timeliness/issues + + +## Description + +Complete validation of dates, times and datetimes for Rails 5.x, 6.x, and +ActiveModel. + +If you a looking for the old version for Rails 4.x go here +[https://github.com/adzap/validates_timeliness/tree/4-0-stable]. + +## Features + +* Adds validation for dates, times and datetimes to ActiveModel +* Handles timezones and type casting of values for you +* Only Rails date/time validation plugin offering complete validation (See + ORM/ODM support) +* Uses extensible date/time parser (Using [timeliness + gem](https://github.com/adzap/timeliness). See Plugin Parser) +* Adds extensions to fix Rails date/time select issues (See Extensions) +* Supports I18n for the error messages. For multi-language support try + [timeliness-i18n gem](https://github.com/pedrofurtado/timeliness-i18n). +* Supports all the Rubies (that any sane person would be using in + production). + + +## Installation + +``` +# in Gemfile +gem 'validates_timeliness', '~> 5.0.0.beta1' + +# Run bundler +$ bundle install +``` + +Then run + +```sh +$ rails generate validates_timeliness:install +``` + +This creates configuration initializer and locale files. In the initializer, +there are a number of config options to customize the plugin. + +NOTE: You may wish to enable the plugin parser and the extensions to start. +Please read those sections first. + +## Examples + +```ruby +validates_datetime :occurred_at + +validates_date :date_of_birth, before: lambda { 18.years.ago }, + before_message: "must be at least 18 years old" + +validates_datetime :finish_time, after: :start_time # Method symbol + +validates_date :booked_at, on: :create, on_or_after: :today # See Restriction Shorthand. + +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', + on_or_after_message: 'must be after opening time', + before: :lunchtime, + before_message: 'must be before lunch time' +``` + +## Usage + +To validate a model with a date, time or datetime attribute you just use the +validation method + +```ruby +class Person < ActiveRecord::Base + validates_date :date_of_birth, on_or_before: lambda { Date.current } + # or + validates :date_of_birth, timeliness: { on_or_before: lambda { Date.current }, type: :date } +end +``` + +or even on a specific record, per ActiveModel API. + +```ruby +@person.validates_date :date_of_birth, on_or_before: lambda { Date.current } +``` + +The list of validation methods available are as follows: + +``` +validates_date - validate value as date +validates_time - validate value as time only i.e. '12:20pm' +validates_datetime - validate value as a full date and time +validates - use the :timeliness key and set the type in the hash. +``` + +The validation methods take the usual options plus some specific ones to +restrict the valid range of dates or times allowed + +Temporal options (or restrictions): + +``` +:is_at - Attribute must be equal to value to be valid +:before - Attribute must be before this value to be valid +:on_or_before - Attribute must be equal to or before this value to be valid +:after - Attribute must be after this value to be valid +:on_or_after - Attribute must be equal to or after this value to be valid +:between - Attribute must be between the values to be valid. Range or Array of 2 values. +``` + +Regular validation options: + +``` +:allow_nil - Allow a nil value to be valid +:allow_blank - Allows a nil or empty string value to be valid +:if - Execute validation when :if evaluates true +:unless - Execute validation when :unless evaluates false +:on - Specify validation context e.g :save, :create or :update. Default is :save. +``` + +Special options: + +``` +:ignore_usec - Ignores microsecond value on datetime restrictions +:format - Limit validation to a single format for special cases. Requires plugin parser. +``` + +The temporal restrictions can take 4 different value types: + +* Date, Time, or DateTime object value +* Proc or lambda object which may take an optional parameter, being the + record object +* A symbol matching a method name in the model +* String value + + +When an attribute value is compared to temporal restrictions, they are +compared as the same type as the validation method type. So using +validates_date means all values are compared as dates. + +## Configuration + +### ORM/ODM Support + +The plugin adds date/time validation to ActiveModel for any ORM/ODM that +supports the ActiveModel validations component. However, there is an issue +with most ORM/ODMs which does not allow 100% date/time validation by default. +Specifically, when you assign an invalid date/time value to an attribute, most +ORM/ODMs will only store a nil value for the attribute. This causes an issue +for date/time validation, since we need to know that a value was assigned but +was invalid. To fix this, we need to cache the original invalid value to know +that the attribute is not just nil. + +Each ORM/ODM requires a specific shim to fix it. The plugin includes a shim +for ActiveRecord and Mongoid. You can activate them like so + +```ruby +ValidatesTimeliness.setup do |config| + # Extend ORM/ODMs for full support (:active_record). + config.extend_orms = [ :active_record ] +end +``` + +By default the plugin extends ActiveRecord if loaded. If you wish to extend +another ORM then look at the [wiki +page](https://github.com/adzap/validates_timeliness/wiki/ORM-Support) for more +information. + +It is not required that you use a shim, but you will not catch errors when the +attribute value is invalid and evaluated to nil. + +### Error Messages + +Using the I18n system to define new defaults: + +```yaml +en: + errors: + messages: + invalid_date: "is not a valid date" + invalid_time: "is not a valid time" + invalid_datetime: "is not a valid datetime" + is_at: "must be at %{restriction}" + before: "must be before %{restriction}" + on_or_before: "must be on or before %{restriction}" + after: "must be after %{restriction}" + on_or_after: "must be on or after %{restriction}" +``` + +The `%{restriction}` signifies where the interpolation value for the restriction +will be inserted. + +You can also use validation options for custom error messages. The following +option keys are available: + +```ruby +:invalid_date_message +:invalid_time_message +:invalid_datetime_message +:is_at_message +:before_message +:on_or_before_message +:after_message +:on_or_after_message +``` + +Note: There is no `:between_message` option. The between error message should be +defined using the `:on_or_after` and `:on_or_before` (`: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. + +### Plugin Parser + +The plugin uses the [timeliness gem](https://github.com/adzap/timeliness) as a +fast, configurable and extensible date and time parser. You can add or remove +valid formats for dates, times, and datetimes. It is also more strict than the +Ruby parser, which means it won't accept day of the month if it's not a valid +number for the month. + +By default the parser is disabled. To enable it: + +```ruby +# in the setup block +config.use_plugin_parser = true +``` + +Enabling the parser will mean that strings assigned to attributes validated +with the plugin will be parsed using the gem. See the +[wiki](https://github.com/adzap/validates_timeliness/wiki/Plugin-Parser) for +more details about the parser configuration. + +### Restriction Shorthand + +It is common to restrict an attribute to being on or before the current time +or current day. To specify this you need to use a lambda as an option value +e.g. `lambda { Time.current }`. This can be tedious noise amongst your +validations for something so common. To combat this the plugin allows you to +use shorthand symbols for often used relative times or dates. + +Just provide the symbol as the option value like so: + +```ruby +validates_date :birth_date, on_or_before: :today +``` + +The `:today` symbol is evaluated as `lambda { Date.current }`. The `:now` and +`:today` symbols are pre-configured. Configure your own like so: + +```ruby +# in the setup block +config.restriction_shorthand_symbols.update( + yesterday: lambda { 1.day.ago } +) +``` + +### Default Timezone + +The plugin needs to know the default timezone you are using when parsing or +type casting values. If you are using ActiveRecord then the default is +automatically set to the same default zone as ActiveRecord. If you are using +another ORM you may need to change this setting. + +```ruby +# in the setup block +config.default_timezone = :utc +``` + +By default it will be UTC if ActiveRecord is not loaded. + +### Dummy Date For Time Types + +Given that Ruby has no support for a time-only type, all time type columns are +evaluated as a regular Time class objects with a dummy date value set. Rails +defines the dummy date as 2000-01-01. So a time of '12:30' is evaluated as a +Time value of '2000-01-01 12:30'. If you need to customize this for some +reason you can do so as follows + +```ruby +# in the setup block +config.dummy_date_for_time_type = [2009, 1, 1] +``` + +The value should be an array of 3 values being year, month and day in that +order. + +### Temporal Restriction Errors + +When using the validation temporal restrictions there are times when the +restriction option value itself may be invalid. This will add an error to the +model such as 'Error occurred validating birth_date for :before restriction'. +These can be annoying in development or production as you most likely just +want to skip the option if no valid value was returned. By default these +errors are displayed in Rails test mode. + +To turn them on/off: + +```ruby +# in the setup block +config.ignore_restriction_errors = true +``` + +## Extensions + +### Strict Parsing for Select Helpers + +When using date/time select helpers, the component values are handled by +ActiveRecord using the Time class to instantiate them into a time value. This +means that some invalid dates, such as 31st June, are shifted forward and +treated as valid. To handle these cases in a strict way, you can enable the +plugin extension to treat them as invalid dates. + +To activate it, uncomment this line in the initializer: + +```ruby +# in the setup block +config.enable_multiparameter_extension! +``` + +### Display Invalid Values in Select Helpers + +The plugin offers an extension for ActionView to allowing invalid date and +time values to be redisplayed to the user as feedback, instead of a blank +field which happens by default in Rails. Though the date helpers make this a +pretty rare occurrence, given the select dropdowns for each date/time +component, but it may be something of interest. + +To activate it, uncomment this line in the initializer: + +```ruby +# in the setup block +config.enable_date_time_select_extension! +``` + +## Contributors + +To see the generous people who have contributed code, take a look at the +[contributors +list](https://github.com/adzap/validates_timeliness/contributors). + +## Maintainers + +* [Adam Meehan](https://github.com/adzap) + + +## License + +Copyright (c) 2008 Adam Meehan, released under the MIT license diff --git a/README.rdoc b/README.rdoc deleted file mode 100644 index 0c7e7f0..0000000 --- a/README.rdoc +++ /dev/null @@ -1,299 +0,0 @@ -= ValidatesTimeliness {Build Status}[https://travis-ci.org/adzap/validates_timeliness] - -* Source: http://github.com/adzap/validates_timeliness -* Issues: http://github.com/adzap/validates_timeliness/issues - -== Description - -Complete validation of dates, times and datetimes for Rails 5.x and ActiveModel. - -If you a looking for the old version for Rails 4.x go here [https://github.com/adzap/validates_timeliness/tree/4-0-stable]. - - -== Features - -* Adds validation for dates, times and datetimes to ActiveModel - -* Handles timezones and type casting of values for you - -* Only Rails date/time validation plugin offering complete validation (See ORM/ODM support) - -* 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. For multi-language support try {timeliness-i18n gem}[https://github.com/pedrofurtado/timeliness-i18n]. - -* Supports all the Rubies (that any sane person would be using in production). - - -== Installation - - # in Gemfile - gem 'validates_timeliness', '~> 5.0.0.beta1' - - # Run bundler - $ bundle install - -Then run - - $ rails generate validates_timeliness:install - -This creates configuration initializer and locale files. In the initializer, there are a number of config -options to customize the plugin. - -NOTE: You may wish to enable the plugin parser and the extensions to start. Please read those sections first. - - -== Examples - - validates_datetime :occurred_at - - validates_date :date_of_birth, before: lambda { 18.years.ago }, - before_message: "must be at least 18 years old" - - validates_datetime :finish_time, after: :start_time # Method symbol - - validates_date :booked_at, on: :create, on_or_after: :today # See Restriction Shorthand. - - 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', - on_or_after_message: 'must be after opening time', - before: :lunchtime, - before_message: 'must be before lunch time' - - -== Usage - -To validate a model with a date, time or datetime attribute you just use the -validation method - - class Person < ActiveRecord::Base - validates_date :date_of_birth, on_or_before: lambda { Date.current } - # or - validates :date_of_birth, timeliness: {on_or_before: lambda { Date.current }, type: :date} - end - -or even on a specific record, per ActiveModel API. - - @person.validates_date :date_of_birth, on_or_before: lambda { Date.current } - - -The list of validation methods available are as follows: - validates_date - validate value as date - validates_time - validate value as time only i.e. '12:20pm' - validates_datetime - validate value as a full date and time - validates - use the :timeliness key and set the type in the hash. - -The validation methods take the usual options plus some specific ones to restrict -the valid range of dates or times allowed - -Temporal options (or restrictions): - :is_at - Attribute must be equal to value to be valid - :before - Attribute must be before this value to be valid - :on_or_before - Attribute must be equal to or before this value to be valid - :after - Attribute must be after this value to be valid - :on_or_after - Attribute must be equal to or after this value to be valid - :between - Attribute must be between the values to be valid. Range or Array of 2 values. - -Regular validation options: - :allow_nil - Allow a nil value to be valid - :allow_blank - Allows a nil or empty string value to be valid - :if - Execute validation when :if evaluates true - :unless - Execute validation when :unless evaluates false - :on - Specify validation context e.g :save, :create or :update. Default is :save. - -Special options: - :ignore_usec - Ignores microsecond value on datetime restrictions - :format - Limit validation to a single format for special cases. Requires plugin parser. - -The temporal restrictions can take 4 different value types: - -* Date, Time, or DateTime object value -* Proc or lambda object which may take an optional parameter, being the record object -* A symbol matching a method name in the model -* String value - -When an attribute value is compared to temporal restrictions, they are compared as -the same type as the validation method type. So using validates_date means all -values are compared as dates. - - -== Configuration - -=== ORM/ODM Support - -The plugin adds date/time validation to ActiveModel for any ORM/ODM that supports the ActiveModel validations component. -However, there is an issue with most ORM/ODMs which does not allow 100% date/time validation by default. Specifically, when you -assign an invalid date/time value to an attribute, most ORM/ODMs will only store a nil value for the attribute. This causes an -issue for date/time validation, since we need to know that a value was assigned but was invalid. To fix this, we need to cache -the original invalid value to know that the attribute is not just nil. - -Each ORM/ODM requires a specific shim to fix it. The plugin includes a shim for ActiveRecord and Mongoid. You can activate them -like so - - ValidatesTimeliness.setup do |config| - - # Extend ORM/ODMs for full support (:active_record). - config.extend_orms = [ :active_record ] - - end - -By default the plugin extends ActiveRecord if loaded. If you wish to extend another ORM then look at the {wiki page}[http://github.com/adzap/validates_timeliness/wiki/ORM-Support] for more information. - -It is not required that you use a shim, but you will not catch errors when the attribute value is invalid and evaluated to nil. - - -=== Error Messages - -Using the I18n system to define new defaults: - - en: - errors: - messages: - invalid_date: "is not a valid date" - invalid_time: "is not a valid time" - invalid_datetime: "is not a valid datetime" - is_at: "must be at %{restriction}" - before: "must be before %{restriction}" - on_or_before: "must be on or before %{restriction}" - after: "must be after %{restriction}" - on_or_after: "must be on or after %{restriction}" - -The %{restriction} signifies where the interpolation value for the restriction will be inserted. - -You can also use validation options for custom error messages. The following option keys are available: - - :invalid_date_message - :invalid_time_message - :invalid_datetime_message - :is_at_message - :before_message - :on_or_before_message - :after_message - :on_or_after_message - -Note: There is no :between_message option. The between error message should be defined using the :on_or_after and :on_or_before -(: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. - - -=== Plugin Parser - -The plugin uses the {timeliness gem}[http://github.com/adzap/timeliness] as a fast, configurable and extensible date and time parser. -You can add or remove valid formats for dates, times, and datetimes. It is also more strict than the -Ruby parser, which means it won't accept day of the month if it's not a valid number for the month. - -By default the parser is disabled. To enable it: - - # in the setup block - config.use_plugin_parser = true - -Enabling the parser will mean that strings assigned to attributes validated with the plugin will be parsed -using the gem. See the wiki[http://github.com/adzap/validates_timeliness/wiki/Plugin-Parser] for more details about the parser configuration. - - -=== Restriction Shorthand - -It is common to restrict an attribute to being on or before the current time or current day. -To specify this you need to use a lambda as an option value e.g. lambda { Time.current }. -This can be tedious noise amongst your validations for something so common. To combat this the -plugin allows you to use shorthand symbols for often used relative times or dates. - -Just provide the symbol as the option value like so: - - validates_date :birth_date, on_or_before: :today - -The :today symbol is evaluated as lambda { Date.today }. The :now and :today -symbols are pre-configured. Configure your own like so: - - # in the setup block - config.restriction_shorthand_symbols.update( - yesterday: lambda { 1.day.ago } - ) - - -=== Default Timezone - -The plugin needs to know the default timezone you are using when parsing or type casting values. If you are using -ActiveRecord then the default is automatically set to the same default zone as ActiveRecord. If you are using -another ORM you may need to change this setting. - - # in the setup block - config.default_timezone = :utc - -By default it will be UTC if ActiveRecord is not loaded. - - -=== Dummy Date For Time Types - -Given that Ruby has no support for a time-only type, all time type columns are evaluated -as a regular Time class objects with a dummy date value set. Rails defines the dummy date as -2000-01-01. So a time of '12:30' is evaluated as a Time value of '2000-01-01 12:30'. If you -need to customize this for some reason you can do so as follows - - # in the setup block - config.dummy_date_for_time_type = [2009, 1, 1] - -The value should be an array of 3 values being year, month and day in that order. - - -=== Temporal Restriction Errors - -When using the validation temporal restrictions there are times when the restriction -option value itself may be invalid. This will add an error to the model such as -'Error occurred validating birth_date for :before restriction'. These can be annoying -in development or production as you most likely just want to skip the option if no -valid value was returned. By default these errors are displayed in Rails test mode. - -To turn them on/off: - - # in the setup block - config.ignore_restriction_errors = true - - -== Extensions - -=== Strict Parsing for Select Helpers - -When using date/time select helpers, the component values are handled by ActiveRecord using -the Time class to instantiate them into a time value. This means that some invalid dates, -such as 31st June, are shifted forward and treated as valid. To handle these cases in a strict -way, you can enable the plugin extension to treat them as invalid dates. - -To activate it, uncomment this line in the initializer: - - # in the setup block - config.enable_multiparameter_extension! - - -=== Display Invalid Values in Select Helpers - -The plugin offers an extension for ActionView to allowing invalid date and time values to be -redisplayed to the user as feedback, instead of a blank field which happens by default in -Rails. Though the date helpers make this a pretty rare occurrence, given the select dropdowns -for each date/time component, but it may be something of interest. - -To activate it, uncomment this line in the initializer: - - # in the setup block - config.enable_date_time_select_extension! - - -== Contributors - -To see the generous people who have contributed code, take a look at the {contributors list}[http://github.com/adzap/validates_timeliness/contributors]. - - -== Maintainers - -* {Adam Meehan}[http://github.com/adzap] - - -== License - -Copyright (c) 2008 Adam Meehan, released under the MIT license diff --git a/Rakefile b/Rakefile index 1ca3a14..0c2067a 100644 --- a/Rakefile +++ b/Rakefile @@ -19,10 +19,11 @@ end desc 'Generate documentation for plugin.' Rake::RDocTask.new(:rdoc) do |rdoc| + rdoc.main = 'README.md' rdoc.rdoc_dir = 'rdoc' rdoc.title = 'ValidatesTimeliness' rdoc.options << '--line-numbers' << '--inline-source' - rdoc.rdoc_files.include('README') + rdoc.rdoc_files.include('README.md') rdoc.rdoc_files.include('lib/**/*.rb') end diff --git a/validates_timeliness.gemspec b/validates_timeliness.gemspec index 7e4716c..182e573 100644 --- a/validates_timeliness.gemspec +++ b/validates_timeliness.gemspec @@ -15,7 +15,7 @@ Gem::Specification.new do |s| s.require_paths = ["lib"] 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.extra_rdoc_files = ["README.rdoc", "CHANGELOG.rdoc", "LICENSE"] + s.extra_rdoc_files = ["README.md", "CHANGELOG.rdoc", "LICENSE"] s.add_runtime_dependency(%q, [">= 0.3.10", "< 1"]) end