From ba97e3dc2a2f57ab6b5c55cff710b265973dba76 Mon Sep 17 00:00:00 2001 From: lgoldstein Date: Wed, 27 May 2015 17:29:33 -0700 Subject: [PATCH 01/26] Adding namespacing to Rule in Readme to make it easier to run examples --- README.md | 57 ++++++++++++++++++++++++++++--------------------------- 1 file changed, 29 insertions(+), 28 deletions(-) diff --git a/README.md b/README.md index 48d82fab..93f69882 100644 --- a/README.md +++ b/README.md @@ -21,8 +21,9 @@ Imagine you want: You would write: ```ruby +schedule = IceCube::Schedule.new schedule.add_recurrence_rule( - Rule.yearly.day_of_month(13).day(:friday).month_of_year(:october) + IceCube::Rule.yearly.day_of_month(13).day(:friday).month_of_year(:october) ) ``` @@ -42,11 +43,11 @@ With ice_cube, you can specify (in increasing order of precedence): * Recurrence Times - To specifically include in a schedule * Exception Times - To specifically exclude from a schedule -Example: Specifying a recurrence with an exception time: +Example: Specifying a recurrence with an exception time (ActiveRecord: ```ruby schedule = IceCube::Schedule.new(now = Time.now) do |s| - s.add_recurrence_rule(Rule.daily.count(3)) + s.add_recurrence_rule(IceCube::Rule.daily.count(3)) s.add_exception_time(now + 1.day) end @@ -87,13 +88,13 @@ schedule.previous_occurrences(3, from_time) # or give the schedule a duration and ask if occurring_at? schedule = IceCube::Schedule.new(now, :duration => 3600) -schedule.add_recurrence_rule Rule.daily +schedule.add_recurrence_rule IceCube::Rule.daily schedule.occurring_at?(now + 1800) # true schedule.occurring_between?(t1, t2) -# using end_time also sets the duration +# using end_time also sets the duration schedule = IceCube::Schedule.new(start = Time.now, :end_time => start + 3600) -schedule.add_recurrence_rule Rule.daily +schedule.add_recurrence_rule IceCube::Rule.daily schedule.occurring_at?(start + 3599) # true schedule.occurring_at?(start + 3600) # false @@ -170,36 +171,36 @@ There are many types of recurrence rules that can be added to a schedule: ```ruby # every day -schedule.add_recurrence_rule Rule.daily +schedule.add_recurrence_rule IceCube::Rule.daily # every third day -schedule.add_recurrence_rule Rule.daily(3) +schedule.add_recurrence_rule IceCube::Rule.daily(3) ``` ### Weekly ```ruby # every week -schedule.add_recurrence_rule Rule.weekly +schedule.add_recurrence_rule IceCube::Rule.weekly # every other week on monday and tuesday -schedule.add_recurrence_rule Rule.weekly(2).day(:monday, :tuesday) +schedule.add_recurrence_rule IceCube::Rule.weekly(2).day(:monday, :tuesday) # for programmatic convenience (same as above) -schedule.add_recurrence_rule Rule.weekly(2).day(1, 2) +schedule.add_recurrence_rule IceCube::Rule.weekly(2).day(1, 2) # specifying a weekly interval with a different first weekday (defaults to Sunday) -schedule.add_recurrence_rule Rule.weekly(1, :monday) +schedule.add_recurrence_rule IceCube::Rule.weekly(1, :monday) ``` ### Monthly (by day of month) ```ruby # every month on the first and last days of the month -schedule.add_recurrence_rule Rule.monthly.day_of_month(1, -1) +schedule.add_recurrence_rule IceCube::Rule.monthly.day_of_month(1, -1) # every other month on the 15th of the month -schedule.add_recurrence_rule Rule.monthly(2).day_of_month(15) +schedule.add_recurrence_rule IceCube::Rule.monthly(2).day_of_month(15) ``` Monthly rules will skip months that are too short for the specified day of @@ -209,69 +210,69 @@ month (e.g. no occurrences in February for `day_of_month(31)`). ```ruby # every month on the first and last tuesdays of the month -schedule.add_recurrence_rule Rule.monthly.day_of_week(:tuesday => [1, -1]) +schedule.add_recurrence_rule IceCube::Rule.monthly.day_of_week(:tuesday => [1, -1]) # every other month on the first monday and last tuesday -schedule.add_recurrence_rule Rule.monthly(2).day_of_week( +schedule.add_recurrence_rule IceCube::Rule.monthly(2).day_of_week( :monday => [1], :tuesday => [-1] ) # for programmatic convenience (same as above) -schedule.add_recurrence_rule Rule.monthly(2).day_of_week(1 => [1], 2 => [-1]) +schedule.add_recurrence_rule IceCube::Rule.monthly(2).day_of_week(1 => [1], 2 => [-1]) ``` ### Yearly (by day of year) ```ruby # every year on the 100th days from the beginning and end of the year -schedule.add_recurrence_rule Rule.yearly.day_of_year(100, -100) +schedule.add_recurrence_rule IceCube::Rule.yearly.day_of_year(100, -100) # every fourth year on new year's eve -schedule.add_recurrence_rule Rule.yearly(4).day_of_year(-1) +schedule.add_recurrence_rule IceCube::Rule.yearly(4).day_of_year(-1) ``` ### Yearly (by month of year) ```ruby # every year on the same day as start_time but in january and february -schedule.add_recurrence_rule Rule.yearly.month_of_year(:january, :februrary) +schedule.add_recurrence_rule IceCube::Rule.yearly.month_of_year(:january, :februrary) # every third year in march -schedule.add_recurrence_rule Rule.yearly(3).month_of_year(:march) +schedule.add_recurrence_rule IceCube::Rule.yearly(3).month_of_year(:march) # for programatic convenience (same as above) -schedule.add_recurrence_rule Rule.yearly(3).month_of_year(3) +schedule.add_recurrence_rule IceCube::Rule.yearly(3).month_of_year(3) ``` ### Hourly (by hour of day) ```ruby # every hour on the same minute and second as start date -schedule.add_recurrence_rule Rule.hourly +schedule.add_recurrence_rule IceCube::Rule.hourly # every other hour, on mondays -schedule.add_recurrence_rule Rule.hourly(2).day(:monday) +schedule.add_recurrence_rule IceCube::Rule.hourly(2).day(:monday) ``` ### Minutely (every N minutes) ```ruby # every 10 minutes -schedule.add_recurrence_rule Rule.minutely(10) +schedule.add_recurrence_rule IceCube::Rule.minutely(10) # every hour and a half, on the last tuesday of the month -schedule.add_recurrence_rule Rule.minutely(90).day_of_week(:tuesday => [-1]) +schedule.add_recurrence_rule IceCube::Rule.minutely(90).day_of_week(:tuesday => [-1]) ``` ### Secondly (every N seconds) ```ruby # every second -schedule.add_recurrence_rule Rule.secondly +schedule.add_recurrence_rule IceCube::Rule.secondly # every 15 seconds between 12:00 - 12:59 -schedule.add_recurrence_rule Rule.secondly(15).hour_of_day(12) +schedule.add_recurrence_rule IceCube::Rule.secondly(15).hour_of_day(12) ``` --- From 62576e5a02e72362336d00e8c85ba530ec7d80d2 Mon Sep 17 00:00:00 2001 From: compwron Date: Sun, 7 Jun 2015 19:53:12 -0700 Subject: [PATCH 02/26] Removing typo in readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 93f69882..ad599cc5 100644 --- a/README.md +++ b/README.md @@ -43,7 +43,7 @@ With ice_cube, you can specify (in increasing order of precedence): * Recurrence Times - To specifically include in a schedule * Exception Times - To specifically exclude from a schedule -Example: Specifying a recurrence with an exception time (ActiveRecord: +Example: Specifying a recurrence with an exception time ```ruby schedule = IceCube::Schedule.new(now = Time.now) do |s| From 87a03e8068d8a7687ba75ab0e508947c2e34974e Mon Sep 17 00:00:00 2001 From: J Potts Date: Thu, 1 Oct 2015 17:21:17 +0100 Subject: [PATCH 03/26] Option to include prior occurrences with overlapping duration Adding an option on schedule methods to include occurrences whose duration intersects a time window. Issue #154 https://github.com/seejohnrun/ice_cube/issues/154 --- README.md | 7 +++-- lib/ice_cube/schedule.rb | 36 ++++++++++++---------- spec/examples/schedule_spec.rb | 56 ++++++++++++++++++++++++++++++++++ 3 files changed, 80 insertions(+), 19 deletions(-) diff --git a/README.md b/README.md index ad599cc5..10f4008c 100644 --- a/README.md +++ b/README.md @@ -77,9 +77,10 @@ schedule.last(2) # [now + 1.day, now + 2.days] schedule.last # now + 2.days # or the next occurrence -schedule.next_occurrence(from_time) # defaults to Time.now -schedule.next_occurrences(3, from_time) # defaults to Time.now -schedule.remaining_occurrences # for terminating schedules +schedule.next_occurrence(from_time) # defaults to Time.now +schedule.next_occurrences(3, from_time) # defaults to Time.now +schedule.next_occurrences(3, from_time, true) # include prior occurrences with duration overlapping from_time +schedule.remaining_occurrences # for terminating schedules # or the previous occurrence schedule.previous_occurrence(from_time) diff --git a/lib/ice_cube/schedule.rb b/lib/ice_cube/schedule.rb index 73303ff3..870b1b5e 100644 --- a/lib/ice_cube/schedule.rb +++ b/lib/ice_cube/schedule.rb @@ -166,15 +166,15 @@ def each_occurrence(&block) end # The next n occurrences after now - def next_occurrences(num, from = nil) + def next_occurrences(num, from = nil, spans = false) from = TimeUtil.match_zone(from, start_time) || TimeUtil.now(start_time) - enumerate_occurrences(from + 1, nil).take(num) + enumerate_occurrences(from + 1, nil, spans).take(num) end # The next occurrence after now (overridable) - def next_occurrence(from = nil) + def next_occurrence(from = nil, spans = false) from = TimeUtil.match_zone(from, start_time) || TimeUtil.now(start_time) - enumerate_occurrences(from + 1, nil).next + enumerate_occurrences(from + 1, nil, spans).next rescue StopIteration nil end @@ -195,26 +195,26 @@ def previous_occurrences(num, from) end # The remaining occurrences (same requirements as all_occurrences) - def remaining_occurrences(from = nil) + def remaining_occurrences(from = nil, spans = false) require_terminating_rules from ||= TimeUtil.now(@start_time) - enumerate_occurrences(from).to_a + enumerate_occurrences(from, nil, spans).to_a end # Returns an enumerator for all remaining occurrences - def remaining_occurrences_enumerator(from = nil) + def remaining_occurrences_enumerator(from = nil, spans = false) from ||= TimeUtil.now(@start_time) - enumerate_occurrences(from) + enumerate_occurrences(from, nil, spans) end # Occurrences between two times - def occurrences_between(begin_time, closing_time) - enumerate_occurrences(begin_time, closing_time).to_a + def occurrences_between(begin_time, closing_time, spans = false) + enumerate_occurrences(begin_time, closing_time, spans).to_a end # Return a boolean indicating if an occurrence falls between two times - def occurs_between?(begin_time, closing_time) - enumerate_occurrences(begin_time, closing_time).next + def occurs_between?(begin_time, closing_time, spans = false) + enumerate_occurrences(begin_time, closing_time, spans).next true rescue StopIteration false @@ -404,25 +404,29 @@ def reset # Find all of the occurrences for the schedule between opening_time # and closing_time # Iteration is unrolled in pairs to skip duplicate times in end of DST - def enumerate_occurrences(opening_time, closing_time = nil, &block) + def enumerate_occurrences(opening_time, closing_time = nil, spans = false, &block) opening_time = TimeUtil.match_zone(opening_time, start_time) closing_time = TimeUtil.match_zone(closing_time, start_time) opening_time += start_time.subsec - opening_time.subsec rescue 0 opening_time = start_time if opening_time < start_time Enumerator.new do |yielder| reset - t1 = full_required? ? start_time : realign(opening_time) + t1 = full_required? || spans ? start_time : realign(opening_time) loop do break unless (t0 = next_time(t1, closing_time)) break if closing_time && t0 > closing_time - yielder << (block_given? ? block.call(t0) : t0) if t0 >= opening_time + if (spans ? t0.end_time : t0) >= opening_time + yielder << (block_given? ? block.call(t0) : t0) + end break unless (t1 = next_time(t0 + 1, closing_time)) break if closing_time && t1 > closing_time if TimeUtil.same_clock?(t0, t1) && recurrence_rules.any?(&:dst_adjust?) wind_back_dst next (t1 += 1) end - yielder << (block_given? ? block.call(t1) : t1) if t1 >= opening_time + if (spans ? t1.end_time : t1) >= opening_time + yielder << (block_given? ? block.call(t1) : t1) + end next (t1 += 1) end end diff --git a/spec/examples/schedule_spec.rb b/spec/examples/schedule_spec.rb index ea49c951..7b3468ca 100644 --- a/spec/examples/schedule_spec.rb +++ b/spec/examples/schedule_spec.rb @@ -451,6 +451,62 @@ end + describe :spans do + + it 'should find occurrence in past with duration beyond the start time' do + t0 = Time.utc(2015, 10, 1, 15, 31) + schedule = IceCube::Schedule.new(t0, :duration => 2 * IceCube::ONE_HOUR) + schedule.add_recurrence_rule IceCube::Rule.daily + next_occ = schedule.next_occurrence(t0 + IceCube::ONE_HOUR, true) + next_occ.should == t0 + end + + it 'should include occurrence in past with duration beyond the start time' do + t0 = Time.utc(2015, 10, 1, 15, 31) + schedule = IceCube::Schedule.new(t0, :duration => 2 * IceCube::ONE_HOUR) + schedule.add_recurrence_rule IceCube::Rule.daily.count(2) + occs = schedule.next_occurrences(10, t0 + IceCube::ONE_HOUR, true) + occs.should == [t0, t0 + IceCube::ONE_DAY] + end + + it 'should allow duration span on remaining_occurrences' do + t0 = Time.utc(2015, 10, 1, 00, 00) + schedule = IceCube::Schedule.new(t0, :duration => IceCube::ONE_DAY) + schedule.add_recurrence_rule IceCube::Rule.daily.count(3) + occs = schedule.remaining_occurrences(t0 + IceCube::ONE_DAY + IceCube::ONE_HOUR, true) + occs.should == [t0 + IceCube::ONE_DAY, t0 + 2 * IceCube::ONE_DAY] + end + + it 'should include occurrences with duration spanning the requested start time' do + t0 = Time.utc(2015, 10, 1, 15, 31) + schedule = IceCube::Schedule.new(t0, :duration => 30 * IceCube::ONE_DAY) + long_event = schedule.remaining_occurrences_enumerator(t0 + IceCube::ONE_DAY, true).take(1) + long_event.should == [t0] + end + + it 'should find occurrences between including previous one with duration spanning start' do + t0 = Time.utc(2015, 10, 1, 10, 00) + schedule = IceCube::Schedule.new(t0, :duration => IceCube::ONE_HOUR) + schedule.add_recurrence_rule IceCube::Rule.hourly.count(10) + occs = schedule.occurrences_between(t0 + IceCube::ONE_HOUR + 1, t0 + 3 * IceCube::ONE_HOUR + 1, true) + occs.length.should == 3 + end + + it 'should include long occurrences starting before and ending after' do + t0 = Time.utc(2015, 10, 1, 00, 00) + schedule = IceCube::Schedule.new(t0, :duration => IceCube::ONE_DAY) + occs = schedule.occurrences_between(t0 + IceCube::ONE_HOUR, t0 + IceCube::ONE_DAY - IceCube::ONE_HOUR, true) + occs.should == [t0] + end + + it 'should include long occurrences starting before and ending after' do + t0 = Time.utc(2015, 10, 1, 12, 00) + schedule = IceCube::Schedule.new(t0, :duration => IceCube::ONE_HOUR) + schedule.occurs_between?(t0 + IceCube::ONE_HOUR, t0 + 2 * IceCube::ONE_HOUR, true).should be_true + end + + end + describe :previous_occurrence do it 'returns the previous occurrence for a time in the schedule' do From d49c4a4208ed8ae9c9f1e0aa24672869325bf735 Mon Sep 17 00:00:00 2001 From: J Potts Date: Thu, 1 Oct 2015 18:32:39 +0100 Subject: [PATCH 04/26] Fixing speed issue on spans option Unecessarily setting the start time search back to the start of the schedule for a spanned search, when in fact it simply needs to step back a duration. --- lib/ice_cube/schedule.rb | 2 +- spec/examples/schedule_spec.rb | 14 ++++++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/lib/ice_cube/schedule.rb b/lib/ice_cube/schedule.rb index 870b1b5e..1409e753 100644 --- a/lib/ice_cube/schedule.rb +++ b/lib/ice_cube/schedule.rb @@ -411,7 +411,7 @@ def enumerate_occurrences(opening_time, closing_time = nil, spans = false, &bloc opening_time = start_time if opening_time < start_time Enumerator.new do |yielder| reset - t1 = full_required? || spans ? start_time : realign(opening_time) + t1 = full_required? ? start_time : realign((spans ? opening_time - duration : opening_time)) loop do break unless (t0 = next_time(t1, closing_time)) break if closing_time && t0 > closing_time diff --git a/spec/examples/schedule_spec.rb b/spec/examples/schedule_spec.rb index 7b3468ca..30726fcb 100644 --- a/spec/examples/schedule_spec.rb +++ b/spec/examples/schedule_spec.rb @@ -1,4 +1,5 @@ require File.dirname(__FILE__) + '/../spec_helper' +require 'benchmark' describe IceCube::Schedule do @@ -504,6 +505,19 @@ schedule = IceCube::Schedule.new(t0, :duration => IceCube::ONE_HOUR) schedule.occurs_between?(t0 + IceCube::ONE_HOUR, t0 + 2 * IceCube::ONE_HOUR, true).should be_true end + + it 'should quickly fetch a future time from a recurring schedule' do + t0 = Time.utc(2000, 10, 1, 00, 00) + t1 = Time.utc(2015, 10, 1, 12, 00) + schedule = IceCube::Schedule.new(t0, :duration => IceCube::ONE_HOUR - 1) + schedule.add_recurrence_rule IceCube::Rule.hourly + occ = nil + timing = Benchmark.realtime do + occ = schedule.remaining_occurrences_enumerator(t1, true).take(1) + end + timing.should < 0.1 + occ.should == [t1] + end end From e14ad76848e74dd566a3d0bcce6dd508dce1b5f2 Mon Sep 17 00:00:00 2001 From: J Potts Date: Sat, 3 Oct 2015 00:46:27 +0100 Subject: [PATCH 05/26] End of duration shouldn't hit start of check The spans checks were incorrectly returning a hit when the end of the duration for an event ended on the same time as the start time checks. Allows occurring_between? method to now be simplifed to use the spanned check. --- lib/ice_cube/schedule.rb | 9 ++++----- spec/examples/schedule_spec.rb | 26 +++++++++++++++++--------- 2 files changed, 21 insertions(+), 14 deletions(-) diff --git a/lib/ice_cube/schedule.rb b/lib/ice_cube/schedule.rb index 1409e753..7e837b38 100644 --- a/lib/ice_cube/schedule.rb +++ b/lib/ice_cube/schedule.rb @@ -226,9 +226,7 @@ def occurs_between?(begin_time, closing_time, spans = false) # occurrences at the end of the range since none of their duration # intersects the range. def occurring_between?(opening_time, closing_time) - opening_time = opening_time - duration - closing_time = closing_time - 1 if duration > 0 - occurs_between?(opening_time, closing_time) + occurs_between?(opening_time, closing_time, true) end # Return a boolean indicating if an occurrence falls on a certain date @@ -409,13 +407,14 @@ def enumerate_occurrences(opening_time, closing_time = nil, spans = false, &bloc closing_time = TimeUtil.match_zone(closing_time, start_time) opening_time += start_time.subsec - opening_time.subsec rescue 0 opening_time = start_time if opening_time < start_time + spans = false if duration == 0 Enumerator.new do |yielder| reset t1 = full_required? ? start_time : realign((spans ? opening_time - duration : opening_time)) loop do break unless (t0 = next_time(t1, closing_time)) break if closing_time && t0 > closing_time - if (spans ? t0.end_time : t0) >= opening_time + if (spans ? (t0.end_time > opening_time) : (t0 >= opening_time)) yielder << (block_given? ? block.call(t0) : t0) end break unless (t1 = next_time(t0 + 1, closing_time)) @@ -424,7 +423,7 @@ def enumerate_occurrences(opening_time, closing_time = nil, spans = false, &bloc wind_back_dst next (t1 += 1) end - if (spans ? t1.end_time : t1) >= opening_time + if (spans ? (t1.end_time > opening_time) : (t1 >= opening_time)) yielder << (block_given? ? block.call(t1) : t1) end next (t1 += 1) diff --git a/spec/examples/schedule_spec.rb b/spec/examples/schedule_spec.rb index 30726fcb..c5fe023c 100644 --- a/spec/examples/schedule_spec.rb +++ b/spec/examples/schedule_spec.rb @@ -500,10 +500,10 @@ occs.should == [t0] end - it 'should include long occurrences starting before and ending after' do + it 'should not find occurrence with duration ending on start time' do t0 = Time.utc(2015, 10, 1, 12, 00) schedule = IceCube::Schedule.new(t0, :duration => IceCube::ONE_HOUR) - schedule.occurs_between?(t0 + IceCube::ONE_HOUR, t0 + 2 * IceCube::ONE_HOUR, true).should be_true + schedule.occurs_between?(t0 + IceCube::ONE_HOUR, t0 + 2 * IceCube::ONE_HOUR, true).should be_false end it 'should quickly fetch a future time from a recurring schedule' do @@ -518,6 +518,14 @@ timing.should < 0.1 occ.should == [t1] end + + it 'should not include occurrence ending on start time' do + t0 = Time.utc(2015, 10, 1, 10, 00) + schedule = IceCube::Schedule.new(t0, :duration => IceCube::ONE_HOUR / 2) + schedule.add_recurrence_rule IceCube::Rule.minutely(30).count(6) + third_occ = schedule.next_occurrence(t0 + IceCube::ONE_HOUR, true) + third_occ.should == t0 + IceCube::ONE_HOUR + end end @@ -527,8 +535,8 @@ t0 = Time.utc(2013, 5, 18, 12, 34) schedule = IceCube::Schedule.new(t0) schedule.add_recurrence_rule IceCube::Rule.daily - previous = schedule.previous_occurrence(t0 + 2 * ONE_DAY) - previous.should == t0 + ONE_DAY + previous = schedule.previous_occurrence(t0 + 2 * IceCube::ONE_DAY) + previous.should == t0 + IceCube::ONE_DAY end it 'returns nil given the start time' do @@ -555,16 +563,16 @@ t0 = Time.utc(2013, 5, 18, 12, 34) schedule = IceCube::Schedule.new(t0) schedule.add_recurrence_rule IceCube::Rule.daily - previous = schedule.previous_occurrences(2, t0 + 3 * ONE_DAY) - previous.should == [t0 + ONE_DAY, t0 + 2 * ONE_DAY] + previous = schedule.previous_occurrences(2, t0 + 3 * IceCube::ONE_DAY) + previous.should == [t0 + IceCube::ONE_DAY, t0 + 2 * IceCube::ONE_DAY] end it 'limits the returned occurrences to a given count' do t0 = Time.utc(2013, 5, 18, 12, 34) schedule = IceCube::Schedule.new(t0) schedule.add_recurrence_rule IceCube::Rule.daily - previous = schedule.previous_occurrences(999, t0 + 2 * ONE_DAY) - previous.should == [t0, t0 + ONE_DAY] + previous = schedule.previous_occurrences(999, t0 + 2 * IceCube::ONE_DAY) + previous.should == [t0, t0 + IceCube::ONE_DAY] end it 'returns empty array given the start time' do @@ -601,7 +609,7 @@ t1 = Time.utc(2013, 5, 31, 12, 34) schedule = IceCube::Schedule.new(t0) schedule.add_recurrence_rule IceCube::Rule.daily.until(t1 + 1) - schedule.last(2).should == [t1 - ONE_DAY, t1] + schedule.last(2).should == [t1 - IceCube::ONE_DAY, t1] end it 'raises an error for a non-terminating schedule' do From c325a00c3becdeb1149de517ad3b1774e06e1d7b Mon Sep 17 00:00:00 2001 From: Tomo Matsumoto Date: Sun, 5 Oct 2014 23:13:50 +0900 Subject: [PATCH 06/26] use I18n --- config/locales/en.yml | 52 ++++++++++++++++++++ ice_cube.gemspec | 1 + lib/ice_cube.rb | 3 ++ lib/ice_cube/builders/string_builder.rb | 26 ++++++---- lib/ice_cube/validations/count.rb | 2 +- lib/ice_cube/validations/day.rb | 9 ++-- lib/ice_cube/validations/day_of_month.rb | 6 +-- lib/ice_cube/validations/day_of_week.rb | 3 +- lib/ice_cube/validations/day_of_year.rb | 6 +-- lib/ice_cube/validations/hour_of_day.rb | 4 +- lib/ice_cube/validations/minute_of_hour.rb | 4 +- lib/ice_cube/validations/month_of_year.rb | 2 +- lib/ice_cube/validations/second_of_minute.rb | 4 +- spec/examples/to_s_spec.rb | 4 ++ 14 files changed, 97 insertions(+), 29 deletions(-) create mode 100644 config/locales/en.yml diff --git a/config/locales/en.yml b/config/locales/en.yml new file mode 100644 index 00000000..315cd568 --- /dev/null +++ b/config/locales/en.yml @@ -0,0 +1,52 @@ +en: + ice_cube: + times: + other: '%{count} times' + one: '%{count} time' + days_of_month: + other: '%{segments} days of the month' + one: '%{segments} day of the month' + days_of_year: + other: '%{segments} days of the year' + one: '%{segments} day of the year' + at_hours_of_the_day: + other: on the %{segments} hours of the day + one: on the %{segments} hour of the day + on_minutes_of_hour: + other: on the %{segments} minutes of the hour + one: on the %{segments} minute of the hour + at_seconds_of_minute: + other: at the %{segments} seconds + one: at the %{segments} second + on_seconds_of_minute: + other: on the %{segments} seconds of the minute + one: on the %{segments} second of the minute + 'on': on the %{sentence} + in: in + integer: + negative: '%{ordinal} to last' + literal_ordinals: + -1: last + -2: 2nd to last + ordinals: + default: th + 1: st + 2: nd + 3: rd + 11: th + 12: th + 13: th + on_weekends: on Weekends + on_weekdays: on Weekdays + days_on: + - Sundays + - Mondays + - Tuesdays + - Wednesdays + - Thursdays + - Fridays + - Saturdays + on_days: on %{days} + support: + array: + two_words_connector: ' and ' diff --git a/ice_cube.gemspec b/ice_cube.gemspec index 9854163d..6f89238d 100644 --- a/ice_cube.gemspec +++ b/ice_cube.gemspec @@ -21,4 +21,5 @@ Gem::Specification.new do |s| s.add_development_dependency('rspec', '~> 2.12.0') s.add_development_dependency('activesupport', '>= 3.0.0') s.add_development_dependency('tzinfo') + s.add_development_dependency('i18n') end diff --git a/lib/ice_cube.rb b/lib/ice_cube.rb index 4375ee53..ccdc1bb1 100644 --- a/lib/ice_cube.rb +++ b/lib/ice_cube.rb @@ -1,5 +1,8 @@ require 'date' require 'ice_cube/deprecated' +require 'i18n' + +I18n.load_path += Dir[File.expand_path('../../config/locales/*{rb,yml}', __FILE__)] module IceCube diff --git a/lib/ice_cube/builders/string_builder.rb b/lib/ice_cube/builders/string_builder.rb index de4585d7..65fbe702 100644 --- a/lib/ice_cube/builders/string_builder.rb +++ b/lib/ice_cube/builders/string_builder.rb @@ -34,9 +34,6 @@ def self.register_formatter(type, &formatter) module Helpers - NUMBER_SUFFIX = ['th', 'st', 'nd', 'rd', 'th', 'th', 'th', 'th', 'th', 'th'] - SPECIAL_SUFFIX = { 11 => 'th', 12 => 'th', 13 => 'th', 14 => 'th' } - # influenced by ActiveSupport's to_sentence def sentence(array) case array.length @@ -48,13 +45,22 @@ def sentence(array) end def nice_number(number) - return 'last' if number == -1 - suffix = SPECIAL_SUFFIX[number] || NUMBER_SUFFIX[number.abs % 10] - if number < -1 - number.abs.to_s << suffix << ' to last' - else - number.to_s << suffix - end + literal_ordinal(number) || ordinalize(number) + end + + def ordinalize(number) + "#{number}#{ordinal(number)}" + end + + def literal_ordinal(number) + I18n.t("ice_cube.integer.literal_ordinals")[number] + end + + def ordinal(number) + ord = I18n.t("ice_cube.integer.ordinals")[number] || + I18n.t("ice_cube.integer.ordinals")[number % 10] || + I18n.t('ice_cube.integer.ordinals')[:default] + number >= 0 ? ord : I18n.t("ice_cube.integer.negative", ordinal: ord) end end diff --git a/lib/ice_cube/validations/count.rb b/lib/ice_cube/validations/count.rb index 61099433..b35e9729 100644 --- a/lib/ice_cube/validations/count.rb +++ b/lib/ice_cube/validations/count.rb @@ -51,7 +51,7 @@ def build_ical(builder) StringBuilder.register_formatter(:count) do |segments| count = segments.first - "#{count} #{count == 1 ? 'time' : 'times'}" + I18n.t('ice_cube.times', count: count) end end diff --git a/lib/ice_cube/validations/day.rb b/lib/ice_cube/validations/day.rb index c29396f0..1fbef4bc 100644 --- a/lib/ice_cube/validations/day.rb +++ b/lib/ice_cube/validations/day.rb @@ -54,12 +54,13 @@ def build_ical(builder) validation_days.sort! # pick the right shortening, if applicable if validation_days == [0, 6] - 'on Weekends' + I18n.t('ice_cube.on_weekends') elsif validation_days == (1..5).to_a - 'on Weekdays' + I18n.t('ice_cube.on_weekdays') else - segments = validation_days.map { |d| "#{Date::DAYNAMES[d]}s" } - "on #{StringBuilder.sentence(segments)}" + day_names = ->(d){ "#{I18n.t("ice_cube.days_on")[d]}" } + segments = validation_days.map(&day_names) + I18n.t('ice_cube.on_days', days: StringBuilder.sentence(segments)) end end diff --git a/lib/ice_cube/validations/day_of_month.rb b/lib/ice_cube/validations/day_of_month.rb index ef2cd2ad..cca1e7ae 100644 --- a/lib/ice_cube/validations/day_of_month.rb +++ b/lib/ice_cube/validations/day_of_month.rb @@ -43,9 +43,9 @@ def build_ical(builder) end StringBuilder.register_formatter(:day_of_month) do |entries| - str = "on the #{StringBuilder.sentence(entries)} " - str << (entries.size == 1 ? 'day of the month' : 'days of the month') - str + sentence = StringBuilder.sentence(entries) + str = I18n.t('ice_cube.days_of_month', count: entries.size, segments: sentence) + I18n.t('ice_cube.on', sentence: str) end end diff --git a/lib/ice_cube/validations/day_of_week.rb b/lib/ice_cube/validations/day_of_week.rb index de40040e..637b6b8b 100644 --- a/lib/ice_cube/validations/day_of_week.rb +++ b/lib/ice_cube/validations/day_of_week.rb @@ -62,7 +62,8 @@ def build_ical(builder) end StringBuilder.register_formatter(:day_of_week) do |segments| - 'on the ' + segments.join(' and ') + sentence = segments.join(I18n.t('support.array.two_words_connector')) + I18n.t('ice_cube.on', sentence: sentence) end end diff --git a/lib/ice_cube/validations/day_of_year.rb b/lib/ice_cube/validations/day_of_year.rb index b68c980b..120a565a 100644 --- a/lib/ice_cube/validations/day_of_year.rb +++ b/lib/ice_cube/validations/day_of_year.rb @@ -49,9 +49,9 @@ def build_ical(builder) end StringBuilder.register_formatter(:day_of_year) do |entries| - str = "on the #{StringBuilder.sentence(entries)} " - str << (entries.size == 1 ? 'day of the year' : 'days of the year') - str + str = StringBuilder.sentence(entries) + sentence = I18n.t('ice_cube.days_of_year', count: entries.size, segments: str) + I18n.t('ice_cube.on', sentence: sentence) end end diff --git a/lib/ice_cube/validations/hour_of_day.rb b/lib/ice_cube/validations/hour_of_day.rb index a171722b..877e4eeb 100644 --- a/lib/ice_cube/validations/hour_of_day.rb +++ b/lib/ice_cube/validations/hour_of_day.rb @@ -44,8 +44,8 @@ def build_ical(builder) end StringBuilder.register_formatter(:hour_of_day) do |segments| - str = "on the #{StringBuilder.sentence(segments)} " - str << (segments.size == 1 ? 'hour of the day' : 'hours of the day') + str = StringBuilder.sentence(segments) + I18n.t('ice_cube.at_hours_of_the_day', count: segments.size, segments: str) end end diff --git a/lib/ice_cube/validations/minute_of_hour.rb b/lib/ice_cube/validations/minute_of_hour.rb index bf1e26f9..d4fbf14a 100644 --- a/lib/ice_cube/validations/minute_of_hour.rb +++ b/lib/ice_cube/validations/minute_of_hour.rb @@ -43,8 +43,8 @@ def build_ical(builder) end StringBuilder.register_formatter(:minute_of_hour) do |segments| - str = "on the #{StringBuilder.sentence(segments)} " - str << (segments.size == 1 ? 'minute of the hour' : 'minutes of the hour') + str = StringBuilder.sentence(segments) + I18n.t('ice_cube.on_minutes_of_hour', count: segments.size, segments: str) end end diff --git a/lib/ice_cube/validations/month_of_year.rb b/lib/ice_cube/validations/month_of_year.rb index 5c9c0f98..1d1c0d65 100644 --- a/lib/ice_cube/validations/month_of_year.rb +++ b/lib/ice_cube/validations/month_of_year.rb @@ -44,7 +44,7 @@ def build_ical(builder) end StringBuilder.register_formatter(:month_of_year) do |segments| - "in #{StringBuilder.sentence(segments)}" + "#{I18n.t("ice_cube.in")} #{StringBuilder.sentence(segments)}" end end diff --git a/lib/ice_cube/validations/second_of_minute.rb b/lib/ice_cube/validations/second_of_minute.rb index 6985623c..0ad30198 100644 --- a/lib/ice_cube/validations/second_of_minute.rb +++ b/lib/ice_cube/validations/second_of_minute.rb @@ -43,8 +43,8 @@ def build_ical(builder) end StringBuilder.register_formatter(:second_of_minute) do |segments| - str = "on the #{StringBuilder.sentence(segments)} " - str << (segments.size == 1 ? 'second of the minute' : 'seconds of the minute') + str = StringBuilder.sentence(segments) + I18n.t('ice_cube.on_seconds_of_minute', count: segments.size, segments: str) end end diff --git a/spec/examples/to_s_spec.rb b/spec/examples/to_s_spec.rb index fef6e531..e74785b6 100644 --- a/spec/examples/to_s_spec.rb +++ b/spec/examples/to_s_spec.rb @@ -2,6 +2,10 @@ describe IceCube::Schedule, 'to_s' do + before :each do + I18n.locale = :en + end + it 'should represent its start time by default' do t0 = Time.local(2013, 2, 14) IceCube::Schedule.new(t0).to_s.should == 'February 14, 2013' From aa666a57acd65121acec54128dbf65246db5628a Mon Sep 17 00:00:00 2001 From: Tomo Matsumoto Date: Mon, 6 Oct 2014 23:56:24 +0900 Subject: [PATCH 07/26] add Japanese locale --- config/locales/en.yml | 68 +++++- config/locales/ja.yml | 107 +++++++++ lib/ice_cube.rb | 2 +- lib/ice_cube/builders/string_builder.rb | 16 +- lib/ice_cube/schedule.rb | 8 +- lib/ice_cube/validations/daily_interval.rb | 2 +- lib/ice_cube/validations/day_of_week.rb | 8 +- lib/ice_cube/validations/hourly_interval.rb | 2 +- lib/ice_cube/validations/minutely_interval.rb | 2 +- lib/ice_cube/validations/month_of_year.rb | 4 +- lib/ice_cube/validations/monthly_interval.rb | 2 +- lib/ice_cube/validations/secondly_interval.rb | 2 +- lib/ice_cube/validations/until.rb | 3 +- lib/ice_cube/validations/weekly_interval.rb | 2 +- lib/ice_cube/validations/yearly_interval.rb | 2 +- .../{to_s_spec.rb => to_s_en_spec.rb} | 2 +- spec/examples/to_s_ja_spec.rb | 207 ++++++++++++++++++ 17 files changed, 414 insertions(+), 25 deletions(-) create mode 100644 config/locales/ja.yml rename spec/examples/{to_s_spec.rb => to_s_en_spec.rb} (99%) create mode 100644 spec/examples/to_s_ja_spec.rb diff --git a/config/locales/en.yml b/config/locales/en.yml index 315cd568..3bc1d465 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -1,8 +1,38 @@ en: ice_cube: + pieces_connector: ' / ' + not: 'not %{target}' + not_on: 'not on %{target}' + date: + formats: + default: '%B %-d, %Y' + month_names: + - + - January + - February + - March + - April + - May + - June + - July + - August + - September + - October + - November + - December + day_names: + - Sunday + - Monday + - Tuesday + - Wednesday + - Thursday + - Friday + - Saturday times: other: '%{count} times' one: '%{count} time' + until: 'until %{date}' + days_of_week: '%{segments} %{day}' days_of_month: other: '%{segments} days of the month' one: '%{segments} day of the month' @@ -21,13 +51,35 @@ en: on_seconds_of_minute: other: on the %{segments} seconds of the minute one: on the %{segments} second of the minute + each_second: + one: Secondly + other: Every %{count} seconds + each_minute: + one: Minutely + other: Every %{count} minutes + each_hour: + one: Hourly + other: Every %{count} hours + each_day: + one: Daily + other: Every %{count} days + each_week: + one: Weekly + other: Every %{count} weeks + each_month: + one: Monthly + other: Every %{count} months + each_year: + one: Yearly + other: Every %{count} years 'on': on the %{sentence} - in: in + in: 'in %{target}' integer: negative: '%{ordinal} to last' literal_ordinals: -1: last -2: 2nd to last + ordinal: '%{number}%{ordinal}' ordinals: default: th 1: st @@ -47,6 +99,18 @@ en: - Fridays - Saturdays on_days: on %{days} - support: array: + last_word_connector: ', and ' two_words_connector: ' and ' + words_connector: ', ' + string: + format: + day: '%{rest} %{current}' + day_of_week: '%{rest} %{current}' + day_of_month: '%{rest} %{current}' + day_of_year: '%{rest} %{current}' + hour_of_day: '%{rest} %{current}' + minute_of_hour: '%{rest} %{current}' + until: '%{rest} %{current}' + count: '%{rest} %{current}' + default: '%{rest} %{current}' diff --git a/config/locales/ja.yml b/config/locales/ja.yml new file mode 100644 index 00000000..a113af1a --- /dev/null +++ b/config/locales/ja.yml @@ -0,0 +1,107 @@ +ja: + ice_cube: + pieces_connector: ' / ' + not: '%{target}以外' + not_on: '%{target}以外' + date: + formats: + default: '%Y年%m月%d日' + month_names: + - + - 1月 + - 2月 + - 3月 + - 4月 + - 5月 + - 6月 + - 7月 + - 8月 + - 9月 + - 10月 + - 11月 + - 12月 + day_names: + - 日曜 + - 月曜 + - 火曜 + - 水曜 + - 木曜 + - 金曜 + - 土曜 + times: + other: '%{count}回' + one: '%{count}回' + until: '%{date}まで' + days_of_week: '%{segments}%{day}' + days_of_month: + other: '%{segments}日' + one: '%{segments}日' + days_of_year: + other: '%{segments}日' + one: '%{segments}日' + at_hours_of_the_day: + other: '%{segments}時' + one: '%{segments}時' + on_minutes_of_hour: + other: '%{segments}分' + one: '%{segments}分' + on_seconds_of_minute: + other: '%{segments}秒' + one: '%{segments}秒' + each_second: + one: 毎秒 + other: '%{count}秒ごと' + each_minute: + one: 毎分 + other: '%{count}分ごと' + each_hour: + one: 毎時間 + other: '%{count}時間ごと' + each_day: + one: 毎日 + other: '%{count}日ごと' + each_week: + one: 毎週 + other: '%{count}週間ごと' + each_month: + one: 毎月 + other: '%{count}ヶ月ごと' + each_year: + one: 毎年 + other: '%{count}年ごと' + 'on': '%{sentence}' + in: '%{target}' + integer: + negative: '最終%{ordinal}' + literal_ordinals: + -1: 最終 + -2: 最後から2番目の + ordinal: '%{ordinal}%{number}' + ordinals: + default: '' + on_weekends: 週末 + on_weekdays: 平日 + days_on: + - 日曜 + - 月曜 + - 火曜 + - 水曜 + - 木曜 + - 金曜 + - 土曜 + on_days: '%{days}' + array: + last_word_connector: '、' + two_words_connector: '、' + words_connector: '、' + string: + format: + day: '%{rest}%{current}' + day_of_week: '%{rest}%{current}' + day_of_month: '%{rest}%{current}' + day_of_year: '%{rest}%{current}' + hour_of_day: '%{rest}%{current}' + minute_of_hour: '%{rest}%{current}' + until: '%{current}%{rest}' + count: '%{rest}%{current}' + default: '%{rest}%{current}' diff --git a/lib/ice_cube.rb b/lib/ice_cube.rb index ccdc1bb1..269339f8 100644 --- a/lib/ice_cube.rb +++ b/lib/ice_cube.rb @@ -72,7 +72,7 @@ module Validations # Defines the format used by IceCube when printing out Schedule#to_s. # Defaults to '%B %e, %Y' def self.to_s_time_format - @to_s_time_format ||= '%B %e, %Y' + @to_s_time_format ||= I18n.t("ice_cube.date.formats.default") end # Sets the format used by IceCube when printing out Schedule#to_s. diff --git a/lib/ice_cube/builders/string_builder.rb b/lib/ice_cube/builders/string_builder.rb index 65fbe702..7809f6bf 100644 --- a/lib/ice_cube/builders/string_builder.rb +++ b/lib/ice_cube/builders/string_builder.rb @@ -13,14 +13,18 @@ def piece(type, prefix = nil, suffix = nil) end def to_s - @types.each_with_object(@base || '') do |(type, segments), str| + string = @base || '' + @types.each do |type, segments| if f = self.class.formatter(type) - str << ' ' << f.call(segments) + current = f.call(segments) else next if segments.empty? - str << ' ' << self.class.sentence(segments) + current = self.class.sentence(segments) end + f = I18n.t('ice_cube.string.format')[type] ? type : 'default' + string = I18n.t("ice_cube.string.format.#{f}", rest: string, current: current) end + string end def self.formatter(type) @@ -39,8 +43,8 @@ def sentence(array) case array.length when 0 ; '' when 1 ; array[0].to_s - when 2 ; "#{array[0]} and #{array[1]}" - else ; "#{array[0...-1].join(', ')}, and #{array[-1]}" + when 2 ; "#{array[0]}#{I18n.t('ice_cube.array.two_words_connector')}#{array[1]}" + else ; "#{array[0...-1].join(I18n.t('ice_cube.array.words_connector'))}#{I18n.t('ice_cube.array.last_word_connector')}#{array[-1]}" end end @@ -49,7 +53,7 @@ def nice_number(number) end def ordinalize(number) - "#{number}#{ordinal(number)}" + I18n.t('ice_cube.integer.ordinal', number: number, ordinal: ordinal(number)) end def literal_ordinal(number) diff --git a/lib/ice_cube/schedule.rb b/lib/ice_cube/schedule.rb index 73303ff3..2da82ef4 100644 --- a/lib/ice_cube/schedule.rb +++ b/lib/ice_cube/schedule.rb @@ -315,9 +315,11 @@ def to_s rd = recurrence_times_with_start_time - extimes pieces.concat rd.sort.map { |t| t.strftime(IceCube.to_s_time_format) } pieces.concat rrules.map { |t| t.to_s } - pieces.concat exrules.map { |t| "not #{t.to_s}" } - pieces.concat extimes.sort.map { |t| "not on #{t.strftime(IceCube.to_s_time_format)}" } - pieces.join(' / ') + pieces.concat exrules.map { |t| I18n.t('ice_cube.not', target: t.to_s) } + pieces.concat extimes.sort.map { |t| + I18n.t('ice_cube.not_on', target: t.strftime(IceCube.to_s_time_format)) + } + pieces.join(I18n.t('ice_cube.pieces_connector')) end # Serialize this schedule to_ical diff --git a/lib/ice_cube/validations/daily_interval.rb b/lib/ice_cube/validations/daily_interval.rb index edf8ce72..f75d207a 100644 --- a/lib/ice_cube/validations/daily_interval.rb +++ b/lib/ice_cube/validations/daily_interval.rb @@ -35,7 +35,7 @@ def validate(step_time, schedule) end def build_s(builder) - builder.base = interval == 1 ? 'Daily' : "Every #{interval} days" + builder.base = I18n.t('ice_cube.each_day', count: interval) end def build_hash(builder) diff --git a/lib/ice_cube/validations/day_of_week.rb b/lib/ice_cube/validations/day_of_week.rb index 637b6b8b..a9ad49f9 100644 --- a/lib/ice_cube/validations/day_of_week.rb +++ b/lib/ice_cube/validations/day_of_week.rb @@ -45,7 +45,11 @@ def validate(step_time, schedule) end def build_s(builder) - builder.piece(:day_of_week) << "#{StringBuilder.nice_number(occ)} #{Date::DAYNAMES[day]}" + builder.piece(:day_of_week) << I18n.t( + 'ice_cube.days_of_week', + segments: StringBuilder.nice_number(occ), + day: I18n.t('ice_cube.date.day_names')[day] + ) end def build_hash(builder) @@ -62,7 +66,7 @@ def build_ical(builder) end StringBuilder.register_formatter(:day_of_week) do |segments| - sentence = segments.join(I18n.t('support.array.two_words_connector')) + sentence = segments.join(I18n.t('ice_cube.array.two_words_connector')) I18n.t('ice_cube.on', sentence: sentence) end diff --git a/lib/ice_cube/validations/hourly_interval.rb b/lib/ice_cube/validations/hourly_interval.rb index ce2484c4..1b526953 100644 --- a/lib/ice_cube/validations/hourly_interval.rb +++ b/lib/ice_cube/validations/hourly_interval.rb @@ -35,7 +35,7 @@ def validate(step_time, schedule) end def build_s(builder) - builder.base = interval == 1 ? 'Hourly' : "Every #{interval} hours" + builder.base = I18n.t("ice_cube.each_hour", count: interval) end def build_hash(builder) diff --git a/lib/ice_cube/validations/minutely_interval.rb b/lib/ice_cube/validations/minutely_interval.rb index eb03f366..1363a573 100644 --- a/lib/ice_cube/validations/minutely_interval.rb +++ b/lib/ice_cube/validations/minutely_interval.rb @@ -35,7 +35,7 @@ def validate(step_time, schedule) end def build_s(builder) - builder.base = interval == 1 ? 'Minutely' : "Every #{interval} minutes" + builder.base = I18n.t('ice_cube.each_minute', count: interval) end def build_hash(builder) diff --git a/lib/ice_cube/validations/month_of_year.rb b/lib/ice_cube/validations/month_of_year.rb index 1d1c0d65..4628c386 100644 --- a/lib/ice_cube/validations/month_of_year.rb +++ b/lib/ice_cube/validations/month_of_year.rb @@ -32,7 +32,7 @@ def dst_adjust? end def build_s(builder) - builder.piece(:month_of_year) << Date::MONTHNAMES[month] + builder.piece(:month_of_year) << I18n.t("ice_cube.date.month_names")[month] end def build_hash(builder) @@ -44,7 +44,7 @@ def build_ical(builder) end StringBuilder.register_formatter(:month_of_year) do |segments| - "#{I18n.t("ice_cube.in")} #{StringBuilder.sentence(segments)}" + I18n.t("ice_cube.in", target: StringBuilder.sentence(segments)) end end diff --git a/lib/ice_cube/validations/monthly_interval.rb b/lib/ice_cube/validations/monthly_interval.rb index 61fde0c5..b5d75b4b 100644 --- a/lib/ice_cube/validations/monthly_interval.rb +++ b/lib/ice_cube/validations/monthly_interval.rb @@ -34,7 +34,7 @@ def validate(step_time, schedule) end def build_s(builder) - builder.base = interval == 1 ? 'Monthly' : "Every #{interval} months" + builder.base = I18n.t('ice_cube.each_month', count: interval) end def build_hash(builder) diff --git a/lib/ice_cube/validations/secondly_interval.rb b/lib/ice_cube/validations/secondly_interval.rb index 4e79b56e..37d018df 100644 --- a/lib/ice_cube/validations/secondly_interval.rb +++ b/lib/ice_cube/validations/secondly_interval.rb @@ -32,7 +32,7 @@ def validate(step_time, schedule) end def build_s(builder) - builder.base = interval == 1 ? 'Secondly' : "Every #{interval} seconds" + builder.base = I18n.t("ice_cube.each_second", count: interval) end def build_hash(builder) diff --git a/lib/ice_cube/validations/until.rb b/lib/ice_cube/validations/until.rb index d834e431..56a264b6 100644 --- a/lib/ice_cube/validations/until.rb +++ b/lib/ice_cube/validations/until.rb @@ -38,7 +38,8 @@ def validate(step_time, schedule) end def build_s(builder) - builder.piece(:until) << "until #{time.strftime(IceCube.to_s_time_format)}" + date = time.strftime(IceCube.to_s_time_format) + builder.piece(:until) << I18n.t('ice_cube.until', date: date) end def build_hash(builder) diff --git a/lib/ice_cube/validations/weekly_interval.rb b/lib/ice_cube/validations/weekly_interval.rb index 5bdf33be..73a9d3d4 100644 --- a/lib/ice_cube/validations/weekly_interval.rb +++ b/lib/ice_cube/validations/weekly_interval.rb @@ -44,7 +44,7 @@ def validate(step_time, schedule) end def build_s(builder) - builder.base = interval == 1 ? 'Weekly' : "Every #{interval} weeks" + builder.base = I18n.t('ice_cube.each_week', count: interval) end def build_hash(builder) diff --git a/lib/ice_cube/validations/yearly_interval.rb b/lib/ice_cube/validations/yearly_interval.rb index 9daab221..09027368 100644 --- a/lib/ice_cube/validations/yearly_interval.rb +++ b/lib/ice_cube/validations/yearly_interval.rb @@ -32,7 +32,7 @@ def validate(step_time, schedule) end def build_s(builder) - builder.base = interval == 1 ? 'Yearly' : "Every #{interval} years" + builder.base = I18n.t('ice_cube.each_year', count: interval) end def build_hash(builder) diff --git a/spec/examples/to_s_spec.rb b/spec/examples/to_s_en_spec.rb similarity index 99% rename from spec/examples/to_s_spec.rb rename to spec/examples/to_s_en_spec.rb index e74785b6..d41193ce 100644 --- a/spec/examples/to_s_spec.rb +++ b/spec/examples/to_s_en_spec.rb @@ -188,7 +188,7 @@ it 'should be able to reflect until dates' do schedule = IceCube::Schedule.new(Time.now) schedule.rrule IceCube::Rule.weekly.until(Time.local(2012, 2, 3)) - schedule.to_s.should == 'Weekly until February 3, 2012' + schedule.to_s.should == 'Weekly until February 3, 2012' end it 'should be able to reflect count' do diff --git a/spec/examples/to_s_ja_spec.rb b/spec/examples/to_s_ja_spec.rb new file mode 100644 index 00000000..6e79b27d --- /dev/null +++ b/spec/examples/to_s_ja_spec.rb @@ -0,0 +1,207 @@ +# -*- coding: utf-8 -*- +require File.dirname(__FILE__) + '/../spec_helper' + +describe IceCube::Schedule, 'to_s' do + + before :each do + I18n.locale = :ja + end + + it 'should represent its start time by default' do + t0 = Time.local(2013, 2, 14) + IceCube::Schedule.new(t0).to_s.should == '2013年02月14日' + end + + it 'should have a useful base to_s representation for a secondly rule' do + IceCube::Rule.secondly.to_s.should == '毎秒' + IceCube::Rule.secondly(2).to_s.should == '2秒ごと' + end + + it 'should have a useful base to_s representation for a minutely rule' do + IceCube::Rule.minutely.to_s.should == '毎分' + IceCube::Rule.minutely(2).to_s.should == '2分ごと' + end + + it 'should have a useful base to_s representation for a hourly rule' do + IceCube::Rule.hourly.to_s.should == '毎時間' + IceCube::Rule.hourly(2).to_s.should == '2時間ごと' + end + + it 'should have a useful base to_s representation for a daily rule' do + IceCube::Rule.daily.to_s.should == '毎日' + IceCube::Rule.daily(2).to_s.should == '2日ごと' + end + + it 'should have a useful base to_s representation for a weekly rule' do + IceCube::Rule.weekly.to_s.should == '毎週' + IceCube::Rule.weekly(2).to_s.should == '2週間ごと' + end + + it 'should have a useful base to_s representation for a monthly rule' do + IceCube::Rule.monthly.to_s.should == '毎月' + IceCube::Rule.monthly(2).to_s.should == '2ヶ月ごと' + end + + it 'should have a useful base to_s representation for a yearly rule' do + IceCube::Rule.yearly.to_s.should == '毎年' + IceCube::Rule.yearly(2).to_s.should == '2年ごと' + end + + it 'should work with various sentence types properly' do + IceCube::Rule.weekly.to_s.should == '毎週' + IceCube::Rule.weekly.day(:monday).to_s.should == '毎週月曜' + IceCube::Rule.weekly.day(:monday, :tuesday).to_s.should == '毎週月曜、火曜' + IceCube::Rule.weekly.day(:monday, :tuesday, :wednesday).to_s.should == '毎週月曜、火曜、水曜' + end + + it 'should show saturday and sunday as weekends' do + IceCube::Rule.weekly.day(:saturday, :sunday).to_s.should == '毎週週末' + end + + it 'should not show saturday and sunday as weekends when other days are present also' do + IceCube::Rule.weekly.day(:sunday, :monday, :saturday).to_s.should == + '毎週日曜、月曜、土曜' + end + + it 'should reorganize days to be in order' do + IceCube::Rule.weekly.day(:tuesday, :monday).to_s.should == + '毎週月曜、火曜' + end + + it 'should show weekdays as such' do + IceCube::Rule.weekly.day( + :monday, :tuesday, :wednesday, + :thursday, :friday + ).to_s.should == '毎週平日' + end + + it 'should not show weekdays as such when a weekend day is present' do + IceCube::Rule.weekly.day( + :sunday, :monday, :tuesday, :wednesday, + :thursday, :friday + ).to_s.should == '毎週日曜、月曜、火曜、水曜、木曜、金曜' + end + + it 'should show start time for an empty schedule' do + schedule = IceCube::Schedule.new Time.local(2010, 3, 20) + schedule.to_s.should == "2010年03月20日" + end + + it 'should work with a single date' do + schedule = IceCube::Schedule.new Time.local(2010, 3, 20) + schedule.add_recurrence_time Time.local(2010, 3, 20) + schedule.to_s.should == "2010年03月20日" + end + + it 'should work with additional dates' do + schedule = IceCube::Schedule.new Time.local(2010, 3, 20) + schedule.add_recurrence_time Time.local(2010, 3, 20) + schedule.add_recurrence_time Time.local(2010, 3, 21) + schedule.to_s.should == '2010年03月20日 / 2010年03月21日' + end + + it 'should order dates that are out of order' do + schedule = IceCube::Schedule.new(t0 = Time.local(2010, 3, 20)) + schedule.add_recurrence_time t1 = Time.local(2010, 3, 19) + schedule.to_s.should == '2010年03月19日 / 2010年03月20日' + end + + it 'should remove duplicated start time' do + schedule = IceCube::Schedule.new t0 = Time.local(2010, 3, 20) + schedule.add_recurrence_time t0 + schedule.to_s.should == '2010年03月20日' + end + + it 'should remove duplicate rtimes' do + schedule = IceCube::Schedule.new t0 = Time.local(2010, 3, 19) + schedule.add_recurrence_time Time.local(2010, 3, 20) + schedule.add_recurrence_time Time.local(2010, 3, 20) + schedule.to_s.should == '2010年03月19日 / 2010年03月20日' + end + + it 'should work with rules and dates' do + schedule = IceCube::Schedule.new Time.local(2010, 3, 19) + schedule.add_recurrence_time Time.local(2010, 3, 20) + schedule.add_recurrence_rule IceCube::Rule.weekly + schedule.to_s.should == '2010年03月20日 / 毎週' + end + + it 'should work with rules and times and exception times' do + schedule = IceCube::Schedule.new Time.local(2010, 3, 20) + schedule.add_recurrence_rule IceCube::Rule.weekly + schedule.add_recurrence_time Time.local(2010, 3, 20) + schedule.add_exception_time Time.local(2010, 3, 20) # ignored + schedule.add_exception_time Time.local(2010, 3, 21) + schedule.to_s.should == '毎週 / 2010年03月20日以外 / 2010年03月21日以外' + end + + it 'should work with a single rrule' do + schedule = IceCube::Schedule.new Time.local(2010, 3, 20) + schedule.add_recurrence_rule IceCube::Rule.weekly.day_of_week(:monday => [1]) + schedule.to_s.should == schedule.rrules[0].to_s + end + + it 'should be able to say the last Thursday of the month' do + rule_str = IceCube::Rule.monthly.day_of_week(:thursday => [-1]).to_s + rule_str.should == '毎月最終木曜' + end + + it 'should be able to say what months of the year something happens' do + rule_str = IceCube::Rule.yearly.month_of_year(:june, :july).to_s + rule_str.should == '毎年6月、7月' + end + + it 'should be able to say the second to last monday of the month' do + rule_str = IceCube::Rule.monthly.day_of_week(:thursday => [-2]).to_s + rule_str.should == '毎月最後から2番目の木曜' + end + + it 'should join the first and last weekdays of the month' do + rule_str = IceCube::Rule.monthly.day_of_week(:thursday => [1, -1]).to_s + rule_str.should == '毎月1木曜、最終木曜' + end + + it 'should be able to say the days of the month something happens' do + rule_str = IceCube::Rule.monthly.day_of_month(1, 15, 30).to_s + rule_str.should == '毎月1、15、30日' + end + + it 'should be able to say what day of the year something happens' do + rule_str = IceCube::Rule.yearly.day_of_year(30).to_s + rule_str.should == '毎年30日' + end + + it 'should be able to say what hour of the day something happens' do + rule_str = IceCube::Rule.daily.hour_of_day(6, 12).to_s + rule_str.should == '毎日6、12時' + end + + it 'should be able to say what minute of an hour something happens - with special suffix minutes' do + rule_str = IceCube::Rule.hourly.minute_of_hour(10, 11, 12, 13, 14, 15).to_s + rule_str.should == '毎時間10、11、12、13、14、15分' + end + + it 'should be able to say what seconds of the minute something happens' do + rule_str = IceCube::Rule.minutely.second_of_minute(10, 11).to_s + rule_str.should == '毎分10、11秒' + end + + it 'should be able to reflect until dates' do + schedule = IceCube::Schedule.new(Time.now) + schedule.rrule IceCube::Rule.weekly.until(Time.local(2012, 2, 3)) + schedule.to_s.should == '2012年02月03日まで毎週' + end + + it 'should be able to reflect count' do + schedule = IceCube::Schedule.new(Time.now) + schedule.add_recurrence_rule IceCube::Rule.weekly.count(1) + schedule.to_s.should == '毎週1回' + end + + it 'should be able to reflect count (proper pluralization)' do + schedule = IceCube::Schedule.new(Time.now) + schedule.add_recurrence_rule IceCube::Rule.weekly.count(2) + schedule.to_s.should == '毎週2回' + end + +end From 10e61724f2f8c50dad86215aac04cc83beeb00b4 Mon Sep 17 00:00:00 2001 From: Tomo Matsumoto Date: Fri, 7 Nov 2014 08:56:52 +0900 Subject: [PATCH 08/26] delete `s.add_development_dependency('i18n')` and add `gem 'i18n'` in Gemfile --- Gemfile | 2 ++ ice_cube.gemspec | 1 - 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/Gemfile b/Gemfile index fa75df15..40fb1292 100644 --- a/Gemfile +++ b/Gemfile @@ -1,3 +1,5 @@ source 'https://rubygems.org' gemspec + +gem 'i18n' \ No newline at end of file diff --git a/ice_cube.gemspec b/ice_cube.gemspec index 6f89238d..9854163d 100644 --- a/ice_cube.gemspec +++ b/ice_cube.gemspec @@ -21,5 +21,4 @@ Gem::Specification.new do |s| s.add_development_dependency('rspec', '~> 2.12.0') s.add_development_dependency('activesupport', '>= 3.0.0') s.add_development_dependency('tzinfo') - s.add_development_dependency('i18n') end From 1865a7866c9dd754a21b72e75aa7ccca15a096d6 Mon Sep 17 00:00:00 2001 From: Tomo Matsumoto Date: Sat, 8 Nov 2014 10:35:21 +0900 Subject: [PATCH 09/26] s.add_runtime_dependency('i18n') --- Gemfile | 4 +--- ice_cube.gemspec | 1 + 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/Gemfile b/Gemfile index 40fb1292..cd8aa9e0 100644 --- a/Gemfile +++ b/Gemfile @@ -1,5 +1,3 @@ source 'https://rubygems.org' -gemspec - -gem 'i18n' \ No newline at end of file +gemspec \ No newline at end of file diff --git a/ice_cube.gemspec b/ice_cube.gemspec index 9854163d..6f41e090 100644 --- a/ice_cube.gemspec +++ b/ice_cube.gemspec @@ -21,4 +21,5 @@ Gem::Specification.new do |s| s.add_development_dependency('rspec', '~> 2.12.0') s.add_development_dependency('activesupport', '>= 3.0.0') s.add_development_dependency('tzinfo') + s.add_runtime_dependency('i18n') end From 33697c5a86de8fdb1aeef586ae49abc406054987 Mon Sep 17 00:00:00 2001 From: David Gil Date: Tue, 9 Dec 2014 11:14:51 +0100 Subject: [PATCH 10/26] un-memoize IceCube.to_s_time_format to allow changing locale in runtime; fix tests --- lib/ice_cube.rb | 2 +- spec/examples/occurrence_spec.rb | 2 +- spec/examples/schedule_spec.rb | 14 +++++++------- spec/examples/to_s_ja_spec.rb | 5 ++++- 4 files changed, 13 insertions(+), 10 deletions(-) diff --git a/lib/ice_cube.rb b/lib/ice_cube.rb index 269339f8..7b290cca 100644 --- a/lib/ice_cube.rb +++ b/lib/ice_cube.rb @@ -72,7 +72,7 @@ module Validations # Defines the format used by IceCube when printing out Schedule#to_s. # Defaults to '%B %e, %Y' def self.to_s_time_format - @to_s_time_format ||= I18n.t("ice_cube.date.formats.default") + I18n.t("ice_cube.date.formats.default") end # Sets the format used by IceCube when printing out Schedule#to_s. diff --git a/spec/examples/occurrence_spec.rb b/spec/examples/occurrence_spec.rb index e46f29ca..7498a476 100644 --- a/spec/examples/occurrence_spec.rb +++ b/spec/examples/occurrence_spec.rb @@ -28,7 +28,7 @@ end it "accepts a format option to comply with ActiveSupport" do - require 'active_support/core_ext/time' + # require 'active_support/core_ext/time' time_now = Time.current occurrence = Occurrence.new(time_now) diff --git a/spec/examples/schedule_spec.rb b/spec/examples/schedule_spec.rb index ea49c951..0f353aaf 100644 --- a/spec/examples/schedule_spec.rb +++ b/spec/examples/schedule_spec.rb @@ -457,8 +457,8 @@ t0 = Time.utc(2013, 5, 18, 12, 34) schedule = IceCube::Schedule.new(t0) schedule.add_recurrence_rule IceCube::Rule.daily - previous = schedule.previous_occurrence(t0 + 2 * ONE_DAY) - previous.should == t0 + ONE_DAY + previous = schedule.previous_occurrence(t0 + 2 * IceCube::ONE_DAY) + previous.should == t0 + IceCube::ONE_DAY end it 'returns nil given the start time' do @@ -485,16 +485,16 @@ t0 = Time.utc(2013, 5, 18, 12, 34) schedule = IceCube::Schedule.new(t0) schedule.add_recurrence_rule IceCube::Rule.daily - previous = schedule.previous_occurrences(2, t0 + 3 * ONE_DAY) - previous.should == [t0 + ONE_DAY, t0 + 2 * ONE_DAY] + previous = schedule.previous_occurrences(2, t0 + 3 * IceCube::ONE_DAY) + previous.should == [t0 + IceCube::ONE_DAY, t0 + 2 * IceCube::ONE_DAY] end it 'limits the returned occurrences to a given count' do t0 = Time.utc(2013, 5, 18, 12, 34) schedule = IceCube::Schedule.new(t0) schedule.add_recurrence_rule IceCube::Rule.daily - previous = schedule.previous_occurrences(999, t0 + 2 * ONE_DAY) - previous.should == [t0, t0 + ONE_DAY] + previous = schedule.previous_occurrences(999, t0 + 2 * IceCube::ONE_DAY) + previous.should == [t0, t0 + IceCube::ONE_DAY] end it 'returns empty array given the start time' do @@ -531,7 +531,7 @@ t1 = Time.utc(2013, 5, 31, 12, 34) schedule = IceCube::Schedule.new(t0) schedule.add_recurrence_rule IceCube::Rule.daily.until(t1 + 1) - schedule.last(2).should == [t1 - ONE_DAY, t1] + schedule.last(2).should == [t1 - IceCube::ONE_DAY, t1] end it 'raises an error for a non-terminating schedule' do diff --git a/spec/examples/to_s_ja_spec.rb b/spec/examples/to_s_ja_spec.rb index 6e79b27d..57139a7b 100644 --- a/spec/examples/to_s_ja_spec.rb +++ b/spec/examples/to_s_ja_spec.rb @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- require File.dirname(__FILE__) + '/../spec_helper' describe IceCube::Schedule, 'to_s' do @@ -7,6 +6,10 @@ I18n.locale = :ja end + after :all do + I18n.locale = :en + end + it 'should represent its start time by default' do t0 = Time.local(2013, 2, 14) IceCube::Schedule.new(t0).to_s.should == '2013年02月14日' From 8ef5bf09c4f8d12b6e92b8c47d23749b03ccf53e Mon Sep 17 00:00:00 2001 From: David Gil Date: Tue, 9 Dec 2014 11:37:48 +0100 Subject: [PATCH 11/26] add encoding magic comment to ja_spec --- spec/examples/to_s_ja_spec.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/spec/examples/to_s_ja_spec.rb b/spec/examples/to_s_ja_spec.rb index 57139a7b..011213e3 100644 --- a/spec/examples/to_s_ja_spec.rb +++ b/spec/examples/to_s_ja_spec.rb @@ -1,3 +1,4 @@ +# encoding: utf-8 require File.dirname(__FILE__) + '/../spec_helper' describe IceCube::Schedule, 'to_s' do From c16470b631a21f0c3116873f14cf6eac0e4cef9b Mon Sep 17 00:00:00 2001 From: David Gil Date: Tue, 9 Dec 2014 11:45:37 +0100 Subject: [PATCH 12/26] adding spanish (es) locale and test --- spec/examples/to_s_es_spec.rb | 203 ++++++++++++++++++++++++++++++++++ 1 file changed, 203 insertions(+) create mode 100644 spec/examples/to_s_es_spec.rb diff --git a/spec/examples/to_s_es_spec.rb b/spec/examples/to_s_es_spec.rb new file mode 100644 index 00000000..0af717f4 --- /dev/null +++ b/spec/examples/to_s_es_spec.rb @@ -0,0 +1,203 @@ +# encoding: utf-8 +require File.dirname(__FILE__) + '/../spec_helper' + +describe IceCube::Schedule, 'to_s' do + before :each do + I18n.locale = :es + end + + after :all do + I18n.locale = :en + end + + it 'should represent its start time by default' do + t0 = Time.local(2013, 2, 14) + IceCube::Schedule.new(t0).to_s.should == '14/02/2013' + end + + it 'should have a useful base to_s representation for a secondly rule' do + IceCube::Rule.secondly.to_s.should == 'cada segundo' + IceCube::Rule.secondly(2).to_s.should == 'cada 2 segundos' + end + + it 'should have a useful base to_s representation for a minutely rule' do + IceCube::Rule.minutely.to_s.should == 'cada minuto' + IceCube::Rule.minutely(2).to_s.should == 'cada 2 minutos' + end + + it 'should have a useful base to_s representation for a hourly rule' do + IceCube::Rule.hourly.to_s.should == 'cada hora' + IceCube::Rule.hourly(2).to_s.should == 'cada 2 horas' + end + + it 'should have a useful base to_s representation for a daily rule' do + IceCube::Rule.daily.to_s.should == 'diariamente' + IceCube::Rule.daily(2).to_s.should == 'cada 2 días' + end + + it 'should have a useful base to_s representation for a weekly rule' do + IceCube::Rule.weekly.to_s.should == 'semanalmente' + IceCube::Rule.weekly(2).to_s.should == 'cada 2 semanas' + end + + it 'should have a useful base to_s representation for a monthly rule' do + IceCube::Rule.monthly.to_s.should == 'mensualmente' + IceCube::Rule.monthly(2).to_s.should == 'cada 2 meses' + end + + it 'should have a useful base to_s representation for a yearly rule' do + IceCube::Rule.yearly.to_s.should == 'anualmente' + IceCube::Rule.yearly(2).to_s.should == 'cada 2 años' + end + + it 'should work with various sentence types properly' do + IceCube::Rule.weekly.to_s.should == 'semanalmente' + IceCube::Rule.weekly.day(:monday).to_s.should == 'semanalmente el Lunes' + IceCube::Rule.weekly.day(:monday, :tuesday).to_s.should == 'semanalmente el Lunes y el Martes' + IceCube::Rule.weekly.day(:monday, :tuesday, :wednesday).to_s.should == 'semanalmente el Lunes, el Martes y el Miércoles' + end + + it 'should show saturday and sunday as weekends' do + IceCube::Rule.weekly.day(:saturday, :sunday).to_s.should == 'semanalmente el fin de semana' + end + + it 'should not show saturday and sunday as weekends when other days are present also' do + IceCube::Rule.weekly.day(:sunday, :monday, :saturday).to_s.should == + 'semanalmente el Domingo, el Lunes y el Sábado' + end + + it 'should reorganize days to be in order' do + IceCube::Rule.weekly.day(:tuesday, :monday).to_s.should == + 'semanalmente el Lunes y el Martes' + end + + it 'should show weekdays as such' do + IceCube::Rule.weekly.day( + :monday, :tuesday, :wednesday, + :thursday, :friday + ).to_s.should == 'semanalmente en días laborables' + end + + it 'should not show weekdays as such when a weekend day is present' do + IceCube::Rule.weekly.day( + :sunday, :monday, :tuesday, :wednesday, + :thursday, :friday + ).to_s.should == 'semanalmente el Lunes, el Martes, el Miércoles, el Jueves, el Viernes y el Domingo' + end + + it 'should work with a single date' do + schedule = IceCube::Schedule.new Time.local(2010, 3, 20) + schedule.add_recurrence_time Time.local(2010, 3, 20) + schedule.to_s.should == "20 de Marzo 2010" + end + + it 'should work with additional dates' do + schedule = IceCube::Schedule.new Time.local(2010, 3, 20) + schedule.add_recurrence_time Time.local(2010, 3, 20) + schedule.add_recurrence_time Time.local(2010, 3, 21) + schedule.to_s.should == '20 de Marzo 2010, 21 de Marzo 2010' + end + + it 'should order dates that are out of order' do + schedule = IceCube::Schedule.new Time.now + schedule.add_recurrence_time Time.local(2010, 3, 20) + schedule.add_recurrence_time Time.local(2010, 3, 19) + schedule.to_s.should == '19 de Marzo 2010, 20 de Marzo 2010' + end + + it 'should remove duplicate rdates' do + schedule = IceCube::Schedule.new Time.now + schedule.add_recurrence_time Time.local(2010, 3, 20) + schedule.add_recurrence_time Time.local(2010, 3, 20) + schedule.to_s.should == '20 de Marzo 2010' + end + + it 'should work with rules and dates' do + schedule = IceCube::Schedule.new Time.local(2010, 3, 20) + schedule.add_recurrence_time Time.local(2010, 3, 20) + schedule.add_recurrence_rule IceCube::Rule.weekly + schedule.to_s.should == '20 de Marzo 2010, semanalmente' + end + + it 'should work with rules and dates and exdates' do + schedule = IceCube::Schedule.new Time.local(2010, 3, 20) + schedule.add_recurrence_rule IceCube::Rule.weekly + schedule.add_recurrence_time Time.local(2010, 3, 20) + schedule.add_exception_date Time.local(2010, 3, 20) # ignored + schedule.add_exception_date Time.local(2010, 3, 21) + schedule.to_s.should == 'semanalmente, excepto el 20 de Marzo 2010 y 21 de Marzo 2010' + end + + it 'should work with a single rrule' do + pending 'remove dependency' + schedule = IceCube::Schedule.new Time.local(2010, 3, 20) + schedule.add_recurrence_rule IceCube::Rule.weekly.day_of_week(:monday => [1]) + schedule.to_s.should == schedule.rrules[0].to_s + end + + it 'should be able to say the last monday of the month' do + rule_str = IceCube::Rule.monthly.day_of_week(:thursday => [-1]).to_s + rule_str.should == 'mensualmente en el último Jueves' + end + + it 'should be able to say what months of the year something happens' do + rule_str = IceCube::Rule.yearly.month_of_year(:june, :july).to_s + rule_str.should == 'anualmente en Junio y Julio' + end + + it 'should be able to say the second to last monday of the month' do + pending 'penultimo' + rule_str = IceCube::Rule.monthly.day_of_week(:thursday => [-2]).to_s + rule_str.should == 'mensualmente del segundo al último Jueves del mes' + end + + it 'should be able to say the days of the month something happens' do + rule_str = IceCube::Rule.monthly.day_of_month(1, 15, 30).to_s + rule_str.should == 'mensualmente en los días 1, 15 y 30 del mes' + end + + it 'should be able to say what day of the year something happens' do + rule_str = IceCube::Rule.yearly.day_of_year(30).to_s + rule_str.should == 'anualmente en el día 30' + end + + it 'should be able to say what hour of the day something happens' do + rule_str = IceCube::Rule.daily.hour_of_day(6, 12).to_s + rule_str.should == 'diariamente en las horas 6 y 12' + end + + it 'should be able to say what minute of an hour something happens - with special suffix minutes' do + rule_str = IceCube::Rule.hourly.minute_of_hour(10, 11, 12, 13, 14, 15).to_s + rule_str.should == 'cada hora en los minutos 10, 11, 12, 13, 14 y 15' + end + + it 'should be able to say what seconds of the minute something happens' do + rule_str = IceCube::Rule.minutely.second_of_minute(10, 11).to_s + rule_str.should == 'cada minuto en los segundos 10 y 11' + end + + it 'should be able to reflect until dates' do + schedule = IceCube::Schedule.new(Time.now) + schedule.rrule IceCube::Rule.weekly.until(Time.local(2012, 2, 3)) + schedule.to_s.should == 'semanalmente hasta el 3 de Febrero 2012' + end + + it 'should be able to reflect count' do + schedule = IceCube::Schedule.new(Time.now) + schedule.add_recurrence_rule IceCube::Rule.weekly.count(1) + schedule.to_s.should == 'semanalmente 1 vez' + end + + it 'should be able to reflect count (proper pluralization)' do + schedule = IceCube::Schedule.new(Time.now) + schedule.add_recurrence_rule IceCube::Rule.weekly.count(2) + schedule.to_s.should == 'semanalmente 2 veces' + end + + it 'should work when an end_time is set' do + schedule = IceCube::Schedule.new(Time.local(2012, 8, 31), :end_time => Time.local(2012, 10, 31)) + schedule.add_recurrence_rule IceCube::Rule.daily.count(2) + schedule.to_s.should == 'diariamente 2 veces, hasta el 31 de Octubre 2012' + end + +end From c2c46269998fbce01ecfdef95d11dff455503586 Mon Sep 17 00:00:00 2001 From: David Gil Date: Tue, 9 Dec 2014 12:48:49 +0100 Subject: [PATCH 13/26] change strftime into I18n.l accross the code and add spanish ES locale and test --- config/locales/es.yml | 176 ++++++++++++++++++++++++++ lib/ice_cube/builders/ical_builder.rb | 6 +- lib/ice_cube/schedule.rb | 5 +- lib/ice_cube/validations/until.rb | 2 +- spec/examples/to_s_en_spec.rb | 6 +- spec/examples/to_s_es_spec.rb | 106 ++++++++-------- 6 files changed, 242 insertions(+), 59 deletions(-) create mode 100644 config/locales/es.yml diff --git a/config/locales/es.yml b/config/locales/es.yml new file mode 100644 index 00000000..aebd3f01 --- /dev/null +++ b/config/locales/es.yml @@ -0,0 +1,176 @@ +es: + ice_cube: + pieces_connector: ', ' + not: 'excepto %{target}' + not_on: 'excepto el %{target}' + date: + formats: + default: '%-d de %B de %Y' + month_names: + - + - Enero + - Febrero + - Marzo + - Abril + - Mayo + - Junio + - Julio + - Agosto + - Septiembre + - Octubre + - Noviembre + - Diciembre + day_names: + - Domingo + - Lunes + - Martes + - Miércoles + - Jueves + - Viernes + - Sábado + times: + other: '%{count} veces' + one: '%{count} vez' + until: 'hasta el %{date}' + days_of_week: '%{segments} %{day}' + days_of_month: + other: 'los días %{segments} del mes' + one: 'el día %{segments} del mes' + days_of_year: + one: 'el día %{segments}' + other: 'los días %{segments}' + at_hours_of_the_day: + one: 'en la hora %{segments}' + other: 'en las horas %{segments}' + on_minutes_of_hour: + one: 'en el minuto %{segments}' + other: 'en los minutos %{segments}' + at_seconds_of_minute: + one: 'en el segundo %{segments}' + other: 'en los segundos %{segments}' + on_seconds_of_minute: + one: 'en el segundo %{segments} del minuto' + other: 'en los segundos %{segments} del minuto' + on_days: '%{days}' + each_second: + one: Cada segundo + other: 'Cada %{count} segundos' + each_minute: + one: Cada minuto + other: 'Cada %{count} minutos' + each_hour: + one: Cada hora + other: 'Cada %{count} horas' + each_day: + one: Diariamente + other: 'Cada %{count} días' + each_week: + one: Semanalmente + other: 'Cada %{count} semanas' + each_month: + one: Mensualmente + other: 'Cada %{count} meses' + each_year: + one: Anualmente + other: 'Cada %{count} años' + 'on': 'en %{sentence}' + in: 'en %{target}' + integer: + negative: '%{ordinal} por la cola' + literal_ordinals: + -1: el último + -2: el penúltimo + ordinal: '%{number}%{ordinal}' + ordinals: + default: º + 1: º + 2: º + 3: º + 11: º + 12: º + 13: º + on_weekends: en fin de semana + on_weekdays: en días laborables + days_on: + - los domingos + - los lunes + - los martes + - los miércoles + - los jueves + - los viernes + - los sábados + on_days: '%{days}' + array: + last_word_connector: ' y ' + two_words_connector: ' y ' + words_connector: ', ' + string: + format: + day: '%{rest} %{current}' + day_of_week: '%{rest} %{current}' + day_of_month: '%{rest} %{current}' + day_of_year: '%{rest} %{current}' + hour_of_day: '%{rest} %{current}' + minute_of_hour: '%{rest} %{current}' + until: '%{rest} %{current}' + count: '%{rest} %{current}' + default: '%{rest} %{current}' + + date: + day_names: + - Domingo + - Lunes + - Martes + - Miércoles + - Jueves + - Viernes + - Sábado + abbr_day_names: + - Dom + - Lun + - Mar + - Mie + - Jue + - Vie + - Sab + # Don't forget the nil at the beginning; there's no such thing as a 0th month + month_names: + - + - Enero + - Febrero + - Marzo + - Abril + - Mayo + - Junio + - Julio + - Agosto + - Septiembre + - Octubre + - Noviembre + - Diciembre + abbr_month_names: + - + - Ene + - Feb + - Mar + - Abr + - May + - Jun + - Jul + - Ago + - Sep + - Oct + - Nov + - Dic + formats: + default: '%d/%m/%Y' + long: '%d de %B de %Y' + short: '%d de %B' + + time: + formats: + default: "%A, %d de %B de %Y %H:%M:%S %z" + short: "%d de %b %H:%M" + long: "%d de %B de %Y a las %H:%M" + am: "am" + pm: "pm" diff --git a/lib/ice_cube/builders/ical_builder.rb b/lib/ice_cube/builders/ical_builder.rb index d6592a6a..67e87cd8 100644 --- a/lib/ice_cube/builders/ical_builder.rb +++ b/lib/ice_cube/builders/ical_builder.rb @@ -32,15 +32,15 @@ def to_s def self.ical_utc_format(time) time = time.dup.utc - "#{time.strftime('%Y%m%dT%H%M%SZ')}" # utc time + I18n.l(time, format: '%Y%m%dT%H%M%SZ') # utc time end def self.ical_format(time, force_utc) time = time.dup.utc if force_utc if time.utc? - ":#{time.strftime('%Y%m%dT%H%M%SZ')}" # utc time + ":#{I18n.l(time, format: '%Y%m%dT%H%M%SZ')}" # utc time else - ";TZID=#{time.strftime('%Z:%Y%m%dT%H%M%S')}" # local time specified + ";TZID=#{I18n.l(time, format: '%Z:%Y%m%dT%H%M%S')}" # local time specified end end diff --git a/lib/ice_cube/schedule.rb b/lib/ice_cube/schedule.rb index 2da82ef4..1b6a09c1 100644 --- a/lib/ice_cube/schedule.rb +++ b/lib/ice_cube/schedule.rb @@ -313,11 +313,12 @@ def last(n = nil) def to_s pieces = [] rd = recurrence_times_with_start_time - extimes - pieces.concat rd.sort.map { |t| t.strftime(IceCube.to_s_time_format) } + pieces.concat rd.sort.map { |t| I18n.l(t, format: IceCube.to_s_time_format) } pieces.concat rrules.map { |t| t.to_s } pieces.concat exrules.map { |t| I18n.t('ice_cube.not', target: t.to_s) } pieces.concat extimes.sort.map { |t| - I18n.t('ice_cube.not_on', target: t.strftime(IceCube.to_s_time_format)) + target = I18n.l(t, format: IceCube.to_s_time_format) + I18n.t('ice_cube.not_on', target: target) } pieces.join(I18n.t('ice_cube.pieces_connector')) end diff --git a/lib/ice_cube/validations/until.rb b/lib/ice_cube/validations/until.rb index 56a264b6..8771734f 100644 --- a/lib/ice_cube/validations/until.rb +++ b/lib/ice_cube/validations/until.rb @@ -38,7 +38,7 @@ def validate(step_time, schedule) end def build_s(builder) - date = time.strftime(IceCube.to_s_time_format) + date = I18n.l(time, format: IceCube.to_s_time_format) builder.piece(:until) << I18n.t('ice_cube.until', date: date) end diff --git a/spec/examples/to_s_en_spec.rb b/spec/examples/to_s_en_spec.rb index d41193ce..148b969f 100644 --- a/spec/examples/to_s_en_spec.rb +++ b/spec/examples/to_s_en_spec.rb @@ -100,8 +100,8 @@ end it 'should order dates that are out of order' do - schedule = IceCube::Schedule.new(t0 = Time.local(2010, 3, 20)) - schedule.add_recurrence_time t1 = Time.local(2010, 3, 19) + schedule = IceCube::Schedule.new Time.local(2010, 3, 20) + schedule.add_recurrence_time Time.local(2010, 3, 19) schedule.to_s.should == 'March 19, 2010 / March 20, 2010' end @@ -112,7 +112,7 @@ end it 'should remove duplicate rtimes' do - schedule = IceCube::Schedule.new t0 = Time.local(2010, 3, 19) + schedule = IceCube::Schedule.new Time.local(2010, 3, 19) schedule.add_recurrence_time Time.local(2010, 3, 20) schedule.add_recurrence_time Time.local(2010, 3, 20) schedule.to_s.should == 'March 19, 2010 / March 20, 2010' diff --git a/spec/examples/to_s_es_spec.rb b/spec/examples/to_s_es_spec.rb index 0af717f4..dadaa87e 100644 --- a/spec/examples/to_s_es_spec.rb +++ b/spec/examples/to_s_es_spec.rb @@ -12,111 +12,116 @@ it 'should represent its start time by default' do t0 = Time.local(2013, 2, 14) - IceCube::Schedule.new(t0).to_s.should == '14/02/2013' + IceCube::Schedule.new(t0).to_s.should == '14 de Febrero de 2013' end it 'should have a useful base to_s representation for a secondly rule' do - IceCube::Rule.secondly.to_s.should == 'cada segundo' - IceCube::Rule.secondly(2).to_s.should == 'cada 2 segundos' + IceCube::Rule.secondly.to_s.should == 'Cada segundo' + IceCube::Rule.secondly(2).to_s.should == 'Cada 2 segundos' end it 'should have a useful base to_s representation for a minutely rule' do - IceCube::Rule.minutely.to_s.should == 'cada minuto' - IceCube::Rule.minutely(2).to_s.should == 'cada 2 minutos' + IceCube::Rule.minutely.to_s.should == 'Cada minuto' + IceCube::Rule.minutely(2).to_s.should == 'Cada 2 minutos' end it 'should have a useful base to_s representation for a hourly rule' do - IceCube::Rule.hourly.to_s.should == 'cada hora' - IceCube::Rule.hourly(2).to_s.should == 'cada 2 horas' + IceCube::Rule.hourly.to_s.should == 'Cada hora' + IceCube::Rule.hourly(2).to_s.should == 'Cada 2 horas' end it 'should have a useful base to_s representation for a daily rule' do - IceCube::Rule.daily.to_s.should == 'diariamente' - IceCube::Rule.daily(2).to_s.should == 'cada 2 días' + IceCube::Rule.daily.to_s.should == 'Diariamente' + IceCube::Rule.daily(2).to_s.should == 'Cada 2 días' end it 'should have a useful base to_s representation for a weekly rule' do - IceCube::Rule.weekly.to_s.should == 'semanalmente' - IceCube::Rule.weekly(2).to_s.should == 'cada 2 semanas' + IceCube::Rule.weekly.to_s.should == 'Semanalmente' + IceCube::Rule.weekly(2).to_s.should == 'Cada 2 semanas' end it 'should have a useful base to_s representation for a monthly rule' do - IceCube::Rule.monthly.to_s.should == 'mensualmente' - IceCube::Rule.monthly(2).to_s.should == 'cada 2 meses' + IceCube::Rule.monthly.to_s.should == 'Mensualmente' + IceCube::Rule.monthly(2).to_s.should == 'Cada 2 meses' end it 'should have a useful base to_s representation for a yearly rule' do - IceCube::Rule.yearly.to_s.should == 'anualmente' - IceCube::Rule.yearly(2).to_s.should == 'cada 2 años' + IceCube::Rule.yearly.to_s.should == 'Anualmente' + IceCube::Rule.yearly(2).to_s.should == 'Cada 2 años' end it 'should work with various sentence types properly' do - IceCube::Rule.weekly.to_s.should == 'semanalmente' - IceCube::Rule.weekly.day(:monday).to_s.should == 'semanalmente el Lunes' - IceCube::Rule.weekly.day(:monday, :tuesday).to_s.should == 'semanalmente el Lunes y el Martes' - IceCube::Rule.weekly.day(:monday, :tuesday, :wednesday).to_s.should == 'semanalmente el Lunes, el Martes y el Miércoles' + IceCube::Rule.weekly.to_s.should == 'Semanalmente' + IceCube::Rule.weekly.day(:monday).to_s.should == 'Semanalmente los lunes' + IceCube::Rule.weekly.day(:monday, :tuesday).to_s.should == 'Semanalmente los lunes y los martes' + IceCube::Rule.weekly.day(:monday, :tuesday, :wednesday).to_s.should == 'Semanalmente los lunes, los martes y los miércoles' end it 'should show saturday and sunday as weekends' do - IceCube::Rule.weekly.day(:saturday, :sunday).to_s.should == 'semanalmente el fin de semana' + IceCube::Rule.weekly.day(:saturday, :sunday).to_s.should == 'Semanalmente en fin de semana' end it 'should not show saturday and sunday as weekends when other days are present also' do IceCube::Rule.weekly.day(:sunday, :monday, :saturday).to_s.should == - 'semanalmente el Domingo, el Lunes y el Sábado' + 'Semanalmente los domingos, los lunes y los sábados' end it 'should reorganize days to be in order' do IceCube::Rule.weekly.day(:tuesday, :monday).to_s.should == - 'semanalmente el Lunes y el Martes' + 'Semanalmente los lunes y los martes' end it 'should show weekdays as such' do IceCube::Rule.weekly.day( :monday, :tuesday, :wednesday, :thursday, :friday - ).to_s.should == 'semanalmente en días laborables' + ).to_s.should == 'Semanalmente en días laborables' end it 'should not show weekdays as such when a weekend day is present' do IceCube::Rule.weekly.day( :sunday, :monday, :tuesday, :wednesday, :thursday, :friday - ).to_s.should == 'semanalmente el Lunes, el Martes, el Miércoles, el Jueves, el Viernes y el Domingo' + ).to_s.should == 'Semanalmente los domingos, los lunes, los martes, los miércoles, los jueves y los viernes' end it 'should work with a single date' do schedule = IceCube::Schedule.new Time.local(2010, 3, 20) schedule.add_recurrence_time Time.local(2010, 3, 20) - schedule.to_s.should == "20 de Marzo 2010" + schedule.to_s.should == "20 de Marzo de 2010" end it 'should work with additional dates' do schedule = IceCube::Schedule.new Time.local(2010, 3, 20) schedule.add_recurrence_time Time.local(2010, 3, 20) schedule.add_recurrence_time Time.local(2010, 3, 21) - schedule.to_s.should == '20 de Marzo 2010, 21 de Marzo 2010' + schedule.to_s.should == '20 de Marzo de 2010, 21 de Marzo de 2010' end it 'should order dates that are out of order' do - schedule = IceCube::Schedule.new Time.now - schedule.add_recurrence_time Time.local(2010, 3, 20) + schedule = IceCube::Schedule.new Time.local(2010, 3, 20) schedule.add_recurrence_time Time.local(2010, 3, 19) - schedule.to_s.should == '19 de Marzo 2010, 20 de Marzo 2010' + schedule.to_s.should == '19 de Marzo de 2010, 20 de Marzo de 2010' + end + + it 'should remove duplicated start time' do + schedule = IceCube::Schedule.new t0 = Time.local(2010, 3, 20) + schedule.add_recurrence_time t0 + schedule.to_s.should == '20 de Marzo de 2010' end - it 'should remove duplicate rdates' do - schedule = IceCube::Schedule.new Time.now + it 'should remove duplicate rtimes' do + schedule = IceCube::Schedule.new Time.local(2010, 3, 20) schedule.add_recurrence_time Time.local(2010, 3, 20) schedule.add_recurrence_time Time.local(2010, 3, 20) - schedule.to_s.should == '20 de Marzo 2010' + schedule.to_s.should == '20 de Marzo de 2010' end it 'should work with rules and dates' do schedule = IceCube::Schedule.new Time.local(2010, 3, 20) schedule.add_recurrence_time Time.local(2010, 3, 20) schedule.add_recurrence_rule IceCube::Rule.weekly - schedule.to_s.should == '20 de Marzo 2010, semanalmente' + schedule.to_s.should == '20 de Marzo de 2010, Semanalmente' end it 'should work with rules and dates and exdates' do @@ -125,7 +130,8 @@ schedule.add_recurrence_time Time.local(2010, 3, 20) schedule.add_exception_date Time.local(2010, 3, 20) # ignored schedule.add_exception_date Time.local(2010, 3, 21) - schedule.to_s.should == 'semanalmente, excepto el 20 de Marzo 2010 y 21 de Marzo 2010' + # TODO: this text should be improved to add sentence connector + schedule.to_s.should == 'Semanalmente, excepto el 20 de Marzo de 2010, excepto el 21 de Marzo de 2010' end it 'should work with a single rrule' do @@ -137,67 +143,67 @@ it 'should be able to say the last monday of the month' do rule_str = IceCube::Rule.monthly.day_of_week(:thursday => [-1]).to_s - rule_str.should == 'mensualmente en el último Jueves' + rule_str.should == 'Mensualmente en el último Jueves' end it 'should be able to say what months of the year something happens' do rule_str = IceCube::Rule.yearly.month_of_year(:june, :july).to_s - rule_str.should == 'anualmente en Junio y Julio' + rule_str.should == 'Anualmente en Junio y Julio' end it 'should be able to say the second to last monday of the month' do pending 'penultimo' rule_str = IceCube::Rule.monthly.day_of_week(:thursday => [-2]).to_s - rule_str.should == 'mensualmente del segundo al último Jueves del mes' + rule_str.should == 'Mensualmente del segundo al último Jueves del mes' end it 'should be able to say the days of the month something happens' do rule_str = IceCube::Rule.monthly.day_of_month(1, 15, 30).to_s - rule_str.should == 'mensualmente en los días 1, 15 y 30 del mes' + rule_str.should == 'Mensualmente en los días 1º, 15º y 30º del mes' end it 'should be able to say what day of the year something happens' do rule_str = IceCube::Rule.yearly.day_of_year(30).to_s - rule_str.should == 'anualmente en el día 30' + rule_str.should == 'Anualmente en el día 30º' end it 'should be able to say what hour of the day something happens' do rule_str = IceCube::Rule.daily.hour_of_day(6, 12).to_s - rule_str.should == 'diariamente en las horas 6 y 12' + rule_str.should == 'Diariamente en las horas 6º y 12º' end it 'should be able to say what minute of an hour something happens - with special suffix minutes' do rule_str = IceCube::Rule.hourly.minute_of_hour(10, 11, 12, 13, 14, 15).to_s - rule_str.should == 'cada hora en los minutos 10, 11, 12, 13, 14 y 15' + rule_str.should == 'Cada hora en los minutos 10º, 11º, 12º, 13º, 14º y 15º' end it 'should be able to say what seconds of the minute something happens' do rule_str = IceCube::Rule.minutely.second_of_minute(10, 11).to_s - rule_str.should == 'cada minuto en los segundos 10 y 11' + rule_str.should == 'Cada minuto en los segundos 10º y 11º del minuto' end it 'should be able to reflect until dates' do schedule = IceCube::Schedule.new(Time.now) schedule.rrule IceCube::Rule.weekly.until(Time.local(2012, 2, 3)) - schedule.to_s.should == 'semanalmente hasta el 3 de Febrero 2012' + schedule.to_s.should == 'Semanalmente hasta el 3 de Febrero de 2012' end it 'should be able to reflect count' do schedule = IceCube::Schedule.new(Time.now) schedule.add_recurrence_rule IceCube::Rule.weekly.count(1) - schedule.to_s.should == 'semanalmente 1 vez' + schedule.to_s.should == 'Semanalmente 1 vez' end it 'should be able to reflect count (proper pluralization)' do schedule = IceCube::Schedule.new(Time.now) schedule.add_recurrence_rule IceCube::Rule.weekly.count(2) - schedule.to_s.should == 'semanalmente 2 veces' + schedule.to_s.should == 'Semanalmente 2 veces' end - it 'should work when an end_time is set' do - schedule = IceCube::Schedule.new(Time.local(2012, 8, 31), :end_time => Time.local(2012, 10, 31)) - schedule.add_recurrence_rule IceCube::Rule.daily.count(2) - schedule.to_s.should == 'diariamente 2 veces, hasta el 31 de Octubre 2012' - end + # it 'should work when an end_time is set' do + # schedule = IceCube::Schedule.new(Time.local(2012, 8, 31), :end_time => Time.local(2012, 10, 31)) + # schedule.add_recurrence_rule IceCube::Rule.daily.count(2) + # schedule.to_s.should == 'Diariamente 2 veces, hasta el 31 de Octubre 2012' + # end end From 5c6cf58e4d206acfab7ad6672d597d764ac4ad93 Mon Sep 17 00:00:00 2001 From: Isaac Seymour Date: Tue, 17 Mar 2015 21:49:07 +0000 Subject: [PATCH 14/26] Add NullI18n and IceCube::I18n to remove runtime dependency --- config/locales/en.yml | 62 +++ ice_cube.gemspec | 2 +- lib/ice_cube.rb | 6 +- lib/ice_cube/builders/ical_builder.rb | 6 +- lib/ice_cube/builders/string_builder.rb | 20 +- lib/ice_cube/i18n.rb | 24 + lib/ice_cube/null_i18n.rb | 28 ++ lib/ice_cube/schedule.rb | 10 +- lib/ice_cube/validations/count.rb | 2 +- lib/ice_cube/validations/daily_interval.rb | 2 +- lib/ice_cube/validations/day.rb | 8 +- lib/ice_cube/validations/day_of_month.rb | 4 +- lib/ice_cube/validations/day_of_week.rb | 8 +- lib/ice_cube/validations/day_of_year.rb | 4 +- lib/ice_cube/validations/hour_of_day.rb | 2 +- lib/ice_cube/validations/hourly_interval.rb | 2 +- lib/ice_cube/validations/minute_of_hour.rb | 2 +- lib/ice_cube/validations/minutely_interval.rb | 2 +- lib/ice_cube/validations/month_of_year.rb | 4 +- lib/ice_cube/validations/monthly_interval.rb | 2 +- lib/ice_cube/validations/second_of_minute.rb | 2 +- lib/ice_cube/validations/secondly_interval.rb | 2 +- lib/ice_cube/validations/until.rb | 4 +- lib/ice_cube/validations/weekly_interval.rb | 2 +- lib/ice_cube/validations/yearly_interval.rb | 2 +- spec/examples/to_s_en_spec.rb | 416 +++++++++--------- 26 files changed, 380 insertions(+), 248 deletions(-) create mode 100644 lib/ice_cube/i18n.rb create mode 100644 lib/ice_cube/null_i18n.rb diff --git a/config/locales/en.yml b/config/locales/en.yml index 3bc1d465..b1ad9023 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -114,3 +114,65 @@ en: until: '%{rest} %{current}' count: '%{rest} %{current}' default: '%{rest} %{current}' + + date: + abbr_day_names: + - Sun + - Mon + - Tue + - Wed + - Thu + - Fri + - Sat + abbr_month_names: + - + - Jan + - Feb + - Mar + - Apr + - May + - Jun + - Jul + - Aug + - Sep + - Oct + - Nov + - Dec + day_names: + - Sunday + - Monday + - Tuesday + - Wednesday + - Thursday + - Friday + - Saturday + formats: + default: "%Y-%m-%d" + long: "%B %d, %Y" + short: "%b %d" + month_names: + - + - January + - February + - March + - April + - May + - June + - July + - August + - September + - October + - November + - December + order: + - :year + - :month + - :day + + time: + am: am + formats: + default: "%a, %d %b %Y %H:%M:%S %z" + long: "%B %d, %Y %H:%M" + short: "%d %b %H:%M" + pm: pm diff --git a/ice_cube.gemspec b/ice_cube.gemspec index 6f41e090..6f89238d 100644 --- a/ice_cube.gemspec +++ b/ice_cube.gemspec @@ -21,5 +21,5 @@ Gem::Specification.new do |s| s.add_development_dependency('rspec', '~> 2.12.0') s.add_development_dependency('activesupport', '>= 3.0.0') s.add_development_dependency('tzinfo') - s.add_runtime_dependency('i18n') + s.add_development_dependency('i18n') end diff --git a/lib/ice_cube.rb b/lib/ice_cube.rb index 7b290cca..fe03d9d5 100644 --- a/lib/ice_cube.rb +++ b/lib/ice_cube.rb @@ -1,8 +1,8 @@ require 'date' require 'ice_cube/deprecated' -require 'i18n' +require 'ice_cube/i18n' -I18n.load_path += Dir[File.expand_path('../../config/locales/*{rb,yml}', __FILE__)] +IceCube::I18n.detect_backend! module IceCube @@ -72,7 +72,7 @@ module Validations # Defines the format used by IceCube when printing out Schedule#to_s. # Defaults to '%B %e, %Y' def self.to_s_time_format - I18n.t("ice_cube.date.formats.default") + IceCube::I18n.t("ice_cube.date.formats.default") end # Sets the format used by IceCube when printing out Schedule#to_s. diff --git a/lib/ice_cube/builders/ical_builder.rb b/lib/ice_cube/builders/ical_builder.rb index 67e87cd8..2ba4e646 100644 --- a/lib/ice_cube/builders/ical_builder.rb +++ b/lib/ice_cube/builders/ical_builder.rb @@ -32,15 +32,15 @@ def to_s def self.ical_utc_format(time) time = time.dup.utc - I18n.l(time, format: '%Y%m%dT%H%M%SZ') # utc time + IceCube::I18n.l(time, format: '%Y%m%dT%H%M%SZ') # utc time end def self.ical_format(time, force_utc) time = time.dup.utc if force_utc if time.utc? - ":#{I18n.l(time, format: '%Y%m%dT%H%M%SZ')}" # utc time + ":#{IceCube::I18n.l(time, format: '%Y%m%dT%H%M%SZ')}" # utc time else - ";TZID=#{I18n.l(time, format: '%Z:%Y%m%dT%H%M%S')}" # local time specified + ";TZID=#{IceCube::I18n.l(time, format: '%Z:%Y%m%dT%H%M%S')}" # local time specified end end diff --git a/lib/ice_cube/builders/string_builder.rb b/lib/ice_cube/builders/string_builder.rb index 7809f6bf..dda38dcc 100644 --- a/lib/ice_cube/builders/string_builder.rb +++ b/lib/ice_cube/builders/string_builder.rb @@ -21,8 +21,8 @@ def to_s next if segments.empty? current = self.class.sentence(segments) end - f = I18n.t('ice_cube.string.format')[type] ? type : 'default' - string = I18n.t("ice_cube.string.format.#{f}", rest: string, current: current) + f = IceCube::I18n.t('ice_cube.string.format')[type] ? type : 'default' + string = IceCube::I18n.t("ice_cube.string.format.#{f}", rest: string, current: current) end string end @@ -43,8 +43,8 @@ def sentence(array) case array.length when 0 ; '' when 1 ; array[0].to_s - when 2 ; "#{array[0]}#{I18n.t('ice_cube.array.two_words_connector')}#{array[1]}" - else ; "#{array[0...-1].join(I18n.t('ice_cube.array.words_connector'))}#{I18n.t('ice_cube.array.last_word_connector')}#{array[-1]}" + when 2 ; "#{array[0]}#{IceCube::I18n.t('ice_cube.array.two_words_connector')}#{array[1]}" + else ; "#{array[0...-1].join(IceCube::I18n.t('ice_cube.array.words_connector'))}#{IceCube::I18n.t('ice_cube.array.last_word_connector')}#{array[-1]}" end end @@ -53,18 +53,18 @@ def nice_number(number) end def ordinalize(number) - I18n.t('ice_cube.integer.ordinal', number: number, ordinal: ordinal(number)) + IceCube::I18n.t('ice_cube.integer.ordinal', number: number, ordinal: ordinal(number)) end def literal_ordinal(number) - I18n.t("ice_cube.integer.literal_ordinals")[number] + IceCube::I18n.t("ice_cube.integer.literal_ordinals")[number] end def ordinal(number) - ord = I18n.t("ice_cube.integer.ordinals")[number] || - I18n.t("ice_cube.integer.ordinals")[number % 10] || - I18n.t('ice_cube.integer.ordinals')[:default] - number >= 0 ? ord : I18n.t("ice_cube.integer.negative", ordinal: ord) + ord = IceCube::I18n.t("ice_cube.integer.ordinals")[number] || + IceCube::I18n.t("ice_cube.integer.ordinals")[number % 10] || + IceCube::I18n.t('ice_cube.integer.ordinals')[:default] + number >= 0 ? ord : IceCube::I18n.t("ice_cube.integer.negative", ordinal: ord) end end diff --git a/lib/ice_cube/i18n.rb b/lib/ice_cube/i18n.rb new file mode 100644 index 00000000..a9c090d9 --- /dev/null +++ b/lib/ice_cube/i18n.rb @@ -0,0 +1,24 @@ +module IceCube + module I18n + def self.t(*args) + backend.t(*args) + end + + def self.l(*args) + backend.l(*args) + end + + def self.backend + @backend + end + + def self.detect_backend! + require 'i18n' + ::I18n.load_path += Dir[File.expand_path('../../../config/locales/*{rb,yml}', __FILE__)] + @backend = ::I18n + rescue LoadError + require 'ice_cube/null_i18n' + @backend = NullI18n + end + end +end diff --git a/lib/ice_cube/null_i18n.rb b/lib/ice_cube/null_i18n.rb new file mode 100644 index 00000000..1dd37fcf --- /dev/null +++ b/lib/ice_cube/null_i18n.rb @@ -0,0 +1,28 @@ +require 'yaml' + +module IceCube + module NullI18n + def self.t(key, options = {}) + base = key.to_s.split('.').reduce(config) { |hash, current_key| hash[current_key] } + + base = base[options[:count] == 1 ? "one" : "other"] if options[:count] + + if base.is_a?(Hash) + return base.each_with_object({}) do |(key, value), hash| + hash[key.is_a?(String) ? key.to_sym : key] = value + end + end + + options.reduce(base) { |result, (find, replace)| result.gsub("%{#{find}}", "#{replace}") } + end + + def self.l(date_or_time, options = {}) + return date_or_time.strftime(options[:format]) if options[:format] + date_or_time.strftime(t('ice_cube.date.formats.default')) + end + + def self.config + @config ||= YAML.load(File.read(File.join(File.dirname(__FILE__), '..', '..', 'config', 'locales', 'en.yml')))['en'] + end + end +end diff --git a/lib/ice_cube/schedule.rb b/lib/ice_cube/schedule.rb index 1b6a09c1..903c28fa 100644 --- a/lib/ice_cube/schedule.rb +++ b/lib/ice_cube/schedule.rb @@ -313,14 +313,14 @@ def last(n = nil) def to_s pieces = [] rd = recurrence_times_with_start_time - extimes - pieces.concat rd.sort.map { |t| I18n.l(t, format: IceCube.to_s_time_format) } + pieces.concat rd.sort.map { |t| IceCube::I18n.l(t, format: IceCube.to_s_time_format) } pieces.concat rrules.map { |t| t.to_s } - pieces.concat exrules.map { |t| I18n.t('ice_cube.not', target: t.to_s) } + pieces.concat exrules.map { |t| IceCube::I18n.t('ice_cube.not', target: t.to_s) } pieces.concat extimes.sort.map { |t| - target = I18n.l(t, format: IceCube.to_s_time_format) - I18n.t('ice_cube.not_on', target: target) + target = IceCube::I18n.l(t, format: IceCube.to_s_time_format) + IceCube::I18n.t('ice_cube.not_on', target: target) } - pieces.join(I18n.t('ice_cube.pieces_connector')) + pieces.join(IceCube::I18n.t('ice_cube.pieces_connector')) end # Serialize this schedule to_ical diff --git a/lib/ice_cube/validations/count.rb b/lib/ice_cube/validations/count.rb index b35e9729..be22fd9e 100644 --- a/lib/ice_cube/validations/count.rb +++ b/lib/ice_cube/validations/count.rb @@ -51,7 +51,7 @@ def build_ical(builder) StringBuilder.register_formatter(:count) do |segments| count = segments.first - I18n.t('ice_cube.times', count: count) + IceCube::I18n.t('ice_cube.times', count: count) end end diff --git a/lib/ice_cube/validations/daily_interval.rb b/lib/ice_cube/validations/daily_interval.rb index f75d207a..635e77f1 100644 --- a/lib/ice_cube/validations/daily_interval.rb +++ b/lib/ice_cube/validations/daily_interval.rb @@ -35,7 +35,7 @@ def validate(step_time, schedule) end def build_s(builder) - builder.base = I18n.t('ice_cube.each_day', count: interval) + builder.base = IceCube::I18n.t('ice_cube.each_day', count: interval) end def build_hash(builder) diff --git a/lib/ice_cube/validations/day.rb b/lib/ice_cube/validations/day.rb index 1fbef4bc..4c6bc56e 100644 --- a/lib/ice_cube/validations/day.rb +++ b/lib/ice_cube/validations/day.rb @@ -54,13 +54,13 @@ def build_ical(builder) validation_days.sort! # pick the right shortening, if applicable if validation_days == [0, 6] - I18n.t('ice_cube.on_weekends') + IceCube::I18n.t('ice_cube.on_weekends') elsif validation_days == (1..5).to_a - I18n.t('ice_cube.on_weekdays') + IceCube::I18n.t('ice_cube.on_weekdays') else - day_names = ->(d){ "#{I18n.t("ice_cube.days_on")[d]}" } + day_names = ->(d){ "#{IceCube::I18n.t("ice_cube.days_on")[d]}" } segments = validation_days.map(&day_names) - I18n.t('ice_cube.on_days', days: StringBuilder.sentence(segments)) + IceCube::I18n.t('ice_cube.on_days', days: StringBuilder.sentence(segments)) end end diff --git a/lib/ice_cube/validations/day_of_month.rb b/lib/ice_cube/validations/day_of_month.rb index cca1e7ae..3acccd7a 100644 --- a/lib/ice_cube/validations/day_of_month.rb +++ b/lib/ice_cube/validations/day_of_month.rb @@ -44,8 +44,8 @@ def build_ical(builder) StringBuilder.register_formatter(:day_of_month) do |entries| sentence = StringBuilder.sentence(entries) - str = I18n.t('ice_cube.days_of_month', count: entries.size, segments: sentence) - I18n.t('ice_cube.on', sentence: str) + str = IceCube::I18n.t('ice_cube.days_of_month', count: entries.size, segments: sentence) + IceCube::I18n.t('ice_cube.on', sentence: str) end end diff --git a/lib/ice_cube/validations/day_of_week.rb b/lib/ice_cube/validations/day_of_week.rb index a9ad49f9..a35ba258 100644 --- a/lib/ice_cube/validations/day_of_week.rb +++ b/lib/ice_cube/validations/day_of_week.rb @@ -45,10 +45,10 @@ def validate(step_time, schedule) end def build_s(builder) - builder.piece(:day_of_week) << I18n.t( + builder.piece(:day_of_week) << IceCube::I18n.t( 'ice_cube.days_of_week', segments: StringBuilder.nice_number(occ), - day: I18n.t('ice_cube.date.day_names')[day] + day: IceCube::I18n.t('ice_cube.date.day_names')[day] ) end @@ -66,8 +66,8 @@ def build_ical(builder) end StringBuilder.register_formatter(:day_of_week) do |segments| - sentence = segments.join(I18n.t('ice_cube.array.two_words_connector')) - I18n.t('ice_cube.on', sentence: sentence) + sentence = segments.join(IceCube::I18n.t('ice_cube.array.two_words_connector')) + IceCube::I18n.t('ice_cube.on', sentence: sentence) end end diff --git a/lib/ice_cube/validations/day_of_year.rb b/lib/ice_cube/validations/day_of_year.rb index 120a565a..e4eba5e8 100644 --- a/lib/ice_cube/validations/day_of_year.rb +++ b/lib/ice_cube/validations/day_of_year.rb @@ -50,8 +50,8 @@ def build_ical(builder) StringBuilder.register_formatter(:day_of_year) do |entries| str = StringBuilder.sentence(entries) - sentence = I18n.t('ice_cube.days_of_year', count: entries.size, segments: str) - I18n.t('ice_cube.on', sentence: sentence) + sentence = IceCube::I18n.t('ice_cube.days_of_year', count: entries.size, segments: str) + IceCube::I18n.t('ice_cube.on', sentence: sentence) end end diff --git a/lib/ice_cube/validations/hour_of_day.rb b/lib/ice_cube/validations/hour_of_day.rb index 877e4eeb..e5258006 100644 --- a/lib/ice_cube/validations/hour_of_day.rb +++ b/lib/ice_cube/validations/hour_of_day.rb @@ -45,7 +45,7 @@ def build_ical(builder) StringBuilder.register_formatter(:hour_of_day) do |segments| str = StringBuilder.sentence(segments) - I18n.t('ice_cube.at_hours_of_the_day', count: segments.size, segments: str) + IceCube::I18n.t('ice_cube.at_hours_of_the_day', count: segments.size, segments: str) end end diff --git a/lib/ice_cube/validations/hourly_interval.rb b/lib/ice_cube/validations/hourly_interval.rb index 1b526953..789b82c1 100644 --- a/lib/ice_cube/validations/hourly_interval.rb +++ b/lib/ice_cube/validations/hourly_interval.rb @@ -35,7 +35,7 @@ def validate(step_time, schedule) end def build_s(builder) - builder.base = I18n.t("ice_cube.each_hour", count: interval) + builder.base = IceCube::I18n.t("ice_cube.each_hour", count: interval) end def build_hash(builder) diff --git a/lib/ice_cube/validations/minute_of_hour.rb b/lib/ice_cube/validations/minute_of_hour.rb index d4fbf14a..dcc70c6f 100644 --- a/lib/ice_cube/validations/minute_of_hour.rb +++ b/lib/ice_cube/validations/minute_of_hour.rb @@ -44,7 +44,7 @@ def build_ical(builder) StringBuilder.register_formatter(:minute_of_hour) do |segments| str = StringBuilder.sentence(segments) - I18n.t('ice_cube.on_minutes_of_hour', count: segments.size, segments: str) + IceCube::I18n.t('ice_cube.on_minutes_of_hour', count: segments.size, segments: str) end end diff --git a/lib/ice_cube/validations/minutely_interval.rb b/lib/ice_cube/validations/minutely_interval.rb index 1363a573..63c8894b 100644 --- a/lib/ice_cube/validations/minutely_interval.rb +++ b/lib/ice_cube/validations/minutely_interval.rb @@ -35,7 +35,7 @@ def validate(step_time, schedule) end def build_s(builder) - builder.base = I18n.t('ice_cube.each_minute', count: interval) + builder.base = IceCube::I18n.t('ice_cube.each_minute', count: interval) end def build_hash(builder) diff --git a/lib/ice_cube/validations/month_of_year.rb b/lib/ice_cube/validations/month_of_year.rb index 4628c386..d7431f2f 100644 --- a/lib/ice_cube/validations/month_of_year.rb +++ b/lib/ice_cube/validations/month_of_year.rb @@ -32,7 +32,7 @@ def dst_adjust? end def build_s(builder) - builder.piece(:month_of_year) << I18n.t("ice_cube.date.month_names")[month] + builder.piece(:month_of_year) << IceCube::I18n.t("ice_cube.date.month_names")[month] end def build_hash(builder) @@ -44,7 +44,7 @@ def build_ical(builder) end StringBuilder.register_formatter(:month_of_year) do |segments| - I18n.t("ice_cube.in", target: StringBuilder.sentence(segments)) + IceCube::I18n.t("ice_cube.in", target: StringBuilder.sentence(segments)) end end diff --git a/lib/ice_cube/validations/monthly_interval.rb b/lib/ice_cube/validations/monthly_interval.rb index b5d75b4b..3939d4a9 100644 --- a/lib/ice_cube/validations/monthly_interval.rb +++ b/lib/ice_cube/validations/monthly_interval.rb @@ -34,7 +34,7 @@ def validate(step_time, schedule) end def build_s(builder) - builder.base = I18n.t('ice_cube.each_month', count: interval) + builder.base = IceCube::I18n.t('ice_cube.each_month', count: interval) end def build_hash(builder) diff --git a/lib/ice_cube/validations/second_of_minute.rb b/lib/ice_cube/validations/second_of_minute.rb index 0ad30198..63b9a818 100644 --- a/lib/ice_cube/validations/second_of_minute.rb +++ b/lib/ice_cube/validations/second_of_minute.rb @@ -44,7 +44,7 @@ def build_ical(builder) StringBuilder.register_formatter(:second_of_minute) do |segments| str = StringBuilder.sentence(segments) - I18n.t('ice_cube.on_seconds_of_minute', count: segments.size, segments: str) + IceCube::I18n.t('ice_cube.on_seconds_of_minute', count: segments.size, segments: str) end end diff --git a/lib/ice_cube/validations/secondly_interval.rb b/lib/ice_cube/validations/secondly_interval.rb index 37d018df..a8a3d77d 100644 --- a/lib/ice_cube/validations/secondly_interval.rb +++ b/lib/ice_cube/validations/secondly_interval.rb @@ -32,7 +32,7 @@ def validate(step_time, schedule) end def build_s(builder) - builder.base = I18n.t("ice_cube.each_second", count: interval) + builder.base = IceCube::I18n.t("ice_cube.each_second", count: interval) end def build_hash(builder) diff --git a/lib/ice_cube/validations/until.rb b/lib/ice_cube/validations/until.rb index 8771734f..748f2bdd 100644 --- a/lib/ice_cube/validations/until.rb +++ b/lib/ice_cube/validations/until.rb @@ -38,8 +38,8 @@ def validate(step_time, schedule) end def build_s(builder) - date = I18n.l(time, format: IceCube.to_s_time_format) - builder.piece(:until) << I18n.t('ice_cube.until', date: date) + date = IceCube::I18n.l(time, format: IceCube.to_s_time_format) + builder.piece(:until) << IceCube::I18n.t('ice_cube.until', date: date) end def build_hash(builder) diff --git a/lib/ice_cube/validations/weekly_interval.rb b/lib/ice_cube/validations/weekly_interval.rb index 73a9d3d4..50e7a6cb 100644 --- a/lib/ice_cube/validations/weekly_interval.rb +++ b/lib/ice_cube/validations/weekly_interval.rb @@ -44,7 +44,7 @@ def validate(step_time, schedule) end def build_s(builder) - builder.base = I18n.t('ice_cube.each_week', count: interval) + builder.base = IceCube::I18n.t('ice_cube.each_week', count: interval) end def build_hash(builder) diff --git a/lib/ice_cube/validations/yearly_interval.rb b/lib/ice_cube/validations/yearly_interval.rb index 09027368..3fa01673 100644 --- a/lib/ice_cube/validations/yearly_interval.rb +++ b/lib/ice_cube/validations/yearly_interval.rb @@ -32,7 +32,7 @@ def validate(step_time, schedule) end def build_s(builder) - builder.base = I18n.t('ice_cube.each_year', count: interval) + builder.base = IceCube::I18n.t('ice_cube.each_year', count: interval) end def build_hash(builder) diff --git a/spec/examples/to_s_en_spec.rb b/spec/examples/to_s_en_spec.rb index 148b969f..b6ca73f6 100644 --- a/spec/examples/to_s_en_spec.rb +++ b/spec/examples/to_s_en_spec.rb @@ -1,206 +1,224 @@ require File.dirname(__FILE__) + '/../spec_helper' +require 'i18n' +require 'ice_cube/null_i18n' describe IceCube::Schedule, 'to_s' do - before :each do - I18n.locale = :en - end - - it 'should represent its start time by default' do - t0 = Time.local(2013, 2, 14) - IceCube::Schedule.new(t0).to_s.should == 'February 14, 2013' - end - - it 'should have a useful base to_s representation for a secondly rule' do - IceCube::Rule.secondly.to_s.should == 'Secondly' - IceCube::Rule.secondly(2).to_s.should == 'Every 2 seconds' - end - - it 'should have a useful base to_s representation for a minutely rule' do - IceCube::Rule.minutely.to_s.should == 'Minutely' - IceCube::Rule.minutely(2).to_s.should == 'Every 2 minutes' - end - - it 'should have a useful base to_s representation for a hourly rule' do - IceCube::Rule.hourly.to_s.should == 'Hourly' - IceCube::Rule.hourly(2).to_s.should == 'Every 2 hours' - end - - it 'should have a useful base to_s representation for a daily rule' do - IceCube::Rule.daily.to_s.should == 'Daily' - IceCube::Rule.daily(2).to_s.should == 'Every 2 days' - end - - it 'should have a useful base to_s representation for a weekly rule' do - IceCube::Rule.weekly.to_s.should == 'Weekly' - IceCube::Rule.weekly(2).to_s.should == 'Every 2 weeks' - end - - it 'should have a useful base to_s representation for a monthly rule' do - IceCube::Rule.monthly.to_s.should == 'Monthly' - IceCube::Rule.monthly(2).to_s.should == 'Every 2 months' - end - - it 'should have a useful base to_s representation for a yearly rule' do - IceCube::Rule.yearly.to_s.should == 'Yearly' - IceCube::Rule.yearly(2).to_s.should == 'Every 2 years' - end - - it 'should work with various sentence types properly' do - IceCube::Rule.weekly.to_s.should == 'Weekly' - IceCube::Rule.weekly.day(:monday).to_s.should == 'Weekly on Mondays' - IceCube::Rule.weekly.day(:monday, :tuesday).to_s.should == 'Weekly on Mondays and Tuesdays' - IceCube::Rule.weekly.day(:monday, :tuesday, :wednesday).to_s.should == 'Weekly on Mondays, Tuesdays, and Wednesdays' - end - - it 'should show saturday and sunday as weekends' do - IceCube::Rule.weekly.day(:saturday, :sunday).to_s.should == 'Weekly on Weekends' - end - - it 'should not show saturday and sunday as weekends when other days are present also' do - IceCube::Rule.weekly.day(:sunday, :monday, :saturday).to_s.should == - 'Weekly on Sundays, Mondays, and Saturdays' - end - - it 'should reorganize days to be in order' do - IceCube::Rule.weekly.day(:tuesday, :monday).to_s.should == - 'Weekly on Mondays and Tuesdays' - end - - it 'should show weekdays as such' do - IceCube::Rule.weekly.day( - :monday, :tuesday, :wednesday, - :thursday, :friday - ).to_s.should == 'Weekly on Weekdays' - end - - it 'should not show weekdays as such when a weekend day is present' do - IceCube::Rule.weekly.day( - :sunday, :monday, :tuesday, :wednesday, - :thursday, :friday - ).to_s.should == 'Weekly on Sundays, Mondays, Tuesdays, Wednesdays, Thursdays, and Fridays' - end - - it 'should show start time for an empty schedule' do - schedule = IceCube::Schedule.new Time.local(2010, 3, 20) - schedule.to_s.should == "March 20, 2010" - end - - it 'should work with a single date' do - schedule = IceCube::Schedule.new Time.local(2010, 3, 20) - schedule.add_recurrence_time Time.local(2010, 3, 20) - schedule.to_s.should == "March 20, 2010" - end - - it 'should work with additional dates' do - schedule = IceCube::Schedule.new Time.local(2010, 3, 20) - schedule.add_recurrence_time Time.local(2010, 3, 20) - schedule.add_recurrence_time Time.local(2010, 3, 21) - schedule.to_s.should == 'March 20, 2010 / March 21, 2010' - end - - it 'should order dates that are out of order' do - schedule = IceCube::Schedule.new Time.local(2010, 3, 20) - schedule.add_recurrence_time Time.local(2010, 3, 19) - schedule.to_s.should == 'March 19, 2010 / March 20, 2010' - end - - it 'should remove duplicated start time' do - schedule = IceCube::Schedule.new t0 = Time.local(2010, 3, 20) - schedule.add_recurrence_time t0 - schedule.to_s.should == 'March 20, 2010' - end - - it 'should remove duplicate rtimes' do - schedule = IceCube::Schedule.new Time.local(2010, 3, 19) - schedule.add_recurrence_time Time.local(2010, 3, 20) - schedule.add_recurrence_time Time.local(2010, 3, 20) - schedule.to_s.should == 'March 19, 2010 / March 20, 2010' - end - - it 'should work with rules and dates' do - schedule = IceCube::Schedule.new Time.local(2010, 3, 19) - schedule.add_recurrence_time Time.local(2010, 3, 20) - schedule.add_recurrence_rule IceCube::Rule.weekly - schedule.to_s.should == 'March 20, 2010 / Weekly' - end - - it 'should work with rules and times and exception times' do - schedule = IceCube::Schedule.new Time.local(2010, 3, 20) - schedule.add_recurrence_rule IceCube::Rule.weekly - schedule.add_recurrence_time Time.local(2010, 3, 20) - schedule.add_exception_time Time.local(2010, 3, 20) # ignored - schedule.add_exception_time Time.local(2010, 3, 21) - schedule.to_s.should == 'Weekly / not on March 20, 2010 / not on March 21, 2010' - end - - it 'should work with a single rrule' do - schedule = IceCube::Schedule.new Time.local(2010, 3, 20) - schedule.add_recurrence_rule IceCube::Rule.weekly.day_of_week(:monday => [1]) - schedule.to_s.should == schedule.rrules[0].to_s - end - - it 'should be able to say the last Thursday of the month' do - rule_str = IceCube::Rule.monthly.day_of_week(:thursday => [-1]).to_s - rule_str.should == 'Monthly on the last Thursday' - end - - it 'should be able to say what months of the year something happens' do - rule_str = IceCube::Rule.yearly.month_of_year(:june, :july).to_s - rule_str.should == 'Yearly in June and July' - end - - it 'should be able to say the second to last monday of the month' do - rule_str = IceCube::Rule.monthly.day_of_week(:thursday => [-2]).to_s - rule_str.should == 'Monthly on the 2nd to last Thursday' - end - - it 'should join the first and last weekdays of the month' do - rule_str = IceCube::Rule.monthly.day_of_week(:thursday => [1, -1]).to_s - rule_str.should == 'Monthly on the 1st Thursday and last Thursday' - end - - it 'should be able to say the days of the month something happens' do - rule_str = IceCube::Rule.monthly.day_of_month(1, 15, 30).to_s - rule_str.should == 'Monthly on the 1st, 15th, and 30th days of the month' - end - - it 'should be able to say what day of the year something happens' do - rule_str = IceCube::Rule.yearly.day_of_year(30).to_s - rule_str.should == 'Yearly on the 30th day of the year' - end - - it 'should be able to say what hour of the day something happens' do - rule_str = IceCube::Rule.daily.hour_of_day(6, 12).to_s - rule_str.should == 'Daily on the 6th and 12th hours of the day' - end - - it 'should be able to say what minute of an hour something happens - with special suffix minutes' do - rule_str = IceCube::Rule.hourly.minute_of_hour(10, 11, 12, 13, 14, 15).to_s - rule_str.should == 'Hourly on the 10th, 11th, 12th, 13th, 14th, and 15th minutes of the hour' - end - - it 'should be able to say what seconds of the minute something happens' do - rule_str = IceCube::Rule.minutely.second_of_minute(10, 11).to_s - rule_str.should == 'Minutely on the 10th and 11th seconds of the minute' - end - - it 'should be able to reflect until dates' do - schedule = IceCube::Schedule.new(Time.now) - schedule.rrule IceCube::Rule.weekly.until(Time.local(2012, 2, 3)) - schedule.to_s.should == 'Weekly until February 3, 2012' - end - - it 'should be able to reflect count' do - schedule = IceCube::Schedule.new(Time.now) - schedule.add_recurrence_rule IceCube::Rule.weekly.count(1) - schedule.to_s.should == 'Weekly 1 time' - end - - it 'should be able to reflect count (proper pluralization)' do - schedule = IceCube::Schedule.new(Time.now) - schedule.add_recurrence_rule IceCube::Rule.weekly.count(2) - schedule.to_s.should == 'Weekly 2 times' + shared_examples "to_s in English" do + + it 'should represent its start time by default' do + t0 = Time.local(2013, 2, 14) + IceCube::Schedule.new(t0).to_s.should == 'February 14, 2013' + end + + it 'should have a useful base to_s representation for a secondly rule' do + IceCube::Rule.secondly.to_s.should == 'Secondly' + IceCube::Rule.secondly(2).to_s.should == 'Every 2 seconds' + end + + it 'should have a useful base to_s representation for a minutely rule' do + IceCube::Rule.minutely.to_s.should == 'Minutely' + IceCube::Rule.minutely(2).to_s.should == 'Every 2 minutes' + end + + it 'should have a useful base to_s representation for a hourly rule' do + IceCube::Rule.hourly.to_s.should == 'Hourly' + IceCube::Rule.hourly(2).to_s.should == 'Every 2 hours' + end + + it 'should have a useful base to_s representation for a daily rule' do + IceCube::Rule.daily.to_s.should == 'Daily' + IceCube::Rule.daily(2).to_s.should == 'Every 2 days' + end + + it 'should have a useful base to_s representation for a weekly rule' do + IceCube::Rule.weekly.to_s.should == 'Weekly' + IceCube::Rule.weekly(2).to_s.should == 'Every 2 weeks' + end + + it 'should have a useful base to_s representation for a monthly rule' do + IceCube::Rule.monthly.to_s.should == 'Monthly' + IceCube::Rule.monthly(2).to_s.should == 'Every 2 months' + end + + it 'should have a useful base to_s representation for a yearly rule' do + IceCube::Rule.yearly.to_s.should == 'Yearly' + IceCube::Rule.yearly(2).to_s.should == 'Every 2 years' + end + + it 'should work with various sentence types properly' do + IceCube::Rule.weekly.to_s.should == 'Weekly' + IceCube::Rule.weekly.day(:monday).to_s.should == 'Weekly on Mondays' + IceCube::Rule.weekly.day(:monday, :tuesday).to_s.should == 'Weekly on Mondays and Tuesdays' + IceCube::Rule.weekly.day(:monday, :tuesday, :wednesday).to_s.should == 'Weekly on Mondays, Tuesdays, and Wednesdays' + end + + it 'should show saturday and sunday as weekends' do + IceCube::Rule.weekly.day(:saturday, :sunday).to_s.should == 'Weekly on Weekends' + end + + it 'should not show saturday and sunday as weekends when other days are present also' do + IceCube::Rule.weekly.day(:sunday, :monday, :saturday).to_s.should == + 'Weekly on Sundays, Mondays, and Saturdays' + end + + it 'should reorganize days to be in order' do + IceCube::Rule.weekly.day(:tuesday, :monday).to_s.should == + 'Weekly on Mondays and Tuesdays' + end + + it 'should show weekdays as such' do + IceCube::Rule.weekly.day( + :monday, :tuesday, :wednesday, + :thursday, :friday + ).to_s.should == 'Weekly on Weekdays' + end + + it 'should not show weekdays as such when a weekend day is present' do + IceCube::Rule.weekly.day( + :sunday, :monday, :tuesday, :wednesday, + :thursday, :friday + ).to_s.should == 'Weekly on Sundays, Mondays, Tuesdays, Wednesdays, Thursdays, and Fridays' + end + + it 'should show start time for an empty schedule' do + schedule = IceCube::Schedule.new Time.local(2010, 3, 20) + schedule.to_s.should == "March 20, 2010" + end + + it 'should work with a single date' do + schedule = IceCube::Schedule.new Time.local(2010, 3, 20) + schedule.add_recurrence_time Time.local(2010, 3, 20) + schedule.to_s.should == "March 20, 2010" + end + + it 'should work with additional dates' do + schedule = IceCube::Schedule.new Time.local(2010, 3, 20) + schedule.add_recurrence_time Time.local(2010, 3, 20) + schedule.add_recurrence_time Time.local(2010, 3, 21) + schedule.to_s.should == 'March 20, 2010 / March 21, 2010' + end + + it 'should order dates that are out of order' do + schedule = IceCube::Schedule.new Time.local(2010, 3, 20) + schedule.add_recurrence_time Time.local(2010, 3, 19) + schedule.to_s.should == 'March 19, 2010 / March 20, 2010' + end + + it 'should remove duplicated start time' do + schedule = IceCube::Schedule.new t0 = Time.local(2010, 3, 20) + schedule.add_recurrence_time t0 + schedule.to_s.should == 'March 20, 2010' + end + + it 'should remove duplicate rtimes' do + schedule = IceCube::Schedule.new Time.local(2010, 3, 19) + schedule.add_recurrence_time Time.local(2010, 3, 20) + schedule.add_recurrence_time Time.local(2010, 3, 20) + schedule.to_s.should == 'March 19, 2010 / March 20, 2010' + end + + it 'should work with rules and dates' do + schedule = IceCube::Schedule.new Time.local(2010, 3, 19) + schedule.add_recurrence_time Time.local(2010, 3, 20) + schedule.add_recurrence_rule IceCube::Rule.weekly + schedule.to_s.should == 'March 20, 2010 / Weekly' + end + + it 'should work with rules and times and exception times' do + schedule = IceCube::Schedule.new Time.local(2010, 3, 20) + schedule.add_recurrence_rule IceCube::Rule.weekly + schedule.add_recurrence_time Time.local(2010, 3, 20) + schedule.add_exception_time Time.local(2010, 3, 20) # ignored + schedule.add_exception_time Time.local(2010, 3, 21) + schedule.to_s.should == 'Weekly / not on March 20, 2010 / not on March 21, 2010' + end + + it 'should work with a single rrule' do + schedule = IceCube::Schedule.new Time.local(2010, 3, 20) + schedule.add_recurrence_rule IceCube::Rule.weekly.day_of_week(:monday => [1]) + schedule.to_s.should == schedule.rrules[0].to_s + end + + it 'should be able to say the last Thursday of the month' do + rule_str = IceCube::Rule.monthly.day_of_week(:thursday => [-1]).to_s + rule_str.should == 'Monthly on the last Thursday' + end + + it 'should be able to say what months of the year something happens' do + rule_str = IceCube::Rule.yearly.month_of_year(:june, :july).to_s + rule_str.should == 'Yearly in June and July' + end + + it 'should be able to say the second to last monday of the month' do + rule_str = IceCube::Rule.monthly.day_of_week(:thursday => [-2]).to_s + rule_str.should == 'Monthly on the 2nd to last Thursday' + end + + it 'should join the first and last weekdays of the month' do + rule_str = IceCube::Rule.monthly.day_of_week(:thursday => [1, -1]).to_s + rule_str.should == 'Monthly on the 1st Thursday and last Thursday' + end + + it 'should be able to say the days of the month something happens' do + rule_str = IceCube::Rule.monthly.day_of_month(1, 15, 30).to_s + rule_str.should == 'Monthly on the 1st, 15th, and 30th days of the month' + end + + it 'should be able to say what day of the year something happens' do + rule_str = IceCube::Rule.yearly.day_of_year(30).to_s + rule_str.should == 'Yearly on the 30th day of the year' + end + + it 'should be able to say what hour of the day something happens' do + rule_str = IceCube::Rule.daily.hour_of_day(6, 12).to_s + rule_str.should == 'Daily on the 6th and 12th hours of the day' + end + + it 'should be able to say what minute of an hour something happens - with special suffix minutes' do + rule_str = IceCube::Rule.hourly.minute_of_hour(10, 11, 12, 13, 14, 15).to_s + rule_str.should == 'Hourly on the 10th, 11th, 12th, 13th, 14th, and 15th minutes of the hour' + end + + it 'should be able to say what seconds of the minute something happens' do + rule_str = IceCube::Rule.minutely.second_of_minute(10, 11).to_s + rule_str.should == 'Minutely on the 10th and 11th seconds of the minute' + end + + it 'should be able to reflect until dates' do + schedule = IceCube::Schedule.new(Time.now) + schedule.rrule IceCube::Rule.weekly.until(Time.local(2012, 2, 3)) + schedule.to_s.should == 'Weekly until February 3, 2012' + end + + it 'should be able to reflect count' do + schedule = IceCube::Schedule.new(Time.now) + schedule.add_recurrence_rule IceCube::Rule.weekly.count(1) + schedule.to_s.should == 'Weekly 1 time' + end + + it 'should be able to reflect count (proper pluralization)' do + schedule = IceCube::Schedule.new(Time.now) + schedule.add_recurrence_rule IceCube::Rule.weekly.count(2) + schedule.to_s.should == 'Weekly 2 times' + end + + end + + context "without I18n" do + before { IceCube::I18n.stub(:backend) { IceCube::NullI18n } } + + it_behaves_like "to_s in English" + end + + context "with I18n" do + before(:each) { I18n.locale = :en } + + it "uses I18n" do + IceCube::I18n.backend.should == I18n + end + + it_behaves_like "to_s in English" end end From 6e7ea1293eb8f466efacf9e65be5035d3fa67332 Mon Sep 17 00:00:00 2001 From: John Crepezzi Date: Mon, 7 Dec 2015 15:07:58 -0500 Subject: [PATCH 15/26] Bump version to 0.13.1 --- CHANGELOG.md | 4 ++++ lib/ice_cube/version.rb | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1a7f6298..a66252b8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # Changelog +## 0.13.1 / 2015-12-07 + +* Added i18n support! + ## 0.13.0 / 2015-05-26 * [FEATURE] from_ical! diff --git a/lib/ice_cube/version.rb b/lib/ice_cube/version.rb index 95885de8..b121e993 100644 --- a/lib/ice_cube/version.rb +++ b/lib/ice_cube/version.rb @@ -1,5 +1,5 @@ module IceCube - VERSION = '0.13.0' + VERSION = '0.13.1' end From 995987709431120029bbda4d6daaadf8c0964ca3 Mon Sep 17 00:00:00 2001 From: John Crepezzi Date: Wed, 9 Dec 2015 09:57:26 -0500 Subject: [PATCH 16/26] Bump version to 0.13.2 --- ice_cube.gemspec | 2 +- lib/ice_cube/version.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ice_cube.gemspec b/ice_cube.gemspec index 6f89238d..195a6de6 100644 --- a/ice_cube.gemspec +++ b/ice_cube.gemspec @@ -11,7 +11,7 @@ Gem::Specification.new do |s| s.version = IceCube::VERSION s.platform = Gem::Platform::RUBY - s.files = Dir['lib/**/*.rb'] + s.files = Dir['lib/**/*.rb', 'config/**/*.yml'] s.test_files = Dir.glob('spec/*.rb') s.require_paths = ['lib'] s.has_rdoc = true diff --git a/lib/ice_cube/version.rb b/lib/ice_cube/version.rb index b121e993..6a350a92 100644 --- a/lib/ice_cube/version.rb +++ b/lib/ice_cube/version.rb @@ -1,5 +1,5 @@ module IceCube - VERSION = '0.13.1' + VERSION = '0.13.2' end From 401ded3195b82f3a091a03b3b7cd2d34fa363df7 Mon Sep 17 00:00:00 2001 From: Andrew Vit Date: Mon, 10 Nov 2014 14:07:05 -0800 Subject: [PATCH 17/26] Fix invalid references in isolated tests --- spec/examples/hourly_rule_spec.rb | 2 +- spec/examples/yearly_rule_spec.rb | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/spec/examples/hourly_rule_spec.rb b/spec/examples/hourly_rule_spec.rb index d0685585..854cf990 100644 --- a/spec/examples/hourly_rule_spec.rb +++ b/spec/examples/hourly_rule_spec.rb @@ -55,7 +55,7 @@ module IceCube schedule = double(start_time: t0 = Time.now) rule = Rule.hourly(7) rule.interval(5) - rule.next_time(t0 + 1, schedule, nil).should == t0 + 5.hours + rule.next_time(t0 + 1, schedule, nil).should == t0 + 5 * ONE_HOUR end it 'should produce the correct days for @interval = 3' do diff --git a/spec/examples/yearly_rule_spec.rb b/spec/examples/yearly_rule_spec.rb index d7cbcdb6..52438c83 100644 --- a/spec/examples/yearly_rule_spec.rb +++ b/spec/examples/yearly_rule_spec.rb @@ -2,12 +2,12 @@ describe IceCube::YearlyRule, 'interval validation' do it 'converts a string integer to an actual int when using the interval method' do - rule = Rule.yearly.interval("2") + rule = IceCube::Rule.yearly.interval("2") rule.validations_for(:interval).first.interval.should == 2 end it 'converts a string integer to an actual int when using the initializer' do - rule = Rule.yearly("3") + rule = IceCube::Rule.yearly("3") rule.validations_for(:interval).first.interval.should == 3 end From a965e5ad4b7cf7cf275774fa36fbdc53204c60a4 Mon Sep 17 00:00:00 2001 From: Andrew Vit Date: Mon, 19 Jan 2015 23:04:06 -0800 Subject: [PATCH 18/26] Optimize tight loop It seems true is no longer returned by any rule validation --- lib/ice_cube/validated_rule.rb | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/lib/ice_cube/validated_rule.rb b/lib/ice_cube/validated_rule.rb index c3ff916b..6dfae137 100644 --- a/lib/ice_cube/validated_rule.rb +++ b/lib/ice_cube/validated_rule.rb @@ -140,21 +140,19 @@ def find_acceptable_time_before(boundary) true end + # Returns true if all validations for the current rule match + # otherwise false and shifts to the first (largest) unmatched offset + # def validation_accepts_or_updates_time?(validations_for_type) - res = validated_results(validations_for_type) - return true if res.any? { |r| r.nil? || r == 0 } - return nil if res.all? { |r| r == true } - res.reject! { |r| r == true } + res = validations_for_type.each_with_object([]) do |validation, offsets| + r = validation.validate(@time, @schedule) + return true if r.nil? || r == 0 + offsets << r + end shift_time_by_validation(res, validations_for_type.first) false end - def validated_results(validations_for_type) - validations_for_type.map do |validation| - validation.validate(@time, @schedule) - end - end - def shift_time_by_validation(res, validation) return unless (interval = res.min) wrapper = TimeUtil::TimeWrapper.new(@time, validation.dst_adjust?) From 82d5da44682a25f2434e045ce02cdc56f25f4a5d Mon Sep 17 00:00:00 2001 From: Andrew Vit Date: Tue, 20 Jan 2015 00:50:35 -0800 Subject: [PATCH 19/26] Use appropriate iterators --- lib/ice_cube/time_util.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/ice_cube/time_util.rb b/lib/ice_cube/time_util.rb index 618c1b3d..bbb5bbb1 100644 --- a/lib/ice_cube/time_util.rb +++ b/lib/ice_cube/time_util.rb @@ -126,7 +126,7 @@ def self.end_of_date(date, reference=Time.now) # Convert a symbol to a numeric month def self.sym_to_month(sym) MONTHS.fetch(sym) do |k| - return wday = sym.to_i if MONTHS.values.any? { |i| i.to_s == sym.to_s } + MONTHS.values.detect { |i| i.to_s == k.to_s } or raise ArgumentError, "Expecting Fixnum or Symbol value for month. " \ "No such month: #{k.inspect}" end @@ -136,7 +136,7 @@ def self.sym_to_month(sym) # Convert a symbol to a wday number def self.sym_to_wday(sym) DAYS.fetch(sym) do |k| - return sym.to_i if DAYS.values.any? { |i| i.to_s == sym.to_s } + DAYS.values.detect { |i| i.to_s == k.to_s } or raise ArgumentError, "Expecting Fixnum or Symbol value for weekday. " \ "No such weekday: #{k.inspect}" end From c7985b007ed62cdfc75ec3cbe7a1274f7779bb8f Mon Sep 17 00:00:00 2001 From: Andrew Vit Date: Sat, 30 Jan 2016 17:56:44 -0800 Subject: [PATCH 20/26] Set default compatibility level to current version --- lib/ice_cube.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/ice_cube.rb b/lib/ice_cube.rb index fe03d9d5..cd1d4015 100644 --- a/lib/ice_cube.rb +++ b/lib/ice_cube.rb @@ -83,7 +83,7 @@ def self.to_s_time_format=(format) # Retain backwards compatibility for schedules exported from older versions # This represents the version number, 11 = 0.11, 1.0 will be 100 def self.compatibility - @compatibility ||= 11 + @compatibility ||= IceCube::VERSION.scan(/\d+/)[0..1].join.to_i end def self.compatibility=(version) From 145bd6040ab12876ccd56d12ce998bb32a20f3bc Mon Sep 17 00:00:00 2001 From: Andrew Vit Date: Sat, 30 Jan 2016 18:05:05 -0800 Subject: [PATCH 21/26] Bump version to 0.13.3 --- lib/ice_cube/version.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/ice_cube/version.rb b/lib/ice_cube/version.rb index 6a350a92..3d2fcbe9 100644 --- a/lib/ice_cube/version.rb +++ b/lib/ice_cube/version.rb @@ -1,5 +1,5 @@ module IceCube - VERSION = '0.13.2' + VERSION = '0.13.3' end From 508007e65c41b3e76b1eba84abebb5d0061b4a1d Mon Sep 17 00:00:00 2001 From: Dan Rice Date: Sat, 29 Aug 2015 16:43:24 -0400 Subject: [PATCH 22/26] Test on Ruby 2.2 --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 60d161b9..e11747f4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,3 +10,4 @@ rvm: - 1.9.3 - 2.0.0 - 2.1 + - 2.2 From 1d1848352985f43d1e6655261d8ff971d93d01d1 Mon Sep 17 00:00:00 2001 From: Dan Dimerman Date: Tue, 27 Oct 2015 17:54:59 +0200 Subject: [PATCH 23/26] fixed parsing of ical with multiple recurrence rules --- lib/ice_cube/parsers/ical_parser.rb | 3 ++- spec/examples/from_ical_spec.rb | 16 ++++++++++++++-- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/lib/ice_cube/parsers/ical_parser.rb b/lib/ice_cube/parsers/ical_parser.rb index 6729fca8..2e1e2f05 100644 --- a/lib/ice_cube/parsers/ical_parser.rb +++ b/lib/ice_cube/parsers/ical_parser.rb @@ -16,7 +16,8 @@ def self.schedule_from_ical(ical_string, options = {}) when 'DURATION' data[:duration] # FIXME when 'RRULE' - data[:rrules] = [rule_from_ical(value)] + data[:rrules] ||= [] + data[:rrules] += [rule_from_ical(value)] end end Schedule.from_hash data diff --git a/spec/examples/from_ical_spec.rb b/spec/examples/from_ical_spec.rb index 68d218ea..a46cb3f1 100644 --- a/spec/examples/from_ical_spec.rb +++ b/spec/examples/from_ical_spec.rb @@ -102,7 +102,7 @@ module IceCube RRULE:FREQ=WEEKLY;BYDAY=TH;UNTIL=20130531T100000Z ICAL - ical_string_woth_multiple_exdates = <<-ICAL.gsub(/^\s*/, '') + ical_string_with_multiple_exdates = <<-ICAL.gsub(/^\s*/, '') DTSTART;TZID=America/Denver:20130731T143000 DTEND;TZID=America/Denver:20130731T153000 RRULE:FREQ=WEEKLY;UNTIL=20140730T203000Z;BYDAY=MO,WE,FR @@ -111,6 +111,11 @@ module IceCube EXDATE;TZID=America/Denver:20130807T143000 ICAL + ical_string_with_multiple_rules = <<-ICAL.gsub(/^\s*/, '' ) + DTSTART;TZID=CDT:20151005T195541 + RRULE:FREQ=WEEKLY;BYDAY=MO,TU + RRULE:FREQ=WEEKLY;INTERVAL=2;WKST=SU;BYDAY=FR + ICAL def sorted_ical(ical) ical.split(/\n/).sort.map { |field| @@ -359,10 +364,17 @@ def sorted_ical(ical) end it 'handles multiple EXDATE lines' do - schedule = IceCube::Schedule.from_ical ical_string_woth_multiple_exdates + schedule = IceCube::Schedule.from_ical ical_string_with_multiple_exdates schedule.exception_times.count.should == 3 end end + + describe 'multiple rules' do + it 'handles multiple recurrence rules' do + schedule = IceCube::Schedule.from_ical ical_string_with_multiple_rules + schedule.recurrence_rules.count.should == 2 + end + end end end From 9742d42875d470af8c5278dd6e4b503ea67722c4 Mon Sep 17 00:00:00 2001 From: J Potts Date: Tue, 23 Feb 2016 11:49:32 +0000 Subject: [PATCH 24/26] Changing spans param to options hash Swapping the new spans parameter for an options hash to make the method calls more specific in their meaning. --- README.md | 10 ++++++---- lib/ice_cube/schedule.rb | 30 +++++++++++++++--------------- spec/examples/schedule_spec.rb | 18 +++++++++--------- 3 files changed, 30 insertions(+), 28 deletions(-) diff --git a/README.md b/README.md index 10f4008c..025f34ce 100644 --- a/README.md +++ b/README.md @@ -77,15 +77,17 @@ schedule.last(2) # [now + 1.day, now + 2.days] schedule.last # now + 2.days # or the next occurrence -schedule.next_occurrence(from_time) # defaults to Time.now -schedule.next_occurrences(3, from_time) # defaults to Time.now -schedule.next_occurrences(3, from_time, true) # include prior occurrences with duration overlapping from_time -schedule.remaining_occurrences # for terminating schedules +schedule.next_occurrence(from_time) # defaults to Time.now +schedule.next_occurrences(3, from_time) # defaults to Time.now +schedule.remaining_occurrences # for terminating schedules # or the previous occurrence schedule.previous_occurrence(from_time) schedule.previous_occurrences(3, from_time) +# or include prior occurrences with a duration overlapping from_time +schedule.next_occurrences(3, from_time, :spans => true) +schedule.occurrences_between(from_time, to_time, :spans => true) # or give the schedule a duration and ask if occurring_at? schedule = IceCube::Schedule.new(now, :duration => 3600) diff --git a/lib/ice_cube/schedule.rb b/lib/ice_cube/schedule.rb index 7e837b38..0367879f 100644 --- a/lib/ice_cube/schedule.rb +++ b/lib/ice_cube/schedule.rb @@ -166,15 +166,15 @@ def each_occurrence(&block) end # The next n occurrences after now - def next_occurrences(num, from = nil, spans = false) + def next_occurrences(num, from = nil, options = {}) from = TimeUtil.match_zone(from, start_time) || TimeUtil.now(start_time) - enumerate_occurrences(from + 1, nil, spans).take(num) + enumerate_occurrences(from + 1, nil, options).take(num) end # The next occurrence after now (overridable) - def next_occurrence(from = nil, spans = false) + def next_occurrence(from = nil, options = {}) from = TimeUtil.match_zone(from, start_time) || TimeUtil.now(start_time) - enumerate_occurrences(from + 1, nil, spans).next + enumerate_occurrences(from + 1, nil, options).next rescue StopIteration nil end @@ -195,26 +195,26 @@ def previous_occurrences(num, from) end # The remaining occurrences (same requirements as all_occurrences) - def remaining_occurrences(from = nil, spans = false) + def remaining_occurrences(from = nil, options = {}) require_terminating_rules from ||= TimeUtil.now(@start_time) - enumerate_occurrences(from, nil, spans).to_a + enumerate_occurrences(from, nil, options).to_a end # Returns an enumerator for all remaining occurrences - def remaining_occurrences_enumerator(from = nil, spans = false) + def remaining_occurrences_enumerator(from = nil, options = {}) from ||= TimeUtil.now(@start_time) - enumerate_occurrences(from, nil, spans) + enumerate_occurrences(from, nil, options) end # Occurrences between two times - def occurrences_between(begin_time, closing_time, spans = false) - enumerate_occurrences(begin_time, closing_time, spans).to_a + def occurrences_between(begin_time, closing_time, options = {}) + enumerate_occurrences(begin_time, closing_time, options).to_a end # Return a boolean indicating if an occurrence falls between two times - def occurs_between?(begin_time, closing_time, spans = false) - enumerate_occurrences(begin_time, closing_time, spans).next + def occurs_between?(begin_time, closing_time, options = {}) + enumerate_occurrences(begin_time, closing_time, options).next true rescue StopIteration false @@ -226,7 +226,7 @@ def occurs_between?(begin_time, closing_time, spans = false) # occurrences at the end of the range since none of their duration # intersects the range. def occurring_between?(opening_time, closing_time) - occurs_between?(opening_time, closing_time, true) + occurs_between?(opening_time, closing_time, :spans => true) end # Return a boolean indicating if an occurrence falls on a certain date @@ -402,12 +402,12 @@ def reset # Find all of the occurrences for the schedule between opening_time # and closing_time # Iteration is unrolled in pairs to skip duplicate times in end of DST - def enumerate_occurrences(opening_time, closing_time = nil, spans = false, &block) + def enumerate_occurrences(opening_time, closing_time = nil, options = {}, &block) opening_time = TimeUtil.match_zone(opening_time, start_time) closing_time = TimeUtil.match_zone(closing_time, start_time) opening_time += start_time.subsec - opening_time.subsec rescue 0 opening_time = start_time if opening_time < start_time - spans = false if duration == 0 + spans = options[:spans] == true && duration != 0 Enumerator.new do |yielder| reset t1 = full_required? ? start_time : realign((spans ? opening_time - duration : opening_time)) diff --git a/spec/examples/schedule_spec.rb b/spec/examples/schedule_spec.rb index c5fe023c..0add833d 100644 --- a/spec/examples/schedule_spec.rb +++ b/spec/examples/schedule_spec.rb @@ -458,7 +458,7 @@ t0 = Time.utc(2015, 10, 1, 15, 31) schedule = IceCube::Schedule.new(t0, :duration => 2 * IceCube::ONE_HOUR) schedule.add_recurrence_rule IceCube::Rule.daily - next_occ = schedule.next_occurrence(t0 + IceCube::ONE_HOUR, true) + next_occ = schedule.next_occurrence(t0 + IceCube::ONE_HOUR, :spans => true) next_occ.should == t0 end @@ -466,7 +466,7 @@ t0 = Time.utc(2015, 10, 1, 15, 31) schedule = IceCube::Schedule.new(t0, :duration => 2 * IceCube::ONE_HOUR) schedule.add_recurrence_rule IceCube::Rule.daily.count(2) - occs = schedule.next_occurrences(10, t0 + IceCube::ONE_HOUR, true) + occs = schedule.next_occurrences(10, t0 + IceCube::ONE_HOUR, :spans => true) occs.should == [t0, t0 + IceCube::ONE_DAY] end @@ -474,14 +474,14 @@ t0 = Time.utc(2015, 10, 1, 00, 00) schedule = IceCube::Schedule.new(t0, :duration => IceCube::ONE_DAY) schedule.add_recurrence_rule IceCube::Rule.daily.count(3) - occs = schedule.remaining_occurrences(t0 + IceCube::ONE_DAY + IceCube::ONE_HOUR, true) + occs = schedule.remaining_occurrences(t0 + IceCube::ONE_DAY + IceCube::ONE_HOUR, :spans => true) occs.should == [t0 + IceCube::ONE_DAY, t0 + 2 * IceCube::ONE_DAY] end it 'should include occurrences with duration spanning the requested start time' do t0 = Time.utc(2015, 10, 1, 15, 31) schedule = IceCube::Schedule.new(t0, :duration => 30 * IceCube::ONE_DAY) - long_event = schedule.remaining_occurrences_enumerator(t0 + IceCube::ONE_DAY, true).take(1) + long_event = schedule.remaining_occurrences_enumerator(t0 + IceCube::ONE_DAY, :spans => true).take(1) long_event.should == [t0] end @@ -489,21 +489,21 @@ t0 = Time.utc(2015, 10, 1, 10, 00) schedule = IceCube::Schedule.new(t0, :duration => IceCube::ONE_HOUR) schedule.add_recurrence_rule IceCube::Rule.hourly.count(10) - occs = schedule.occurrences_between(t0 + IceCube::ONE_HOUR + 1, t0 + 3 * IceCube::ONE_HOUR + 1, true) + occs = schedule.occurrences_between(t0 + IceCube::ONE_HOUR + 1, t0 + 3 * IceCube::ONE_HOUR + 1, :spans => true) occs.length.should == 3 end it 'should include long occurrences starting before and ending after' do t0 = Time.utc(2015, 10, 1, 00, 00) schedule = IceCube::Schedule.new(t0, :duration => IceCube::ONE_DAY) - occs = schedule.occurrences_between(t0 + IceCube::ONE_HOUR, t0 + IceCube::ONE_DAY - IceCube::ONE_HOUR, true) + occs = schedule.occurrences_between(t0 + IceCube::ONE_HOUR, t0 + IceCube::ONE_DAY - IceCube::ONE_HOUR, :spans => true) occs.should == [t0] end it 'should not find occurrence with duration ending on start time' do t0 = Time.utc(2015, 10, 1, 12, 00) schedule = IceCube::Schedule.new(t0, :duration => IceCube::ONE_HOUR) - schedule.occurs_between?(t0 + IceCube::ONE_HOUR, t0 + 2 * IceCube::ONE_HOUR, true).should be_false + schedule.occurs_between?(t0 + IceCube::ONE_HOUR, t0 + 2 * IceCube::ONE_HOUR, :spans => true).should be_false end it 'should quickly fetch a future time from a recurring schedule' do @@ -513,7 +513,7 @@ schedule.add_recurrence_rule IceCube::Rule.hourly occ = nil timing = Benchmark.realtime do - occ = schedule.remaining_occurrences_enumerator(t1, true).take(1) + occ = schedule.remaining_occurrences_enumerator(t1, :spans => true).take(1) end timing.should < 0.1 occ.should == [t1] @@ -523,7 +523,7 @@ t0 = Time.utc(2015, 10, 1, 10, 00) schedule = IceCube::Schedule.new(t0, :duration => IceCube::ONE_HOUR / 2) schedule.add_recurrence_rule IceCube::Rule.minutely(30).count(6) - third_occ = schedule.next_occurrence(t0 + IceCube::ONE_HOUR, true) + third_occ = schedule.next_occurrence(t0 + IceCube::ONE_HOUR, :spans => true) third_occ.should == t0 + IceCube::ONE_HOUR end From db9fa648c3803abd0605cdf07168318515cbec8f Mon Sep 17 00:00:00 2001 From: John Crepezzi Date: Tue, 23 Feb 2016 13:15:00 +0100 Subject: [PATCH 25/26] Updated version --- CHANGELOG.md | 4 ++++ lib/ice_cube/version.rb | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a66252b8..3e2b503b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # Changelog +## 0.14.0 / 2016-02-23 + +* Added span option for occurrence methods + ## 0.13.1 / 2015-12-07 * Added i18n support! diff --git a/lib/ice_cube/version.rb b/lib/ice_cube/version.rb index 3d2fcbe9..9c59ceea 100644 --- a/lib/ice_cube/version.rb +++ b/lib/ice_cube/version.rb @@ -1,5 +1,5 @@ module IceCube - VERSION = '0.13.3' + VERSION = '0.14.0' end From 42c5d27bca497d10a77d3e484370c46e05b7ef58 Mon Sep 17 00:00:00 2001 From: John Crepezzi Date: Tue, 23 Feb 2016 13:26:30 +0100 Subject: [PATCH 26/26] Fix travis build --- .travis.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.travis.yml b/.travis.yml index e11747f4..e7c40249 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,4 +1,6 @@ script: "bundle exec rspec spec" +before_install: + - gem install bundler notifications: email: - john.crepezzi@gmail.com