ice_cube 0.16.0 → 0.16.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +5 -5
- data/config/locales/de.yml +1 -1
- data/config/locales/en.yml +7 -46
- data/config/locales/es.yml +47 -83
- data/config/locales/fr.yml +2 -2
- data/config/locales/it.yml +179 -0
- data/config/locales/ja.yml +52 -29
- data/config/locales/nl.yml +133 -0
- data/config/locales/pt-BR.yml +178 -0
- data/config/locales/sv.yml +1 -1
- data/lib/ice_cube/i18n.rb +11 -12
- data/lib/ice_cube/input_alignment.rb +89 -0
- data/lib/ice_cube/null_i18n.rb +12 -6
- data/lib/ice_cube/occurrence.rb +25 -23
- data/lib/ice_cube/parsers/ical_parser.rb +8 -5
- data/lib/ice_cube/rule.rb +5 -13
- data/lib/ice_cube/rules/daily_rule.rb +9 -0
- data/lib/ice_cube/rules/hourly_rule.rb +9 -0
- data/lib/ice_cube/rules/minutely_rule.rb +9 -0
- data/lib/ice_cube/rules/monthly_rule.rb +9 -0
- data/lib/ice_cube/rules/secondly_rule.rb +9 -0
- data/lib/ice_cube/rules/weekly_rule.rb +30 -9
- data/lib/ice_cube/rules/yearly_rule.rb +9 -0
- data/lib/ice_cube/schedule.rb +30 -29
- data/lib/ice_cube/single_occurrence_rule.rb +4 -0
- data/lib/ice_cube/time_util.rb +65 -46
- data/lib/ice_cube/validated_rule.rb +18 -24
- data/lib/ice_cube/validations/count.rb +1 -2
- data/lib/ice_cube/validations/daily_interval.rb +5 -1
- data/lib/ice_cube/validations/day.rb +6 -2
- data/lib/ice_cube/validations/day_of_month.rb +5 -0
- data/lib/ice_cube/validations/day_of_week.rb +1 -1
- data/lib/ice_cube/validations/hour_of_day.rb +23 -0
- data/lib/ice_cube/validations/hourly_interval.rb +2 -0
- data/lib/ice_cube/validations/minute_of_hour.rb +16 -0
- data/lib/ice_cube/validations/minutely_interval.rb +2 -0
- data/lib/ice_cube/validations/month_of_year.rb +6 -1
- data/lib/ice_cube/validations/monthly_interval.rb +4 -1
- data/lib/ice_cube/validations/schedule_lock.rb +4 -0
- data/lib/ice_cube/validations/second_of_minute.rb +19 -3
- data/lib/ice_cube/validations/secondly_interval.rb +2 -0
- data/lib/ice_cube/validations/until.rb +1 -2
- data/lib/ice_cube/validations/weekly_interval.rb +0 -2
- data/lib/ice_cube/version.rb +1 -1
- data/lib/ice_cube.rb +1 -3
- data/spec/spec_helper.rb +32 -9
- metadata +10 -7
| @@ -0,0 +1,178 @@ | |
| 1 | 
            +
            pt-BR:
         | 
| 2 | 
            +
              ice_cube:
         | 
| 3 | 
            +
                pieces_connector: ' / '
         | 
| 4 | 
            +
                not: 'exceto %{target}'
         | 
| 5 | 
            +
                not_on: 'exceto o dia %{target}'
         | 
| 6 | 
            +
                date:
         | 
| 7 | 
            +
                  formats:
         | 
| 8 | 
            +
                    default: '%-d %B %Y'
         | 
| 9 | 
            +
                  month_names:
         | 
| 10 | 
            +
                  -
         | 
| 11 | 
            +
                  - Janeiro
         | 
| 12 | 
            +
                  - Fevereiro
         | 
| 13 | 
            +
                  - Março
         | 
| 14 | 
            +
                  - Abril
         | 
| 15 | 
            +
                  - Maio
         | 
| 16 | 
            +
                  - Junho
         | 
| 17 | 
            +
                  - Julho
         | 
| 18 | 
            +
                  - Agosto
         | 
| 19 | 
            +
                  - Setembro
         | 
| 20 | 
            +
                  - Outubro
         | 
| 21 | 
            +
                  - Novembro
         | 
| 22 | 
            +
                  - Dezembro
         | 
| 23 | 
            +
                  day_names:
         | 
| 24 | 
            +
                  - Domingo
         | 
| 25 | 
            +
                  - Segunda
         | 
| 26 | 
            +
                  - Terça
         | 
| 27 | 
            +
                  - Quarta
         | 
| 28 | 
            +
                  - Quinta
         | 
| 29 | 
            +
                  - Sexta
         | 
| 30 | 
            +
                  - Sábado
         | 
| 31 | 
            +
                times:
         | 
| 32 | 
            +
                  other: '%{count} vezes'
         | 
| 33 | 
            +
                  one: '%{count} vez'
         | 
| 34 | 
            +
                until: 'até %{date}'
         | 
| 35 | 
            +
                days_of_week: '%{segments} %{day}'
         | 
| 36 | 
            +
                days_of_month:
         | 
| 37 | 
            +
                  other: '%{segments} dias do mês'
         | 
| 38 | 
            +
                  one: '%{segments} dia'
         | 
| 39 | 
            +
                days_of_year:
         | 
