zmanim 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +11 -0
  3. data/.rspec +1 -0
  4. data/Gemfile +6 -0
  5. data/LICENSE +504 -0
  6. data/README.md +124 -0
  7. data/Rakefile +2 -0
  8. data/bin/console +14 -0
  9. data/bin/setup +8 -0
  10. data/lib/zmanim.rb +6 -0
  11. data/lib/zmanim/astronomical_calendar.rb +105 -0
  12. data/lib/zmanim/hebrew_calendar/hebrew_date_formatter.rb +243 -0
  13. data/lib/zmanim/hebrew_calendar/jewish_calendar.rb +390 -0
  14. data/lib/zmanim/hebrew_calendar/jewish_date.rb +397 -0
  15. data/lib/zmanim/limudim/anchor/day_of_month_anchor.rb +49 -0
  16. data/lib/zmanim/limudim/anchor/day_of_week_anchor.rb +26 -0
  17. data/lib/zmanim/limudim/anchor/day_of_year_anchor.rb +27 -0
  18. data/lib/zmanim/limudim/calculators/daf_yomi_bavli.rb +53 -0
  19. data/lib/zmanim/limudim/calculators/daf_yomi_yerushalmi.rb +58 -0
  20. data/lib/zmanim/limudim/calculators/mishna_yomis.rb +48 -0
  21. data/lib/zmanim/limudim/calculators/parsha.rb +91 -0
  22. data/lib/zmanim/limudim/calculators/tehillim_monthly.rb +43 -0
  23. data/lib/zmanim/limudim/cycle.rb +40 -0
  24. data/lib/zmanim/limudim/interval.rb +37 -0
  25. data/lib/zmanim/limudim/limud.rb +42 -0
  26. data/lib/zmanim/limudim/limud_calculator.rb +137 -0
  27. data/lib/zmanim/limudim/limudim_formatter.rb +168 -0
  28. data/lib/zmanim/limudim/unit.rb +53 -0
  29. data/lib/zmanim/util/astronomical_calculations.rb +34 -0
  30. data/lib/zmanim/util/geo_location.rb +116 -0
  31. data/lib/zmanim/util/hebrew_numeric_formatter.rb +67 -0
  32. data/lib/zmanim/util/math_helper.rb +14 -0
  33. data/lib/zmanim/util/noaa_calculator.rb +180 -0
  34. data/lib/zmanim/util/sun_times_calculator.rb +123 -0
  35. data/lib/zmanim/util/text_helper.rb +7 -0
  36. data/lib/zmanim/util/time_zone_converter.rb +20 -0
  37. data/lib/zmanim/version.rb +3 -0
  38. data/lib/zmanim/zmanim_calendar.rb +106 -0
  39. data/zmanim.gemspec +37 -0
  40. metadata +153 -0
