require "hiccup/convenience" require "active_support/concern" module Hiccup module Validatable include Convenience extend ActiveSupport::Concern # !todo: use ActiveModel:Validation rather than a custom method included do validates :skip, numericality: {greater_than: 0} validate :validate_recurrence end private # !todo: use i18n to let clients of this library supply their own wording def validate_recurrence case kind when :never; when :weekly; validate_weekly_recurrence when :monthly; validate_monthly_recurrence when :annually; else; invalid_kind! end errors.add :start_date, "is a #{start_date.class} not a Date" unless start_date.is_a?(Date) if ends? if end_date.is_a?(Date) errors.add :end_date, "cannot be before start" if start_date.is_a?(Date) && end_date < start_date else errors.add :end_date, "is a #{end_date.class} not a Date" end end end def validate_weekly_recurrence if !weekly_pattern.is_a?(Array) errors.add(:weekly_pattern, "is a #{weekly_pattern.class}. It should be an array") elsif weekly_pattern.empty? errors.add(:weekly_pattern, "is empty. It should contain a list of weekdays") elsif (invalid_names = weekly_pattern - Date::DAYNAMES).any? errors.add(:weekly_pattern, "should contain only weekdays. (#{invalid_names.to_sentence} are invalid)") end end def validate_monthly_recurrence if !monthly_pattern.is_a?(Array) errors.add(:monthly_pattern, "is a #{monthly_pattern.class}. It should be an array") elsif monthly_pattern.empty? errors.add(:monthly_pattern, "is empty. It should contain a list of monthly occurrences") elsif monthly_pattern.select(&method(:invalid_occurrence?)).any? errors.add(:monthly_pattern, "contains invalid monthly occurrences") end end def invalid_occurrence?(occurrence) !valid_occurrence?(occurrence) end def valid_occurrence?(occurrence) if occurrence.is_a?(Array) i, wd = occurrence Date::DAYNAMES.member?(wd) && i.is_a?(Fixnum) && ((i == -1) || (1..6).include?(i)) else i = occurrence i.is_a?(Fixnum) && ([-1] + (1..31).to_a).include?(i) end end def invalid_kind! errors.add(:kind, "#{kind.inspect} is not recognized. It must be one of #{Kinds.collect{|kind| ":#{kind}"}.to_sentence(:two_words_connector => " or ", :last_word_connector => ", or ")}.") end # def valid_occurrence?(occurrence) # if occurrence.is_a?(Array) # ordinal, kind = occurrence # # errors.add(:kind, "is not a valid monthly occurrence kind") unless Date::DAYNAMES.member?(kind) # if ordinal.is_a?(Fixnum) # errors.add(:ordinal, "is not a valid integer") unless (ordinal==-1) or (1..6).include?(ordinal) # else # errors.add(:ordinal, "is not an integer") # end # else # ordinal = occurrence # # if ordinal.is_a?(Fixnum) # errors.add(:ordinal, "is not an integer between 1 and 31") unless (1..31).include?(ordinal) # else # errors.add(:ordinal, "is not an integer") # end # end # end end end