| 40 | 
            +
                  other: '%{segments} dias do ano'
         | 
| 41 | 
            +
                  one: '%{segments} dia'
         | 
| 42 | 
            +
                at_hours_of_the_day:
         | 
| 43 | 
            +
                  other: às %{segments} horas
         | 
| 44 | 
            +
                  one: à %{segments} hora
         | 
| 45 | 
            +
                on_minutes_of_hour:
         | 
| 46 | 
            +
                  other: aos %{segments} minutos
         | 
| 47 | 
            +
                  one: ao %{segments} minuto
         | 
| 48 | 
            +
                at_seconds_of_minute:
         | 
| 49 | 
            +
                  other: aos %{segments} segundos
         | 
| 50 | 
            +
                  one: ao %{segments} segundo
         | 
| 51 | 
            +
                on_seconds_of_minute:
         | 
| 52 | 
            +
                  other: aos %{segments} segundos
         | 
| 53 | 
            +
                  one: ao %{segments} segundo
         | 
| 54 | 
            +
                each_second:
         | 
| 55 | 
            +
                  one: A cada segundo
         | 
| 56 | 
            +
                  other: A cada %{count} segundos
         | 
| 57 | 
            +
                each_minute:
         | 
| 58 | 
            +
                  one: A cada minuto
         | 
| 59 | 
            +
                  other: A cada %{count} minutos
         | 
| 60 | 
            +
                each_hour:
         | 
| 61 | 
            +
                  one: A cada hora
         | 
| 62 | 
            +
                  other: A cada %{count} horas
         | 
| 63 | 
            +
                each_day:
         | 
| 64 | 
            +
                  one: Diariamente
         | 
| 65 | 
            +
                  other: A cada %{count} dias
         | 
| 66 | 
            +
                each_week:
         | 
| 67 | 
            +
                  one: Semanalmente
         | 
| 68 | 
            +
                  other: A cada %{count} semanas
         | 
| 69 | 
            +
                each_month:
         | 
| 70 | 
            +
                  one: Mensalmente
         | 
| 71 | 
            +
                  other: A cada %{count} meses
         | 
| 72 | 
            +
                each_year:
         | 
| 73 | 
            +
                  one: Anualmente
         | 
| 74 | 
            +
                  other: A cada %{count} anos
         | 
| 75 | 
            +
                'on': no %{sentence}
         | 
| 76 | 
            +
                in: 'em %{target}'
         | 
| 77 | 
            +
                integer:
         | 
| 78 | 
            +
                  negative: '%{ordinal} depois que acabar'
         | 
| 79 | 
            +
                  literal_ordinals:
         | 
| 80 | 
            +
                    -1: último
         | 
| 81 | 
            +
                    -2: penúltimo
         | 
| 82 | 
            +
                  ordinal: '%{number}%{ordinal}'
         | 
| 83 | 
            +
                  ordinals:
         | 
| 84 | 
            +
                    default: º
         | 
| 85 | 
            +
                    1: º
         | 
| 86 | 
            +
                    2: º
         | 
| 87 | 
            +
                    3: º
         | 
| 88 | 
            +
                    11: º
         | 
| 89 | 
            +
                    12: º
         | 
| 90 | 
            +
                    13: º
         | 
| 91 | 
            +
                on_weekends: nos finais de semana
         | 
| 92 | 
            +
                on_weekdays: nos dias úteis
         | 
| 93 | 
            +
                days_on:
         | 
| 94 | 
            +
                  - Domingos
         | 
| 95 | 
            +
                  - Segundas-feiras
         | 
| 96 | 
            +
                  - Terças-feiras
         | 
| 97 | 
            +
                  - Quartas-feiras
         | 
| 98 | 
            +
                  - Quintas-feiras
         | 
| 99 | 
            +
                  - Sextas-feiras
         | 
| 100 | 
            +
                  - Sábados
         | 
| 101 | 
            +
                on_days: no dia %{days}
         | 
| 102 | 
            +
                array:
         | 
| 103 | 
            +
                  last_word_connector: ' e '
         | 
| 104 | 
            +
                  two_words_connector: ' e '
         | 
| 105 | 
            +
                  words_connector: ', '
         | 
| 106 | 
            +
                string:
         | 
| 107 | 
            +
                  format:
         | 
| 108 | 
            +
                    day: '%{rest} %{current}'
         | 
| 109 | 
            +
                    day_of_week: '%{rest} %{current}'
         | 
| 110 | 
            +
                    day_of_month: '%{rest} %{current}'
         | 
| 111 | 
            +
                    day_of_year: '%{rest} %{current}'
         | 
| 112 | 
            +
                    hour_of_day: '%{rest} %{current}'
         | 
| 113 | 
            +
                    minute_of_hour: '%{rest} %{current}'
         | 
| 114 | 
            +
                    until: '%{rest} %{current}'
         | 
| 115 | 
            +
                    count: '%{rest} %{current}'
         | 
| 116 | 
            +
                    default: '%{rest} %{current}'
         | 
| 117 | 
            +
             | 
| 118 | 
            +
              date:
         | 
| 119 | 
            +
                abbr_day_names:
         | 
| 120 | 
            +
                - Dom
         | 
| 121 | 
            +
                - Seg
         | 
| 122 | 
            +
                - Ter
         | 
