zmanim 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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