@@ -0,0 +1,49 @@
1
+ module Zmanim::Limudim::Anchor
2
+ class DayOfMonthAnchor
3
+ attr_reader :day
4
+ def initialize(day)
5
+ @day = day
6
+ end
7
+
8
+ def next_occurrence(jewish_date)
9
+ occurrence = Zmanim::HebrewCalendar::JewishDate.new(jewish_date.jewish_year, jewish_date.jewish_month, day)
10
+ increment_month(occurrence) if occurrence <= jewish_date
11
+ occurrence
12
+ end
13
+
14
+ def previous_occurrence(jewish_date)
15
+ occurrence = Zmanim::HebrewCalendar::JewishDate.new(jewish_date.jewish_year, jewish_date.jewish_month, day)
16
+ decrement_month(occurrence) if occurrence >= jewish_date
17
+ occurrence
18
+ end
19
+
20
+ def current_or_previous_occurrence(jewish_date)
21
+ occurrence = Zmanim::HebrewCalendar::JewishDate.new(jewish_date.jewish_year, jewish_date.jewish_month, day)
22
+ decrement_month(occurrence) if occurrence > jewish_date
23
+ occurrence
24
+ end
25
+
26
+ private
27
+
28
+ def increment_month(jewish_date)
29
+ if jewish_date.jewish_month == jewish_date.months_in_jewish_year
30
+ jewish_date.jewish_month = 1
31
+ elsif jewish_date.jewish_month == 6
32
+ jewish_date.forward!(29)
33
+ else
34
+ jewish_date.jewish_month += 1
35
+ end
36
+ end
37
+
38
+ def decrement_month(jewish_date)
39
+ if jewish_date.jewish_month == 1
40
+ jewish_date.jewish_month = jewish_date.months_in_jewish_year
41
+ elsif jewish_date.jewish_month == 7
42
+ back_days = jewish_date.jewish_day == 30 ? 30 : 29
43
+ jewish_date.back!(back_days)
44
+ else
45
+ jewish_date.jewish_month -= 1
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,26 @@
1
+ module Zmanim::Limudim::Anchor
2
+ class DayOfWeekAnchor
3
+ attr_reader :day_of_week
4
+ def initialize(day_of_week)
5
+ @day_of_week = day_of_week
6
+ end
7
+
8
+ def next_occurrence(date)
9
+ offset = day_of_week - date.day_of_week
10
+ offset += 7 if offset <= 0
11
+ date + offset
12
+ end
13
+
14
+ def previous_occurrence(date)
15
+ offset = day_of_week - date.day_of_week
16
+ offset -= 7 if offset >= 0
17
+ date + offset
18
+ end
19
+
20
+ def current_or_previous_occurrence(date)
21
+ offset = day_of_week - date.day_of_week
22
+ offset -= 7 if offset > 0
23
+ date + offset
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,27 @@
1
+ module Zmanim::Limudim::Anchor
2
+ class DayOfYearAnchor
3
+ attr_reader :month, :day
4
+ def initialize(month, day)
5
+ @month = month
6
+ @day = day
7
+ end
8
+
9
+ def next_occurrence(jewish_date)
10
+ occurrence = Zmanim::HebrewCalendar::JewishDate.new(jewish_date.jewish_year, month, day)
11
+ occurrence.jewish_year += 1 if occurrence <= jewish_date
12
+ occurrence
13
+ end
14
+
15
+ def previous_occurrence(jewish_date)
16
+ occurrence = Zmanim::HebrewCalendar::JewishDate.new(jewish_date.jewish_year, month, day)
17
+ occurrence.jewish_year -= 1 if occurrence >= jewish_date
18
+ occurrence
19
+ end
20
+
21
+ def current_or_previous_occurrence(jewish_date)
22
+ occurrence = Zmanim::HebrewCalendar::JewishDate.new(jewish_date.jewish_year, month, day)
23
+ occurrence.jewish_year -= 1 if occurrence > jewish_date
24
+ occurrence
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,53 @@
1
+ require 'zmanim/limudim/limud_calculator'
2
+
3
+ module Zmanim::Limudim::Calculators
4
+ class DafYomiBavli
5
+ include Zmanim::Limudim::LimudCalculator
6
+
7
+ def initial_cycle_date
8
+ jewish_date(Date.parse('1923-09-11'))
9
+ end
10
+
11
+ def default_starting_page
12
+ 2
13
+ end
14
+
15
+ def starting_page(units, unit_name)
16
+ case units.keys.index(unit_name.to_sym)
17
+ when 36
18
+ 23
19
+ when 37
20
+ 26
21
+ when 38
22
+ 34
23
+ else
24
+ default_starting_page
25
+ end
26
+ end
27
+
28
+ def default_units
29
+ { berachos: 64, shabbos: 157, eruvin: 105, pesachim: 121, shekalim: 22, yoma: 88, sukkah: 56, beitzah: 40, rosh_hashanah: 35,
30
+ taanis: 31, megillah: 32, moed_katan: 29, chagigah: 27, yevamos: 122, kesubos: 112, nedarim: 91, nazir: 66, sotah: 49,
31
+ gitin: 90, kiddushin: 82, bava_kamma: 119, bava_metzia: 119, bava_basra: 176, sanhedrin: 113, makkos: 24, shevuos: 49,
32
+ avodah_zarah: 76, horiyos: 14, zevachim: 120, menachos: 110, chullin: 142, bechoros: 61, arachin: 34, temurah: 34,
33
+ kerisos: 28, meilah: 22, kinnim: 25, tamid: 33, midos: 37, niddah: 73 }
34
+ end
35
+
36
+ def cycle_end_calculation
37
+ ->(start_date, iteration) do
38
+ duration = iteration < 8 ? 2702 : 2711
39
+ start_date + (duration - 1)
40
+ end
41
+ end
42
+
43
+ def cycle_units_calculation
44
+ ->(cycle) do
45
+ if cycle.iteration < 8
46
+ default_units.merge(shekalim: 13)
47
+ else
48
+ default_units
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,58 @@
1
+ require 'zmanim/limudim/limud_calculator'
2
+
3
+ module Zmanim::Limudim::Calculators
4
+ class DafYomiYerushalmi
5
+ include Zmanim::Limudim::LimudCalculator
6
+
7
+ def initial_cycle_date
8
+ jewish_date(Date.parse('1980-02-02'))
9
+ end
10
+
11
+ def default_units
12
+ { berachos: 68, peah: 37, demai: 34, kilayim: 44, shviis: 31, terumos: 59, maasros: 26, maaser_sheni: 33,
13
+ chalah: 28, orlah: 20, bikurim: 13, shabbos: 92, eruvin: 65, pesachim: 71, beitzah: 22, rosh_hashanah: 22,
14
+ yoma: 42, sukkah: 26, taanis: 26, shekalim: 33, megilah: 34, chagigah: 22, moed_katan: 19, yevamos: 85,
15
+ kesubos: 72, sotah: 47, nedarim: 40, nazir: 47, gitin: 54, kiddushin: 48, bava_kama: 44, bava_metzia: 37,
16
+ bava_basra: 34, sanhedrin: 44, makos: 9, shevuos: 57, avodah_zarah: 37, horayos: 19, niddah: 13 }
17
+ end
18
+
19
+ def cycle_end_calculation
20
+ ->(start_date, iteration) do
21
+ end_date = start_date + (1554 - 1)
22
+ found_skips_between = ->(a, b) do
23
+ (a.jewish_year..b.jewish_year).sum do |year|
24
+ skip_days.count do |m, d|
25
+ Zmanim::HebrewCalendar::JewishDate.new(year, m, d).between?(a,b)
26
+ end
27
+ end
28
+ end
29
+ while (found_days = found_skips_between.(start_date, end_date)) > 0 do
30
+ start_date, end_date = end_date + 1, end_date + found_days
31
+ end
32
+ end_date
33
+ end
34
+ end
35
+
36
+ def unit_for_interval(units, interval)
37
+ if matches_skip_day?(interval.start_date)
38
+ Zmanim::Limudim::Unit.new('no_daf_today')
39
+ else
40
+ super
41
+ end
42
+ end
43
+
44
+ def skip_interval?(interval)
45
+ matches_skip_day?(interval.start_date)
46
+ end
47
+
48
+ private
49
+
50
+ def matches_skip_day?(date)
51
+ skip_days.any?{|m, d| date.jewish_month == m && date.jewish_day == d}
52
+ end
53
+
54
+ def skip_days
55
+ [[5, 9], [7, 10]]
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,48 @@
1
+ require 'zmanim/limudim/limud_calculator'
2
+
3
+ module Zmanim::Limudim::Calculators
4
+ class MishnaYomis
5
+ include Zmanim::Limudim::LimudCalculator
6
+
7
+ def initial_cycle_date
8
+ jewish_date(Date.parse('1947-05-20'))
9
+ end
10
+
11
+ def unit_step
12
+ 2
13
+ end
14
+
15
+ # formatted as `{maseches => {perek => mishna_count, ...}, ... }`
16
+ def default_units
17
+ self.class.default_units
18
+ end
19
+
20
+ def cycle_end_calculation
21
+ ->(start_date, iteration) do
22
+ start_date + ((4192/2) - 1)
23
+ end
24
+ end
25
+
26
+ def self.default_units
27
+ @default_units ||= Hash[
28
+ { berachos: [5,8,6,7,5,8,5,8,5], peah: [6,8,8,11,8,11,8,9], demai: [4,5,6,7,11,12,8], kilayim: [9,11,7,9,8,9,8,6,10],
29
+ sheviis: [8,10,10,10,9,6,7,11,9,9], terumos: [10,6,9,13,9,6,7,12,7,12,10], maasros: [8,8,10,6,8], maaser_sheni: [7,10,13,12,15],
30
+ chalah: [9,8,10,11], orlah: [9,17,9], bikurim: [11,11,12,5], shabbos: [11,7,6,2,4,10,4,7,7,6,6,6,7,4,3,8,8,3,6,5,3,6,5,5],
31
+ eruvin: [10,6,9,11,9,10,11,11,4,15], pesachim: [7,8,8,9,10,6,13,8,11,9], shekalim: [7,5,4,9,6,6,7,8], yoma: [8,7,11,6,7,8,5,9],
32
+ sukkah: [11,9,15,10,8], beitzah: [10,10,8,7,7], rosh_hashanah: [9,8,9,9], taanis: [7,10,9,8], megillah: [11,6,6,10],
33
+ moed_katan: [10,5,9], chagigah: [8,7,8], yevamos: [4,10,10,13,6,6,6,6,6,9,7,6,13,9,10,7], kesubos: [10,10,9,12,9,7,10,8,9,6,6,4,11],
34
+ nedarim: [4,5,11,8,6,10,9,7,10,8,12], nazir: [7,10,7,7,7,11,4,2,5], sotah: [9,6,8,5,5,4,8,7,15], gitin: [6,7,8,9,9,7,9,10,10],
35
+ kiddushin: [10,10,13,14], bava_kamma: [4,6,11,9,7,6,7,7,12,10], bava_metzia: [8,11,12,12,11,8,11,9,13,6],
36
+ bava_basra: [6,14,8,9,11,8,4,8,10,8], sanhedrin: [6,5,8,5,5,6,11,7,6,6,6], makkos: [10,8,16], shevuos: [7,5,11,13,5,7,8,6],
37
+ eduyos: [14,10,12,12,7,3,9,7], avodah_zarah: [9,7,10,12,12], avos: [18,16,18,22,23,11], horiyos: [5,7,8],
38
+ zevachim: [4,5,6,6,8,7,6,12,7,8,8,6,8,10], menachos: [4,5,7,5,9,7,6,7,9,9,9,5,11], chullin: [7,10,7,7,5,7,6,6,8,4,2,5],
39
+ bechoros: [7,9,4,10,6,12,7,10,8], arachin: [4,6,5,4,6,5,5,7,8], temurah: [6,3,5,4,6,5,6], kerisos: [7,6,10,3,8,9],
40
+ meilah: [4,9,8,6,5,6], tamid: [4,5,9,3,6,4,3], midos: [9,6,8,7,4], kinnim: [4,5,6],
41
+ keilim: [9,8,8,4,11,4,6,11,8,8,9,8,8,8,6,8,17,9,10,7,3,10,5,17,9,9,12,10,8,4], ohalos: [8,7,7,3,7,7,6,6,16,7,9,8,6,7,10,5,5,10],
42
+ negaim: [6,5,8,11,5,8,5,10,3,10,12,7,12,13], parah: [4,5,11,4,9,5,12,11,9,6,9,11], taharos: [9,8,8,13,9,10,9,9,9,8],
43
+ mikvaos: [8,10,4,5,6,11,7,5,7,8], niddah: [7,7,7,7,9,14,5,4,11,8], machshirim: [6,11,8,10,11,8], zavim: [6,4,3,7,12],
44
+ tevul_yom: [5,8,6,7], yadayim: [5,4,5,8], uktzin: [6,10,12]
45
+ }.map{|k, v| [k, Hash[v.map.with_index{|m, p| [p+1, m]}]]}]
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,91 @@
1
+ require 'zmanim/limudim/limud_calculator'
2
+
3
+ module Zmanim::Limudim::Calculators
4
+ class Parsha
5
+ include Zmanim::Limudim::LimudCalculator
6
+
7
+ attr_reader :in_israel
8
+
9
+ def initialize(in_israel:false)
10
+ @in_israel = in_israel
11
+ end
12
+
13
+ def tiered_units?
14
+ false
15
+ end
16
+
17
+ def perpetual_cycle_anchor
18
+ Zmanim::Limudim::Anchor::DayOfYearAnchor.new(7, in_israel ? 23 : 24)
19
+ end
20
+
21
+ def default_units
22
+ %i(bereishis noach lech_lecha vayeira chayei_sarah toldos vayeitzei vayishlach vayeishev mikeitz vayigash vayechi
23
+ shemos vaeirah bo beshalach yisro mishpatim terumah tetzaveh ki_sisa vayakheil pekudei
24
+ vayikra tzav shemini tazria metzora acharei kedoshim emor behar bechukosai
25
+ bamidbar naso behaalosecha shelach korach chukas balak pinchas matos masei
26
+ devarim vaeschanan eikev reei shoftim ki_seitzei ki_savo nitzavim vayeilech haazinu vezos_haberacha)
27
+ end
28
+
29
+ def cycle_end_calculation
30
+ ->(start_date, iteration) do
31
+ perpetual_cycle_anchor.next_occurrence(start_date) - 1
32
+ end
33
+ end
34
+
35
+ def interval_end_calculation
36
+ ->(cycle, start_date) do
37
+ skips = in_israel ?
38
+ [[1, (15..21)], [3, [6]], [7, [1,2,10] + (15..21).to_a]] :
39
+ [[1, (15..22)], [3, [6,7]], [7, [1,2,10] + (15..22).to_a]]
40
+ end_date = start_date + (7 - start_date.day_of_week)
41
+ while skips.detect{|month, days| month == end_date.jewish_month && days.include?(end_date.jewish_day) } do
42
+ end_date += 7
43
+ end
44
+ end_date > cycle.end_date ? cycle.end_date : end_date
45
+ end
46
+ end
47
+
48
+ def cycle_units_calculation
49
+ ->(cycle) do
50
+ kviah = Zmanim::HebrewCalendar::HebrewDateFormatter.new.format_kviah(cycle.start_date.jewish_year)
51
+ modifications = in_israel ?
52
+ {
53
+ 'בחה' => [%i(matos masei), %i(nitzavim vayeilech)],
54
+ 'בשז' => [],
55
+ 'גכז' => [],
56
+ 'החא' => [],
57
+ 'השג' => [%i(nitzavim vayeilech)],
58
+ 'זחג' => [%i(matos masei), %i(nitzavim vayeilech)],
59
+ 'זשה' => [%i(matos masei), %i(nitzavim vayeilech)],
60
+ 'בחג' => [%i(vayakheil pikudei), %i(tazria metzora), %i(acharei kedoshim), %i(behar bechukosai), %i(matos masei), %i(nitzavim vayeilech)],
61
+ 'בשה' => [%i(vayakheil pikudei), %i(tazria metzora), %i(acharei kedoshim), %i(behar bechukosai), %i(matos masei), %i(nitzavim vayeilech)],
62
+ 'גכה' => [%i(vayakheil pikudei), %i(tazria metzora), %i(acharei kedoshim), %i(behar bechukosai), %i(matos masei), %i(nitzavim vayeilech)],
63
+ 'הכז' => [%i(vayakheil pikudei), %i(tazria metzora), %i(acharei kedoshim), %i(matos masei)],
64
+ 'השא' => [%i(tazria metzora), %i(acharei kedoshim), %i(behar bechukosai), %i(matos masei)],
65
+ 'זחא' => [%i(vayakheil pikudei), %i(tazria metzora), %i(acharei kedoshim), %i(behar bechukosai), %i(matos masei)],
66
+ 'זשג' => [%i(vayakheil pikudei), %i(tazria metzora), %i(acharei kedoshim), %i(behar bechukosai), %i(matos masei)],
67
+ }[kviah] :
68
+ {
69
+ 'בחה' => [%i(chukas balak), %i(matos masei), %i(nitzavim vayeilech)],
70
+ 'בשז' => [%i(matos masei)],
71
+ 'גכז' => [%i(matos masei)],
72
+ 'החא' => [],
73
+ 'השג' => [%i(nitzavim vayeilech)],
74
+ 'זחג' => [%i(matos masei), %i(nitzavim vayeilech)],
75
+ 'זשה' => [%i(chukas balak), %i(matos masei), %i(nitzavim vayeilech)],
76
+ 'בחג' => [%i(vayakheil pikudei), %i(tazria metzora), %i(acharei kedoshim), %i(behar bechukosai), %i(matos masei), %i(nitzavim vayeilech)],
77
+ 'בשה' => [%i(vayakheil pikudei), %i(tazria metzora), %i(acharei kedoshim), %i(behar bechukosai), %i(chukas balak), %i(matos masei), %i(nitzavim vayeilech)],
78
+ 'גכה' => [%i(vayakheil pikudei), %i(tazria metzora), %i(acharei kedoshim), %i(behar bechukosai), %i(chukas balak), %i(matos masei), %i(nitzavim vayeilech)],
79
+ 'הכז' => [%i(vayakheil pikudei), %i(tazria metzora), %i(acharei kedoshim), %i(behar bechukosai), %i(matos masei)],
80
+ 'השא' => [%i(tazria metzora), %i(acharei kedoshim), %i(behar bechukosai), %i(matos masei)],
81
+ 'זחא' => [%i(vayakheil pikudei), %i(tazria metzora), %i(acharei kedoshim), %i(behar bechukosai), %i(matos masei)],
82
+ 'זשג' => [%i(vayakheil pikudei), %i(tazria metzora), %i(acharei kedoshim), %i(behar bechukosai), %i(matos masei), %i(nitzavim vayeilech)],
83
+ }[kviah]
84
+ modifications.inject(default_units) do |transitioned_units, parsha_pair|
85
+ index = transitioned_units.index(parsha_pair.first)
86
+ transitioned_units[0...index] + [parsha_pair] + transitioned_units[(index + 2)..-1]
87
+ end
88
+ end
89
+ end
90
+ end
91
+ end
@@ -0,0 +1,43 @@
1
+ require 'zmanim/limudim/limud_calculator'
2
+
3
+ module Zmanim::Limudim::Calculators
4
+ class TehillimMonthly
5
+ include Zmanim::Limudim::LimudCalculator
6
+
7
+ def tiered_units?
8
+ false
9
+ end
10
+
11
+ def perpetual_cycle_anchor
12
+ Zmanim::Limudim::Anchor::DayOfMonthAnchor.new(1)
13
+ end
14
+
15
+ def default_units
16
+ [9,17,22,28,34,38,43,48,54,59,65,68,71,76,78,82,87,89,96,103,105,
17
+ 107,112,118,119,119,134,139,144,150]
18
+ end
19
+
20
+ def cycle_end_calculation
21
+ ->(start_date, iteration) do
22
+ perpetual_cycle_anchor.next_occurrence(start_date) - 1
23
+ end
24
+ end
25
+
26
+ def unit_for_interval(units, interval)
27
+ start, stop = case interval.iteration
28
+ when 1
29
+ [1, units[interval.iteration - 1]]
30
+ when 25
31
+ [[119, 1], [119, 30]]
32
+ when 26
33
+ [[119, 40], [119, 400]]
34
+ else
35
+ [units[interval.iteration - 2] + 1, units[interval.iteration - 1]]
36
+ end
37
+ if interval.end_date.jewish_day == 29 && interval.end_date.days_in_jewish_month == 29
38
+ stop = units[interval.iteration]
39
+ end
40
+ Zmanim::Limudim::Unit.new(start, stop)
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,40 @@
1
+ module Zmanim::Limudim
2
+ class Cycle
3
+ attr_reader :start_date, :end_date, :iteration
4
+
5
+ def initialize(start_date, end_date, iteration)
6
+ @start_date = start_date
7
+ @end_date = end_date
8
+ @iteration = iteration
9
+ end
10
+
11
+ def self.from_perpetual_anchor(anchor, cycle_end_calculation, date)
12
+ start_date = anchor.current_or_previous_occurrence(date)
13
+ end_date = cycle_end_calculation.(start_date, nil)
14
+ Cycle.new(start_date, end_date, nil)
15
+ end
16
+
17
+ def self.from_cycle_initiation(initial_cycle_date, cycle_end_calculation, date)
18
+ return nil if initial_cycle_date > date
19
+ iteration = 1
20
+ end_date = cycle_end_calculation.(initial_cycle_date, iteration)
21
+ cycle = Cycle.new(initial_cycle_date, end_date, iteration)
22
+ while date > cycle.end_date
23
+ cycle = cycle.next(cycle_end_calculation)
24
+ end
25
+ cycle
26
+ end
27
+
28
+ def next(cycle_end_calculation)
29
+ return nil unless iteration
30
+ new_iteration = iteration + 1
31
+ new_start_date = end_date + 1
32
+ new_end_date = cycle_end_calculation.(new_start_date, new_iteration)
33
+ Cycle.new(new_start_date, new_end_date, new_iteration)
34
+ end
35
+
36
+ def first_interval(interval_end_calculation)
37
+ Interval.first_for_cycle(self, interval_end_calculation)
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,37 @@
1
+ module Zmanim::Limudim
2
+ class Interval
3
+ attr_reader :start_date, :end_date, :iteration, :cycle
4
+
5
+ def initialize(start_date, end_date, iteration, cycle)
6
+ @start_date = start_date
7
+ @end_date = end_date
8
+ @iteration = iteration
9
+ @cycle = cycle
10
+ end
11
+
12
+ def self.first_for_cycle(cycle, interval_end_calculation)
13
+ start_date = cycle.start_date
14
+ iteration = 1
15
+ end_date = interval_end_calculation.(cycle, start_date)
16
+ Interval.new(start_date, end_date, iteration, cycle)
17
+ end
18
+
19
+ def next(interval_end_calculation)
20
+ next_for_iteration(iteration+1, interval_end_calculation)
21
+ end
22
+
23
+ def skip(interval_end_calculation)
24
+ next_for_iteration(iteration, interval_end_calculation)
25
+ end
26
+
27
+ private
28
+
29
+ def next_for_iteration(new_iteration, interval_end_calculation)
30
+ return nil if end_date >= cycle.end_date # paranoid check to remain in cycle bounds
31
+ new_start_date = end_date + 1
32
+ new_end_date = interval_end_calculation.(cycle, new_start_date)
33
+ Interval.new(new_start_date, new_end_date, new_iteration, cycle)
34
+ end
35
+
36
+ end
37
+ end