| 123 | 
            +
                - Qua
         | 
| 124 | 
            +
                - Qui
         | 
| 125 | 
            +
                - Sex
         | 
| 126 | 
            +
                - Sáb
         | 
| 127 | 
            +
                abbr_month_names:
         | 
| 128 | 
            +
                -
         | 
| 129 | 
            +
                - Jan
         | 
| 130 | 
            +
                - Fev
         | 
| 131 | 
            +
                - Mar
         | 
| 132 | 
            +
                - Abr
         | 
| 133 | 
            +
                - Mai
         | 
| 134 | 
            +
                - Jun
         | 
| 135 | 
            +
                - Jul
         | 
| 136 | 
            +
                - Ago
         | 
| 137 | 
            +
                - Set
         | 
| 138 | 
            +
                - Out
         | 
| 139 | 
            +
                - Nov
         | 
| 140 | 
            +
                - Dez
         | 
| 141 | 
            +
                day_names:
         | 
| 142 | 
            +
                - Domingo
         | 
| 143 | 
            +
                - Segunda-feira
         | 
| 144 | 
            +
                - Terça-feira
         | 
| 145 | 
            +
                - Quarta-feira
         | 
| 146 | 
            +
                - Quinta-feira
         | 
| 147 | 
            +
                - Sexta-feira
         | 
| 148 | 
            +
                - Sábado
         | 
| 149 | 
            +
                formats:
         | 
| 150 | 
            +
                  default: "%d/%m/%Y"
         | 
| 151 | 
            +
                  long: "%d de %B de %Y"
         | 
| 152 | 
            +
                  short: "%d de %B"
         | 
| 153 | 
            +
                month_names:
         | 
| 154 | 
            +
                -
         | 
| 155 | 
            +
                - Janeiro
         | 
| 156 | 
            +
                - Fevereiro
         | 
| 157 | 
            +
                - Março
         | 
| 158 | 
            +
                - Abril
         | 
| 159 | 
            +
                - Maio
         | 
| 160 | 
            +
                - Junho
         | 
| 161 | 
            +
                - Julho
         | 
| 162 | 
            +
                - Agosto
         | 
| 163 | 
            +
                - Setembro
         | 
| 164 | 
            +
                - Outubro
         | 
| 165 | 
            +
                - Novembro
         | 
| 166 | 
            +
                - Dezembro
         | 
| 167 | 
            +
                order:
         | 
| 168 | 
            +
                - :day
         | 
| 169 | 
            +
                - :month
         | 
| 170 | 
            +
                - :year
         | 
| 171 | 
            +
             | 
| 172 | 
            +
              time:
         | 
| 173 | 
            +
                am: ''
         | 
| 174 | 
            +
                formats:
         | 
| 175 | 
            +
                  default: "%a, %d de %B de %Y, %H:%M:%S %z"
         | 
| 176 | 
            +
                  long: "%d de %B de %Y, %H:%M"
         | 
| 177 | 
            +
                  short: "%d de %B, %H:%M"
         | 
| 178 | 
            +
                pm: ''
         | 
    
        data/config/locales/sv.yml
    CHANGED
    
    
    
        data/lib/ice_cube/i18n.rb
    CHANGED
    
    | @@ -1,24 +1,23 @@ | |
| 1 | 
            +
            require 'ice_cube/null_i18n'
         | 
| 2 | 
            +
             | 
| 1 3 | 
             
            module IceCube
         | 
| 2 4 | 
             
              module I18n
         | 
| 3 | 
            -
                def self.t(*args)
         | 
| 4 | 
            -
                  backend.t(*args)
         | 
| 5 | 
            -
                end
         | 
| 6 5 |  | 
| 7 | 
            -
                 | 
| 8 | 
            -
             | 
| 6 | 
            +
                LOCALES_PATH = File.expand_path(File.join('..', '..', '..', 'config', 'locales'), __FILE__)
         | 
| 7 | 
            +
             | 
| 8 | 
            +
                class << self
         | 
| 9 | 
            +
                  delegate :t, :l, to: :backend
         | 
| 9 10 | 
             
                end
         | 
| 10 11 |  | 
| 11 12 | 
             
                def self.backend
         | 
| 12 | 
            -
                  @backend
         | 
| 13 | 
            +
                  @backend ||= detect_backend!
         | 
| 13 14 | 
             
                end
         | 
| 14 15 |  | 
| 15 16 | 
             
                def self.detect_backend!
         | 
| 16 | 
            -
                   | 
| 17 | 
            -
                  ::I18n | 
| 18 | 
            -
             | 
| 19 | 
            -
             | 
| 20 | 
            -
                  require 'ice_cube/null_i18n'
         | 
| 21 | 
            -
                  @backend = NullI18n
         | 
| 17 | 
            +
                  ::I18n.load_path += Dir[File.join(LOCALES_PATH, '*.yml')]
         | 
| 18 | 
            +
                  ::I18n
         | 
| 19 | 
            +
                rescue NameError
         | 
| 20 | 
            +
                  NullI18n
         | 
| 22 21 | 
             
                end
         | 
| 23 22 | 
             
              end
         | 
| 24 23 | 
             
            end
         | 
| @@ -0,0 +1,89 @@ | |
| 1 | 
            +
            module IceCube
         | 
| 2 | 
            +
              class InputAlignment
         | 
| 3 | 
            +
             | 
| 4 | 
            +
                def initialize(rule, value, rule_part)
         | 
| 5 | 
            +
                  @rule = rule
         | 
| 6 | 
            +
                  @value = value
         | 
| 7 | 
            +
                  @rule_part = rule_part
         | 
| 8 | 
            +
                end
         | 
| 9 | 
            +
             | 
| 10 | 
            +
                attr_reader :rule, :value, :rule_part
         | 
| 11 | 
            +
             | 
| 12 | 
            +
                def verify(freq, options={}, &block)
         | 
| 13 | 
            +
                  @rule.validations[:interval] or return
         | 
| 14 | 
            +
             | 
| 15 | 
            +
                  case @rule
         | 
| 16 | 
            +
                  when DailyRule
         | 
| 17 | 
            +
                    verify_wday_alignment(freq, &block)
         | 
| 18 | 
            +
                  when MonthlyRule
         | 
| 19 | 
            +
                    verify_month_alignment(freq, &block)
         | 
| 20 | 
            +
                  else
         | 
| 21 | 
            +
                    verify_freq_alignment(freq, &block)
         | 
| 22 | 
            +
                  end
         | 
| 23 | 
            +
                end
         | 
| 24 | 
            +
             | 
| 25 | 
            +
                private
         | 
| 26 | 
            +
             | 
| 27 | 
            +
                def interval_validation
         | 
| 28 | 
            +
                  @interval_validation ||= @rule.validations[:interval].first
         | 
| 29 | 
            +
                end
         | 
| 30 | 
            +
             | 
| 31 | 
            +
                def interval_value
         | 
| 32 | 
            +
                  @interval_value ||= (rule_part == :interval) ? value : interval_validation.interval
         | 
| 33 | 
            +
                end
         | 
| 34 | 
            +
             | 
| 35 | 
            +
                def fixed_validations
         | 
| 36 | 
            +
                  @fixed_validations ||= @rule.validations.values.flatten.select { |v|
         | 
| 37 | 
            +
                    interval_type = (v.type == :wday ? :day : v.type)
         | 
| 38 | 
            +
                    v.class < Validations::FixedValue &&
         | 
| 39 | 
            +
                      interval_type == rule.base_interval_validation.type
         | 
| 40 | 
            +
                  }
         | 
| 41 | 
            +
                end
         | 
| 42 | 
            +
             | 
| 43 | 
            +
                def verify_freq_alignment(freq)
         | 
| 44 | 
            +
                  interval_validation.type == freq or return
         | 
| 45 | 
            +
                  (last_validation = fixed_validations.min_by(&:value)) or return
         | 
| 46 | 
            +
             | 
| 47 | 
            +
                  alignment = (value - last_validation.value) % interval_validation.interval
         | 
| 48 | 
            +
                  return if alignment.zero?
         | 
| 49 | 
            +
             | 
| 50 | 
            +
                  validation_values = fixed_validations.map(&:value).join(', ')
         | 
| 51 | 
            +
                  if rule_part == :interval
         | 
| 52 | 
            +
                    message = "interval(#{value}) " \
         | 
| 53 | 
            +
                              "must be a multiple of " \
         | 
| 54 | 
            +
                              "intervals in #{last_validation.key}(#{validation_values})"
         | 
| 55 | 
            +
                  else
         | 
| 56 | 
            +
                    message = "intervals in #{last_validation.key}(#{validation_values}, #{value}) " \
         | 
| 57 | 
            +
                              "must be multiples of " \
         | 
| 58 | 
            +
                              "interval(#{interval_validation.interval})"
         | 
| 59 | 
            +
                  end
         | 
| 60 | 
            +
             | 
| 61 | 
            +
                  yield ArgumentError.new(message)
         | 
| 62 | 
            +
                end
         | 
| 63 | 
            +
             | 
| 64 | 
            +
                def verify_month_alignment(_freq)
         | 
| 65 | 
            +
                  return if interval_value == 1 || (interval_value % 12).zero?
         | 
| 66 | 
            +
                  return if fixed_validations.empty?
         | 
| 67 | 
            +
             | 
| 68 | 
            +
                  message = "month_of_year can only be used with interval(1) or multiples of interval(12)"
         | 
| 69 | 
            +
             | 
| 70 | 
            +
                  yield ArgumentError.new(message)
         | 
| 71 | 
            +
                end
         | 
| 72 | 
            +
             | 
| 73 | 
            +
                def verify_wday_alignment(freq)
         | 
| 74 | 
            +
                  return if interval_value == 1
         | 
| 75 | 
            +
             | 
| 76 | 
            +
                  if freq == :wday
         | 
| 77 | 
            +
                    return if (interval_value % 7).zero?
         | 
| 78 | 
            +
                    return if Array(@rule.validations[:day]).empty?
         | 
| 79 | 
            +
                    message = "day can only be used with multiples of interval(7)"
         | 
| 80 | 
            +
                  else
         | 
| 81 | 
            +
                    (fixed_validation = fixed_validations.first) or return
         | 
| 82 | 
            +
                    message = "#{fixed_validation.key} can only be used with interval(1)"
         | 
| 83 | 
            +
                  end
         | 
| 84 | 
            +
             | 
| 85 | 
            +
                  yield ArgumentError.new(message)
         | 
| 86 | 
            +
                end
         | 
| 87 | 
            +
             | 
| 88 | 
            +
              end
         | 
| 89 | 
            +
            end
         | 
    
        data/lib/ice_cube/null_i18n.rb
    CHANGED
    
    | @@ -7,13 +7,19 @@ module IceCube | |
| 7 7 |  | 
| 8 8 | 
             
                  base = base[options[:count] == 1 ? "one" : "other"] if options[:count]
         | 
| 9 9 |  | 
| 10 | 
            -
                   | 
| 11 | 
            -
             | 
| 12 | 
            -
             | 
| 10 | 
            +
                  case base
         | 
| 11 | 
            +
                  when Hash
         | 
| 12 | 
            +
                    base.each_with_object({}) do |(k, v), hash|
         | 
| 13 | 
            +
                      hash[k.is_a?(String) ? k.to_sym : k] = v
         | 
| 13 14 | 
             
                    end
         | 
| 15 | 
            +
                  when Array
         | 
| 16 | 
            +
                    base.each_with_index.each_with_object({}) do |(v, k), hash|
         | 
| 17 | 
            +
                      hash[k] = v
         | 
| 18 | 
            +
                    end
         | 
| 19 | 
            +
                  else
         | 
| 20 | 
            +
                    return base unless base.include?('%{')
         | 
| 21 | 
            +
                    base % options
         | 
| 14 22 | 
             
                  end
         | 
| 15 | 
            -
             | 
| 16 | 
            -
                  options.reduce(base) { |result, (find, replace)| result.gsub("%{#{find}}", "#{replace}") }
         | 
| 17 23 | 
             
                end
         | 
| 18 24 |  | 
| 19 25 | 
             
                def self.l(date_or_time, options = {})
         | 
| @@ -22,7 +28,7 @@ module IceCube | |
| 22 28 | 
             
                end
         | 
| 23 29 |  | 
| 24 30 | 
             
                def self.config
         | 
| 25 | 
            -
                  @config ||= YAML. | 
| 31 | 
            +
                  @config ||= YAML.load_file(File.join(IceCube::I18n::LOCALES_PATH, 'en.yml'))['en']
         | 
| 26 32 | 
             
                end
         | 
| 27 33 | 
             
              end
         | 
| 28 34 | 
             
            end
         | 
    
        data/lib/ice_cube/occurrence.rb
    CHANGED
    
    | @@ -1,4 +1,3 @@ | |
| 1 | 
            -
            require 'forwardable'
         | 
| 2 1 | 
             
            require 'delegate'
         | 
| 3 2 |  | 
| 4 3 | 
             
            module IceCube
         | 
| @@ -20,18 +19,16 @@ module IceCube | |
| 20 19 | 
             
              #     Time.now - Occurrence.new(start_time) # => 3600
         | 
| 21 20 | 
             
              #
         | 
| 22 21 | 
             
              class Occurrence < SimpleDelegator
         | 
| 22 | 
            +
                include Comparable
         | 
| 23 23 |  | 
| 24 24 | 
             
                # Report class name as 'Time' to thwart type checking.
         | 
| 25 25 | 
             
                def self.name
         | 
| 26 26 | 
             
                  'Time'
         | 
| 27 27 | 
             
                end
         | 
| 28 28 |  | 
| 29 | 
            -
                # Optimize for common methods to avoid method_missing
         | 
| 30 | 
            -
                extend Forwardable
         | 
| 31 | 
            -
                def_delegators :start_time, :to_i, :<=>, :==
         | 
| 32 | 
            -
                def_delegators :to_range, :cover?, :include?, :each, :first, :last
         | 
| 33 | 
            -
             | 
| 34 29 | 
             
                attr_reader :start_time, :end_time
         | 
| 30 | 
            +
                alias first start_time
         | 
| 31 | 
            +
                alias last end_time
         | 
| 35 32 |  | 
| 36 33 | 
             
                def initialize(start_time, end_time=nil)
         | 
| 37 34 | 
             
                  @start_time = start_time
         | 
| @@ -39,29 +36,34 @@ module IceCube | |
| 39 36 | 
             
                  __setobj__ @start_time
         | 
| 40 37 | 
             
                end
         | 
| 41 38 |  | 
| 39 | 
            +
                def to_i
         | 
| 40 | 
            +
                  @start_time.to_i
         | 
| 41 | 
            +
                end
         | 
| 42 | 
            +
             | 
| 43 | 
            +
                def <=>(other)
         | 
| 44 | 
            +
                  @start_time <=> other
         | 
| 45 | 
            +
                end
         | 
| 46 | 
            +
             | 
| 42 47 | 
             
                def is_a?(klass)
         | 
| 43 48 | 
             
                  klass == ::Time || super
         | 
| 44 49 | 
             
                end
         | 
| 45 50 | 
             
                alias_method :kind_of?, :is_a?
         | 
| 46 51 |  | 
| 47 | 
            -
                def intersects? | 
| 48 | 
            -
                   | 
| 49 | 
            -
             | 
| 50 | 
            -
             | 
| 51 | 
            -
             | 
| 52 | 
            -
             | 
| 53 | 
            -
             | 
| 54 | 
            -
             | 
| 55 | 
            -
             | 
| 56 | 
            -
             | 
| 57 | 
            -
             | 
| 58 | 
            -
             | 
| 59 | 
            -
             | 
| 60 | 
            -
                    end
         | 
| 61 | 
            -
                  else
         | 
| 62 | 
            -
                    cover? other
         | 
| 63 | 
            -
                  end
         | 
| 52 | 
            +
                def intersects?(other)
         | 
| 53 | 
            +
                  return cover?(other) unless other.is_a?(Occurrence) || other.is_a?(Range)
         | 
| 54 | 
            +
             | 
| 55 | 
            +
                  this_start  = first + 1
         | 
| 56 | 
            +
                  this_end    = last # exclude end boundary
         | 
| 57 | 
            +
                  other_start = other.first + 1
         | 
| 58 | 
            +
                  other_end   = other.last + 1
         | 
| 59 | 
            +
             | 
| 60 | 
            +
                  !(this_end < other_start || this_start > other_end)
         | 
| 61 | 
            +
                end
         | 
| 62 | 
            +
             | 
| 63 | 
            +
                def cover?(other)
         | 
| 64 | 
            +
                  to_range.cover?(other)
         | 
| 64 65 | 
             
                end
         | 
| 66 | 
            +
                alias_method :include?, :cover?
         | 
| 65 67 |  | 
| 66 68 | 
             
                def comparable_time
         | 
| 67 69 | 
             
                  start_time
         | 
| @@ -4,15 +4,18 @@ module IceCube | |
| 4 4 | 
             
                  data = {}
         | 
| 5 5 | 
             
                  ical_string.each_line do |line|
         | 
| 6 6 | 
             
                    (property, value) = line.split(':')
         | 
| 7 | 
            -
                    (property,  | 
| 7 | 
            +
                    (property, _tzid) = property.split(';')
         | 
| 8 8 | 
             
                    case property
         | 
| 9 9 | 
             
                    when 'DTSTART'
         | 
| 10 | 
            -
                      data[:start_time] =  | 
| 10 | 
            +
                      data[:start_time] = TimeUtil.deserialize_time(value)
         | 
| 11 11 | 
             
                    when 'DTEND'
         | 
| 12 | 
            -
                      data[:end_time] =  | 
| 12 | 
            +
                      data[:end_time] = TimeUtil.deserialize_time(value)
         | 
| 13 | 
            +
                    when 'RDATE'
         | 
| 14 | 
            +
                      data[:rtimes] ||= []
         | 
| 15 | 
            +
                      data[:rtimes] += value.split(',').map { |v| TimeUtil.deserialize_time(v) }
         | 
| 13 16 | 
             
                    when 'EXDATE'
         | 
| 14 17 | 
             
                      data[:extimes] ||= []
         | 
| 15 | 
            -
                      data[:extimes] += value.split(',').map{|v|  | 
| 18 | 
            +
                      data[:extimes] += value.split(',').map { |v| TimeUtil.deserialize_time(v) }
         | 
| 16 19 | 
             
                    when 'DURATION'
         | 
| 17 20 | 
             
                      data[:duration] # FIXME
         | 
| 18 21 | 
             
                    when 'RRULE'
         | 
| @@ -41,7 +44,7 @@ module IceCube | |
| 41 44 | 
             
                    when 'COUNT'
         | 
| 42 45 | 
             
                      params[:count] = value.to_i
         | 
| 43 46 | 
             
                    when 'UNTIL'
         | 
| 44 | 
            -
                      params[:until] =  | 
| 47 | 
            +
                      params[:until] = TimeUtil.deserialize_time(value).utc
         | 
| 45 48 | 
             
                    when 'WKST'
         | 
| 46 49 | 
             
                      params[:week_start] = TimeUtil.ical_day_to_symbol(value)
         | 
| 47 50 | 
             
                    when 'BYSECOND'
         | 
    
        data/lib/ice_cube/rule.rb
    CHANGED
    
    | @@ -19,20 +19,17 @@ module IceCube | |
| 19 19 | 
             
                  until_time || occurrence_count
         | 
| 20 20 | 
             
                end
         | 
| 21 21 |  | 
| 22 | 
            -
                def ==( | 
| 23 | 
            -
                   | 
| 24 | 
            -
             | 
| 25 | 
            -
                    hash && hash == rule.to_hash
         | 
| 26 | 
            -
                  end
         | 
| 22 | 
            +
                def ==(other)
         | 
| 23 | 
            +
                  return false unless other.is_a? Rule
         | 
| 24 | 
            +
                  hash == other.hash
         | 
| 27 25 | 
             
                end
         | 
| 28 26 |  | 
| 29 27 | 
             
                def hash
         | 
| 30 | 
            -
                   | 
| 31 | 
            -
                  h.nil? ? super : h.hash
         | 
| 28 | 
            +
                  to_hash.hash
         | 
| 32 29 | 
             
                end
         | 
| 33 30 |  | 
| 34 31 | 
             
                def to_ical
         | 
| 35 | 
            -
                  raise MethodNotImplemented, "Expected to be  | 
| 32 | 
            +
                  raise MethodNotImplemented, "Expected to be overridden by subclasses"
         | 
| 36 33 | 
             
                end
         | 
| 37 34 |  | 
| 38 35 | 
             
                # Convert from ical string and create a rule
         | 
| @@ -61,11 +58,6 @@ module IceCube | |
| 61 58 | 
             
                  next_time(time, schedule, time).to_i == time.to_i
         | 
| 62 59 | 
             
                end
         | 
| 63 60 |  | 
| 64 | 
            -
                # Whether this rule requires a full run
         | 
| 65 | 
            -
                def full_required?
         | 
| 66 | 
            -
                  !@count.nil?
         | 
| 67 | 
            -
                end
         | 
| 68 | 
            -
             | 
| 69 61 | 
             
                class << self
         | 
| 70 62 |  | 
| 71 63 | 
             
                  # Convert from a hash and create a rule
         | 
| @@ -2,6 +2,15 @@ module IceCube | |
| 2 2 |  | 
| 3 3 | 
             
              class DailyRule < ValidatedRule
         | 
| 4 4 |  | 
| 5 | 
            +
                include Validations::HourOfDay
         | 
| 6 | 
            +
                include Validations::MinuteOfHour
         | 
| 7 | 
            +
                include Validations::SecondOfMinute
         | 
| 8 | 
            +
                include Validations::DayOfMonth
         | 
| 9 | 
            +
                include Validations::DayOfWeek
         | 
| 10 | 
            +
                include Validations::Day
         | 
| 11 | 
            +
                include Validations::MonthOfYear
         | 
| 12 | 
            +
                # include Validations::DayOfYear    # n/a
         | 
| 13 | 
            +
             | 
| 5 14 | 
             
                include Validations::DailyInterval
         | 
| 6 15 |  | 
| 7 16 | 
             
                def initialize(interval = 1)
         | 
| @@ -2,6 +2,15 @@ module IceCube | |
| 2 2 |  | 
| 3 3 | 
             
              class HourlyRule < ValidatedRule
         | 
| 4 4 |  | 
| 5 | 
            +
                include Validations::HourOfDay
         | 
| 6 | 
            +
                include Validations::MinuteOfHour
         | 
| 7 | 
            +
                include Validations::SecondOfMinute
         | 
| 8 | 
            +
                include Validations::DayOfMonth
         | 
| 9 | 
            +
                include Validations::DayOfWeek
         | 
| 10 | 
            +
                include Validations::Day
         | 
| 11 | 
            +
                include Validations::MonthOfYear
         | 
| 12 | 
            +
                include Validations::DayOfYear
         | 
| 13 | 
            +
             | 
| 5 14 | 
             
                include Validations::HourlyInterval
         | 
| 6 15 |  | 
| 7 16 | 
             
                def initialize(interval = 1)
         | 
| @@ -2,6 +2,15 @@ module IceCube | |
| 2 2 |  | 
| 3 3 | 
             
              class MinutelyRule < ValidatedRule
         | 
| 4 4 |  | 
| 5 | 
            +
                include Validations::HourOfDay
         | 
| 6 | 
            +
                include Validations::MinuteOfHour
         | 
| 7 | 
            +
                include Validations::SecondOfMinute
         | 
| 8 | 
            +
                include Validations::DayOfMonth
         | 
| 9 | 
            +
                include Validations::DayOfWeek
         | 
| 10 | 
            +
                include Validations::Day
         | 
| 11 | 
            +
                include Validations::MonthOfYear
         | 
| 12 | 
            +
                include Validations::DayOfYear
         | 
| 13 | 
            +
             | 
| 5 14 | 
             
                include Validations::MinutelyInterval
         | 
| 6 15 |  | 
| 7 16 | 
             
                def initialize(interval = 1)
         | 
| @@ -2,6 +2,15 @@ module IceCube | |
| 2 2 |  | 
| 3 3 | 
             
              class MonthlyRule < ValidatedRule
         | 
| 4 4 |  | 
| 5 | 
            +
                include Validations::HourOfDay
         | 
| 6 | 
            +
                include Validations::MinuteOfHour
         | 
| 7 | 
            +
                include Validations::SecondOfMinute
         | 
| 8 | 
            +
                include Validations::DayOfMonth
         | 
| 9 | 
            +
                include Validations::DayOfWeek
         | 
| 10 | 
            +
                include Validations::Day
         | 
| 11 | 
            +
                include Validations::MonthOfYear
         | 
| 12 | 
            +
                # include Validations::DayOfYear    # n/a
         | 
| 13 | 
            +
             | 
| 5 14 | 
             
                include Validations::MonthlyInterval
         | 
| 6 15 |  | 
| 7 16 | 
             
                def initialize(interval = 1)
         | 
| @@ -2,6 +2,15 @@ module IceCube | |
| 2 2 |  | 
| 3 3 | 
             
              class SecondlyRule < ValidatedRule
         | 
| 4 4 |  | 
| 5 | 
            +
                include Validations::HourOfDay
         | 
| 6 | 
            +
                include Validations::MinuteOfHour
         | 
| 7 | 
            +
                include Validations::SecondOfMinute
         | 
| 8 | 
            +
                include Validations::DayOfMonth
         | 
| 9 | 
            +
                include Validations::DayOfWeek
         | 
| 10 | 
            +
                include Validations::Day
         | 
| 11 | 
            +
                include Validations::MonthOfYear
         | 
| 12 | 
            +
                include Validations::DayOfYear
         | 
| 13 | 
            +
             | 
| 5 14 | 
             
                include Validations::SecondlyInterval
         | 
| 6 15 |  | 
| 7 16 | 
             
                def initialize(interval = 1)
         | 
| @@ -2,6 +2,15 @@ module IceCube | |
| 2 2 |  | 
| 3 3 | 
             
              class WeeklyRule < ValidatedRule
         | 
| 4 4 |  | 
| 5 | 
            +
                include Validations::HourOfDay
         | 
| 6 | 
            +
                include Validations::MinuteOfHour
         | 
| 7 | 
            +
                include Validations::SecondOfMinute
         | 
| 8 | 
            +
                # include Validations::DayOfMonth   # n/a
         | 
| 9 | 
            +
                include Validations::DayOfWeek
         | 
| 10 | 
            +
                include Validations::Day
         | 
| 11 | 
            +
                include Validations::MonthOfYear
         | 
| 12 | 
            +
                # include Validations::DayOfYear    # n/a
         | 
| 13 | 
            +
             | 
| 5 14 | 
             
                include Validations::WeeklyInterval
         | 
| 6 15 |  | 
| 7 16 | 
             
                attr_reader :week_start
         | 
| @@ -13,25 +22,37 @@ module IceCube | |
| 13 22 | 
             
                  reset
         | 
| 14 23 | 
             
                end
         | 
| 15 24 |  | 
| 16 | 
            -
                #  | 
| 17 | 
            -
                # in the week than  | 
| 18 | 
            -
                # | 
| 19 | 
            -
                # | 
| 25 | 
            +
                # Move the effective start time to correct for when the schedule has
         | 
| 26 | 
            +
                # validations earlier in the week than the selected start time, e.g.
         | 
| 27 | 
            +
                #
         | 
| 28 | 
            +
                #     Schedule.new(wednesday).weekly(2).day(:monday)
         | 
| 29 | 
            +
                #
         | 
| 30 | 
            +
                # The effective start time gets realigned to the second next Monday, jumping
         | 
| 31 | 
            +
                # over the gap week for the interval (2). Without realignment, the correct
         | 
| 32 | 
            +
                # Monday occurrence would be missed when the schedule performs a 7-day jump
         | 
| 33 | 
            +
                # into the next interval week, arriving on the Wednesday. This corrects any
         | 
| 34 | 
            +
                # selections from dates that are misaligned to the schedule interval.
         | 
| 20 35 | 
             
                #
         | 
| 21 36 | 
             
                def realign(step_time, start_time)
         | 
| 22 37 | 
             
                  time = TimeUtil::TimeWrapper.new(start_time)
         | 
| 23 38 | 
             
                  offset = wday_offset(step_time, start_time)
         | 
| 24 | 
            -
                  time.add(:day, offset) | 
| 25 | 
            -
                  time.to_time
         | 
| 39 | 
            +
                  time.add(:day, offset)
         | 
| 40 | 
            +
                  super step_time, time.to_time
         | 
| 26 41 | 
             
                end
         | 
| 27 42 |  | 
| 43 | 
            +
                # Calculate how many days to the first wday validation in the correct
         | 
| 44 | 
            +
                # interval week. This may move backwards within the week if starting in an
         | 
| 45 | 
            +
                # interval week with earlier validations.
         | 
| 46 | 
            +
                #
         | 
| 28 47 | 
             
                def wday_offset(step_time, start_time)
         | 
| 48 | 
            +
                  return 0 if step_time == start_time
         | 
| 49 | 
            +
             | 
| 29 50 | 
             
                  wday_validations = other_interval_validations.select { |v| v.type == :wday }
         | 
| 30 | 
            -
                  return if wday_validations.none?
         | 
| 51 | 
            +
                  return 0 if wday_validations.none?
         | 
| 31 52 |  | 
| 32 | 
            -
                  days =  | 
| 53 | 
            +
                  days = step_time.to_date - start_time.to_date
         | 
| 33 54 | 
             
                  interval = base_interval_validation.validate(step_time, start_time).to_i
         | 
| 34 | 
            -
                  min_wday = TimeUtil.normalize_wday( | 
| 55 | 
            +
                  min_wday = wday_validations.map { |v| TimeUtil.normalize_wday(v.day, week_start) }.min
         | 
| 35 56 | 
             
                  step_wday = TimeUtil.normalize_wday(step_time.wday, week_start)
         | 
| 36 57 |  | 
| 37 58 | 
             
                  days + interval - step_wday + min_wday
         | 
| @@ -2,6 +2,15 @@ module IceCube | |
| 2 2 |  | 
| 3 3 | 
             
              class YearlyRule < ValidatedRule
         | 
| 4 4 |  | 
| 5 | 
            +
                include Validations::HourOfDay
         | 
| 6 | 
            +
                include Validations::MinuteOfHour
         | 
| 7 | 
            +
                include Validations::SecondOfMinute
         | 
| 8 | 
            +
                include Validations::DayOfMonth
         | 
| 9 | 
            +
                include Validations::DayOfWeek
         | 
| 10 | 
            +
                include Validations::Day
         | 
| 11 | 
            +
                include Validations::MonthOfYear
         | 
| 12 | 
            +
                include Validations::DayOfYear
         | 
| 13 | 
            +
             | 
| 5 14 | 
             
                include Validations::YearlyInterval
         | 
| 6 15 |  | 
| 7 16 | 
             
                def initialize(interval = 1)
         |