mhc 1.0.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 (127) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +27 -0
  3. data/.rspec +2 -0
  4. data/.travis.yml +3 -0
  5. data/COPYRIGHT +28 -0
  6. data/Gemfile +8 -0
  7. data/README.org +209 -0
  8. data/Rakefile +13 -0
  9. data/bin/mhc +312 -0
  10. data/emacs/Cask +25 -0
  11. data/emacs/Makefile +58 -0
  12. data/emacs/mhc-calendar.el +1723 -0
  13. data/emacs/mhc-calfw.el +135 -0
  14. data/emacs/mhc-compat.el +90 -0
  15. data/emacs/mhc-date.el +642 -0
  16. data/emacs/mhc-day.el +149 -0
  17. data/emacs/mhc-db.el +158 -0
  18. data/emacs/mhc-draft.el +211 -0
  19. data/emacs/mhc-e21.el +167 -0
  20. data/emacs/mhc-face.el +236 -0
  21. data/emacs/mhc-file.el +224 -0
  22. data/emacs/mhc-guess.el +648 -0
  23. data/emacs/mhc-header.el +176 -0
  24. data/emacs/mhc-logic.el +563 -0
  25. data/emacs/mhc-message.el +130 -0
  26. data/emacs/mhc-minibuf.el +466 -0
  27. data/emacs/mhc-misc.el +248 -0
  28. data/emacs/mhc-mua.el +260 -0
  29. data/emacs/mhc-parse.el +286 -0
  30. data/emacs/mhc-process.el +35 -0
  31. data/emacs/mhc-ps.el +1174 -0
  32. data/emacs/mhc-record.el +201 -0
  33. data/emacs/mhc-schedule.el +202 -0
  34. data/emacs/mhc-summary.el +763 -0
  35. data/emacs/mhc-sync.el +158 -0
  36. data/emacs/mhc-vars.el +149 -0
  37. data/emacs/mhc.el +1114 -0
  38. data/icons/Anniversary.xbm +6 -0
  39. data/icons/Anniversary.xpm +27 -0
  40. data/icons/Birthday.xbm +6 -0
  41. data/icons/Birthday.xpm +25 -0
  42. data/icons/Business.xbm +6 -0
  43. data/icons/Business.xpm +24 -0
  44. data/icons/CheckBox.xbm +6 -0
  45. data/icons/CheckBox.xpm +24 -0
  46. data/icons/CheckedBox.xbm +6 -0
  47. data/icons/CheckedBox.xpm +25 -0
  48. data/icons/Conflict.xbm +6 -0
  49. data/icons/Conflict.xpm +22 -0
  50. data/icons/Date.xbm +6 -0
  51. data/icons/Date.xpm +29 -0
  52. data/icons/Holiday.xbm +6 -0
  53. data/icons/Holiday.xpm +25 -0
  54. data/icons/Link.xbm +6 -0
  55. data/icons/Link.xpm +25 -0
  56. data/icons/Other.xbm +6 -0
  57. data/icons/Other.xpm +28 -0
  58. data/icons/Party.xbm +6 -0
  59. data/icons/Party.xpm +23 -0
  60. data/icons/Private.xbm +6 -0
  61. data/icons/Private.xpm +26 -0
  62. data/icons/Recurrence.xbm +6 -0
  63. data/icons/Recurrence.xpm +98 -0
  64. data/icons/Vacation.xbm +6 -0
  65. data/icons/Vacation.xpm +26 -0
  66. data/lib/mhc.rb +45 -0
  67. data/lib/mhc/builder.rb +64 -0
  68. data/lib/mhc/caldav.rb +304 -0
  69. data/lib/mhc/calendar.rb +106 -0
  70. data/lib/mhc/command.rb +13 -0
  71. data/lib/mhc/command/cache.rb +14 -0
  72. data/lib/mhc/command/completions.rb +108 -0
  73. data/lib/mhc/command/init.rb +133 -0
  74. data/lib/mhc/command/scan.rb +33 -0
  75. data/lib/mhc/command/sync.rb +22 -0
  76. data/lib/mhc/config.rb +229 -0
  77. data/lib/mhc/converter.rb +330 -0
  78. data/lib/mhc/datastore.rb +164 -0
  79. data/lib/mhc/date_enumerator.rb +274 -0
  80. data/lib/mhc/date_frame.rb +124 -0
  81. data/lib/mhc/date_helper.rb +49 -0
  82. data/lib/mhc/etag.rb +68 -0
  83. data/lib/mhc/event.rb +396 -0
  84. data/lib/mhc/formatter.rb +312 -0
  85. data/lib/mhc/logger.rb +94 -0
  86. data/lib/mhc/modifier.rb +149 -0
  87. data/lib/mhc/occurrence.rb +94 -0
  88. data/lib/mhc/occurrence_enumerator.rb +113 -0
  89. data/lib/mhc/property_value.rb +33 -0
  90. data/lib/mhc/property_value/date.rb +190 -0
  91. data/lib/mhc/property_value/integer.rb +15 -0
  92. data/lib/mhc/property_value/list.rb +41 -0
  93. data/lib/mhc/property_value/period.rb +49 -0
  94. data/lib/mhc/property_value/range.rb +100 -0
  95. data/lib/mhc/property_value/recurrence_condition.rb +272 -0
  96. data/lib/mhc/property_value/text.rb +11 -0
  97. data/lib/mhc/property_value/time.rb +45 -0
  98. data/lib/mhc/query.rb +210 -0
  99. data/lib/mhc/sync.rb +46 -0
  100. data/lib/mhc/sync/driver.rb +108 -0
  101. data/lib/mhc/sync/status.rb +70 -0
  102. data/lib/mhc/sync/status_manager.rb +142 -0
  103. data/lib/mhc/sync/strategy.rb +233 -0
  104. data/lib/mhc/sync/syncinfo.rb +98 -0
  105. data/lib/mhc/templates/config.yml.erb +142 -0
  106. data/lib/mhc/version.rb +4 -0
  107. data/lib/mhc/webdav.rb +319 -0
  108. data/mhc.gemspec +24 -0
  109. data/samples/DOT.mhc-config.yml +116 -0
  110. data/samples/japanese-holidays.mhcc +153 -0
  111. data/samples/mhc-completions.zsh +11 -0
  112. data/spec/mhc_spec.rb +682 -0
  113. data/spec/spec_helper.rb +9 -0
  114. data/xpm/close.xpm +18 -0
  115. data/xpm/delete.xpm +19 -0
  116. data/xpm/exit.xpm +18 -0
  117. data/xpm/month.xpm +18 -0
  118. data/xpm/next.xpm +18 -0
  119. data/xpm/next2.xpm +18 -0
  120. data/xpm/next_year.xpm +18 -0
  121. data/xpm/open.xpm +19 -0
  122. data/xpm/prev.xpm +18 -0
  123. data/xpm/prev2.xpm +18 -0
  124. data/xpm/prev_year.xpm +18 -0
  125. data/xpm/save.xpm +19 -0
  126. data/xpm/today.xpm +18 -0
  127. metadata +214 -0
data/mhc.gemspec ADDED
@@ -0,0 +1,24 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'mhc/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "mhc"
8
+ spec.version = Mhc::VERSION
9
+ spec.authors = ["Yoshinari Nomura"]
10
+ spec.email = ["nom@quickhack.net"]
11
+ spec.summary = %q{Message Harmonized Calendaring}
12
+ spec.description = %q{Message Harmonized Calendaring.}
13
+ spec.homepage = "http://www.quickhack.net/mhc"
14
+ spec.license = "BSD"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_development_dependency "bundler", "~> 1.5"
22
+ spec.add_development_dependency "rake"
23
+ spec.add_development_dependency "rspec"
24
+ end
@@ -0,0 +1,116 @@
1
+ ################################################################
2
+ # Setup config file ~/.mhc/config.yml
3
+ #
4
+ # Google Calendar URL for CalDAV is in the form of:
5
+ # https://www.google.com/calendar/dav/{calendar_id}/events
6
+ #
7
+ # calendar_id:
8
+ # for primary calendar is just your email address.
9
+ # for others will be in the form of:
10
+ # [long-string-of-characters]@group.calendar.google.com
11
+ #
12
+ # You can get them by clicking the down arrow next to your
13
+ # calendar at calendar.google.com and selecting 'Calendar Settings'.
14
+ # Be sure to use HTTPS in your URL, as an http address will not work.
15
+ #
16
+ # for more details about Google Calendar settings:
17
+ # http://www.google.com/support/calendar/bin/answer.py?answer=99358
18
+ # and click Sunbird section.
19
+ #
20
+ # Fill in the blanks indicated as *****,
21
+ # and invoke the command:
22
+ #
23
+ # % mhc sync personal
24
+ #
25
+ # Articles in past 90 days and future 90 days in MHC
26
+ # will be mirrored to target Google Calendar.
27
+ # (Hard-coded in lib/mhc/calendar.rb for now)
28
+ # Also other articles in Google Calendar will be DELETED.
29
+ #
30
+ # Before the first try, I recommend you to
31
+ # make a new calendar on your Google Calendar,
32
+ # and backup MHC folder ~/Mai/schedule.
33
+ #
34
+ # Currently, the type of STRATEGY in SYNC_CHANNELS allows only "mirror"
35
+ # from MHC to Google Calendar. We are planning to support the
36
+ # true two-way sync soon.
37
+ #
38
+ ---
39
+ ################################################################
40
+ GENERAL:
41
+ ################################################################
42
+ TZID: "Asia/Tokyo"
43
+ REPOSITORY: ~/MHC
44
+
45
+ ################################################################
46
+ SYNC_CHANNELS:
47
+ ################################################################
48
+
49
+ - NAME: personal
50
+ CALENDAR1: personal
51
+ CALENDAR2: google_personal
52
+ STRATEGY: mirror
53
+
54
+ - NAME: family
55
+ CALENDAR1: family
56
+ CALENDAR2: google_family
57
+ STRATEGY: mirror
58
+
59
+ - NAME: business
60
+ CALENDAR1: business
61
+ CALENDAR2: google_business
62
+ STRATEGY: mirror
63
+
64
+ ################################################################
65
+ CALENDARS:
66
+ ################################################################
67
+
68
+ ################################################################
69
+ ## MHC local
70
+
71
+ # MHC: Master calendar (default)
72
+ - &mhc_default
73
+ NAME: master
74
+ TYPE: mhc
75
+
76
+ # MHC: Personal calendar mirroed to my Android
77
+ - <<: *mhc_default
78
+ NAME: personal
79
+ FILTER: '!category:[birthday japanese]'
80
+
81
+ # MHC: Published calendar to my colleagues
82
+ - <<: *mhc_default
83
+ NAME: business
84
+ FILTER: '!category:[private japanese] & category:[lecture seminar conference meeting work event party trip holiday reserved task]'
85
+ MODIFIERS:
86
+ - hide_description
87
+ - hide_location
88
+ - replace_subject_by_category
89
+
90
+ # MHC: Published calendar to my family
91
+ - <<: *mhc_default
92
+ NAME: family
93
+ FILTER: '!category:[birthday japanese] & category:[work event party trip holiday private]'
94
+ MODIFIERS:
95
+ - hide_description
96
+
97
+ ################################################################
98
+ ## Google Calendar
99
+
100
+ # Displayname: MHC
101
+ - &google_default
102
+ NAME: google_personal
103
+ TYPE: caldav
104
+ USER: *********@gmail.com
105
+ PASSWORD: ***************
106
+ URL: https://calendar.google.com/calendar/dav/**************************@group.calendar.google.com/events/
107
+
108
+ # Displayname: For Family
109
+ - <<: *google_default
110
+ NAME: google_family
111
+ URL: https://calendar.google.com/calendar/dav/**************************@group.calendar.google.com/events/
112
+
113
+ # Displayname: For Colleagues
114
+ - <<: *google_default
115
+ NAME: google_business
116
+ URL: https://calendar.google.com/calendar/dav/**************************@group.calendar.google.com/events/
@@ -0,0 +1,153 @@
1
+ ##
2
+ ## Japanese Holidays
3
+ ##
4
+ ## Place this as ~/Mail/schedule/presets/japanese-holidays.mhcc
5
+ ##
6
+
7
+ X-SC-Subject: 元日
8
+ X-SC-Category: Holiday Japanese
9
+ X-SC-Cond: 1 Jan
10
+ X-SC-Record-Id: E2BAB555-3CEB-4508-96AD-1B59AA24ADC3
11
+
12
+ X-SC-Subject: 成人の日
13
+ X-SC-Category: Holiday Japanese
14
+ X-SC-Cond: 15 Jan
15
+ X-SC-Duration: -19990115
16
+ X-SC-Record-Id: EA9F4BA5-7D5A-4794-AFB3-6AB68FCA9719
17
+
18
+ X-SC-Subject: 成人の日
19
+ X-SC-Category: Holiday Japanese
20
+ X-SC-Cond: 2nd Mon Jan
21
+ X-SC-Duration: 20000110-
22
+ X-SC-Record-Id: 0BC2CBD0-D81E-4315-B9A8-E112C8E3DC1C
23
+
24
+ X-SC-Subject: 建国記念の日
25
+ X-SC-Category: Holiday Japanese
26
+ X-SC-Cond: 11 Feb
27
+ X-SC-Record-Id: AC1B378C-BAFE-4B6E-AF9C-78C2377E8AA4
28
+
29
+ X-SC-Subject: みどりの日
30
+ X-SC-Category: Holiday Japanese
31
+ X-SC-Cond: 29 Apr
32
+ X-SC-Duration: -20060429
33
+ X-SC-Record-Id: B78EAAEE-9963-4573-9EC7-0879F8940AEE
34
+
35
+ X-SC-Subject: 昭和の日
36
+ X-SC-Category: Holiday Japanese
37
+ X-SC-Cond: 29 Apr
38
+ X-SC-Duration: 20070429-
39
+ X-SC-Record-Id: A458E14C-960C-4F01-AF73-8ACB1B51A6A1
40
+
41
+ X-SC-Subject: 憲法記念日
42
+ X-SC-Category: Holiday Japanese
43
+ X-SC-Cond: 3 May
44
+ X-SC-Record-Id: BA89778E-E8CC-4588-B5C3-56F86483DEC1
45
+
46
+ X-SC-Subject: 国民の休日
47
+ X-SC-Category: Holiday Japanese
48
+ X-SC-Cond: 4 May
49
+ X-SC-Duration: -20060504
50
+ X-SC-Record-Id: 46953810-BD72-45DE-BC11-104CBE970CFF
51
+
52
+ X-SC-Subject: みどりの日
53
+ X-SC-Category: Holiday Japanese
54
+ X-SC-Cond: 4 May
55
+ X-SC-Duration: 20070504-
56
+ X-SC-Record-Id: 47938EDA-41A5-4E51-BDCB-2D3B60F49D71
57
+
58
+ X-SC-Subject: こどもの日
59
+ X-SC-Category: Holiday Japanese
60
+ X-SC-Cond: 5 May
61
+ X-SC-Record-Id: 4AE5568A-2DFE-4B6B-92E5-C4BFADFB2CCF
62
+
63
+ X-SC-Subject: 海の日
64
+ X-SC-Category: Holiday Japanese
65
+ X-SC-Cond: 20 Jul
66
+ X-SC-Duration: -20020720
67
+ X-SC-Record-Id: 5E03776A-4280-4337-85C0-F1322A3AAE6E
68
+
69
+ X-SC-Subject: 海の日
70
+ X-SC-Category: Holiday Japanese
71
+ X-SC-Cond: 3rd Mon Jul
72
+ X-SC-Duration: 20030701-
73
+ X-SC-Record-Id: BD4156C2-5546-4146-8297-09CF4210A346
74
+
75
+ X-SC-Subject: 敬老の日
76
+ X-SC-Category: Holiday Japanese
77
+ X-SC-Cond: 15 Sep
78
+ X-SC-Duration: -20020915
79
+ X-SC-Record-Id: 29BC6E4E-0D70-4EF8-8AF0-7000254D3CDB
80
+
81
+ X-SC-Subject: 敬老の日
82
+ X-SC-Category: Holiday Japanese
83
+ X-SC-Cond: 3rd Mon Sep
84
+ X-SC-Duration: 20030901-
85
+ X-SC-Record-Id: F303C1C9-01B0-437C-A2E2-BCD1ADD901F2
86
+
87
+ X-SC-Subject: 体育の日
88
+ X-SC-Category: Holiday Japanese
89
+ X-SC-Cond: 10 Oct
90
+ X-SC-Duration: -19991010
91
+ X-SC-Record-Id: AFABC42C-2E9D-4093-A4AF-DA12D4D4B9D7
92
+
93
+ X-SC-Subject: 体育の日
94
+ X-SC-Category: Holiday Japanese
95
+ X-SC-Cond: 2nd Mon Oct
96
+ X-SC-Duration: 20001009-
97
+ X-SC-Record-Id: C17D9CA5-28AF-4826-AD33-8B75473E5B52
98
+
99
+ X-SC-Subject: 文化の日
100
+ X-SC-Category: Holiday Japanese
101
+ X-SC-Cond: 3 Nov
102
+ X-SC-Record-Id: A76779D2-BB44-4ED5-ACF9-B646E10C7313
103
+
104
+ X-SC-Subject: 勤労感謝の日
105
+ X-SC-Category: Holiday Japanese
106
+ X-SC-Cond: 23 Nov
107
+ X-SC-Record-Id: 97E6F125-2625-44A9-8D43-A6FCA9670D8D
108
+
109
+ X-SC-Subject: 天皇誕生日
110
+ X-SC-Category: Holiday Japanese
111
+ X-SC-Cond: 23 Dec
112
+ X-SC-Record-Id: 51D42B0D-EF46-4D65-B62A-6ED2F0D1F0B5
113
+
114
+ ## 毎年変わる祝日と振替休日
115
+
116
+ X-SC-Subject: 春分の日
117
+ X-SC-Day: 19960320 19970320 19980321 19990321 20000320 20010320 20020321
118
+ 20030321 20040320 20050320 20060321 20070321 20080320 20090320
119
+ 20100321 20110321 20120320 20130320 20140321 20150321 20160320
120
+ 20170320 20180321 20190321 20200320 20210320 20220321 20230321
121
+ 20240320 20250320 20260320 20270321 20280320 20290320 20300320
122
+ 20310321
123
+ X-SC-Category: Holiday Japanese
124
+ X-SC-Record-Id: 37616252-E6E5-4C69-9965-3F7B0236A0D8
125
+
126
+ X-SC-Subject: 秋分の日
127
+ X-SC-Day: 19960923 19970923 19980923 19990923 20000923 20010923 20020923
128
+ 20030923 20040923 20050923 20060923 20070923 20080923 20090923
129
+ 20100923 20110923 20120922 20130923 20140923 20150923 20160922
130
+ 20170923 20180923 20190923 20200922 20210923 20220923 20230923
131
+ 20240922 20250923 20260923 20270923 20280922 20290923 20300923
132
+ 20310923
133
+ X-SC-Category: Holiday Japanese
134
+ X-SC-Record-Id: 54A339AD-F7FD-4E56-9B70-2D09F840E94D
135
+
136
+ X-SC-Subject: 振替休日
137
+ X-SC-Day: 19900212 19900430 19900924 19901224 19910506 19910916 19911104
138
+ 19931011 19950102 19950116 19960212 19960506 19960916 19961104
139
+ 19970721 19971124 19990322 19991011 20010212 20010430 20010924
140
+ 20011224 20020506 20020916 20021104 20031124 20050321 20060102
141
+ 20070212 20070430 20070924 20071224 20080506 20080721 20081124
142
+ 20090506 20090922 20100322 20120102 20120430 20121224 20130506
143
+ 20131104 20140506 20141124 20150506 20160321 20170102 20180212
144
+ 20180430 20180924 20181224 20190506 20191104 20200506 20230102
145
+ 20240212 20240506 20240923 20241104 20250506 20251124 20260506
146
+ 20270322 20290212 20290430 20290924 20291224 20300506 20301104
147
+ 20310506 20311124
148
+ X-SC-Category: Holiday Japanese
149
+ X-SC-Record-Id: E2D696DF-EB49-44D7-B06C-812B10BD99A2
150
+
151
+ ## Make sure you have at least one blank line for each entry (改行で終わる)
152
+
153
+ ## EOF
@@ -0,0 +1,11 @@
1
+ compdef _mhc mhc
2
+
3
+ _mhc () {
4
+ local curcontext="$curcontext"
5
+ local line state _opts
6
+
7
+ _opts=("${(@f)$(mhc completions -- ${(Q)words[2,-1]})}")
8
+ $_opts && return 0
9
+
10
+ return 1
11
+ }
data/spec/mhc_spec.rb ADDED
@@ -0,0 +1,682 @@
1
+ require 'spec_helper'
2
+
3
+ ### Rspec file for MHC
4
+
5
+ describe Mhc do
6
+ it 'should have a version number' do
7
+ expect(Mhc::VERSION).not_to be_nil
8
+ end
9
+ end
10
+
11
+ describe Mhc::PropertyValue::Date do
12
+ it "should parse 'today'" do
13
+ expect(Mhc::PropertyValue::Date.parse_relative("today")).to eq(Date.today)
14
+ end
15
+ end
16
+
17
+ describe Mhc::Converter::Emacs do
18
+ it "should convert a Ruby Hash to Emacs plist" do
19
+ hash = {
20
+ :title => "\\a\"",
21
+ :start_date => "b\"b",
22
+ :start_time => "c",
23
+ :end_date => "d",
24
+ :end_time => "e",
25
+ :description => "f",
26
+ :location => "g",
27
+ :source => "h"
28
+ }
29
+ expect(Mhc::Converter::Emacs.new.to_emacs(hash)).to eq '(:title "\\\\a\\"" :start-date "b\\"b" :start-time "c" :end-date "d" :end-time "e" :description "f" :location "g" :source "h")'
30
+ end
31
+ end
32
+
33
+ describe Mhc::Event do
34
+ before :all do
35
+ ENV["MHC_TZID"] = 'UTC'
36
+ Mhc.default_tzid = ENV["MHC_TZID"]
37
+ end
38
+
39
+ before :each do
40
+ time_now = ::Time.utc(2014, 1, 1)
41
+ allow(::Time).to receive(:now).and_return(time_now)
42
+ end
43
+
44
+ it "should parse a string and dump to the same string" do
45
+ str = <<-EOF.strip_heredoc
46
+ X-SC-Subject: Weekly Event on Monday and Thursday
47
+ X-SC-Location: Office
48
+ X-SC-Day: !20140410
49
+ X-SC-Time: 12:40-14:10
50
+ X-SC-Category: Work
51
+ X-SC-Mission-Tag: TEST-Mission
52
+ X-SC-Recurrence-Tag: TEST
53
+ X-SC-Cond: Mon Thu
54
+ X-SC-Duration: 20140401-20140430
55
+ X-SC-Alarm: 5 minutes
56
+ X-SC-Record-Id: FEDA4C97-21C2-46AA-A395-075856FBD5C3
57
+ X-SC-Sequence: 0
58
+
59
+ this is description
60
+ EOF
61
+ ev = Mhc::Event.parse(str)
62
+ expect(ev.dump).to eq str
63
+ end
64
+
65
+ it "should parse a string and dump to the same string even if all values are empty" do
66
+ str = <<-EOF.strip_heredoc
67
+ X-SC-Subject:
68
+ X-SC-Location:
69
+ X-SC-Day:
70
+ X-SC-Time:
71
+ X-SC-Category:
72
+ X-SC-Mission-Tag:
73
+ X-SC-Recurrence-Tag:
74
+ X-SC-Cond:
75
+ X-SC-Duration:
76
+ X-SC-Alarm:
77
+ X-SC-Record-Id:
78
+ X-SC-Sequence: 0
79
+
80
+ EOF
81
+ ev = Mhc::Event.parse(str)
82
+ expect(ev.dump).to eq str
83
+ end
84
+
85
+ it "should parse a string and dump to the same string even if some fields has hanging strings" do
86
+ str = <<-EOF.strip_heredoc
87
+ X-SC-Subject: Autumnal Equinox Day
88
+ X-SC-Location:
89
+ X-SC-Day: 19960923 19970923 19980923 19990923 20000923 20010923 20020923
90
+ 20030923 20040923 20050923 20060923 20070923 20080923 20090923
91
+ 20100923 20110923 20120922 20130923 20140923 20150923 20160922
92
+ 20170923 20180923 20190923 20200922 20210923 20220923 20230923
93
+ 20240922 20250923 20260923 20270923 20280922 20290923 20300923
94
+ 20310923
95
+ X-SC-Time:
96
+ X-SC-Category: Holiday
97
+ Japanese
98
+ X-SC-Mission-Tag:
99
+ X-SC-Recurrence-Tag:
100
+ X-SC-Cond:
101
+ X-SC-Duration:
102
+ X-SC-Alarm:
103
+ X-SC-Record-Id: 54A339AD-F7FD-4E56-9B70-2D09F840E94D
104
+ X-SC-Sequence: 0
105
+
106
+ EOF
107
+
108
+ dump_str = <<-EOF.strip_heredoc
109
+ X-SC-Subject: Autumnal Equinox Day
110
+ X-SC-Location:
111
+ X-SC-Day: 19960923 19970923 19980923 19990923 20000923 20010923 20020923 20030923 20040923 20050923 20060923 20070923 20080923 20090923 20100923 20110923 20120922 20130923 20140923 20150923 20160922 20170923 20180923 20190923 20200922 20210923 20220923 20230923 20240922 20250923 20260923 20270923 20280922 20290923 20300923 20310923
112
+ X-SC-Time:
113
+ X-SC-Category: Holiday Japanese
114
+ X-SC-Mission-Tag:
115
+ X-SC-Recurrence-Tag:
116
+ X-SC-Cond:
117
+ X-SC-Duration:
118
+ X-SC-Alarm:
119
+ X-SC-Record-Id: 54A339AD-F7FD-4E56-9B70-2D09F840E94D
120
+ X-SC-Sequence: 0
121
+
122
+ EOF
123
+ ev = Mhc::Event.parse(str)
124
+ expect(ev.dump).to eq dump_str
125
+ end
126
+
127
+
128
+
129
+ it "should occur weekly on Monday and Thursday from 2014-04-01 to 2014-04-30 with exception of 2014-04-10 (Thu)" do
130
+ ev = Mhc::Event.parse <<-EOF.strip_heredoc
131
+ X-SC-Subject: Weekly Event on Monday and Thursday
132
+ X-SC-Location: Office
133
+ X-SC-Day: !20140410
134
+ X-SC-Time: 12:40-14:10
135
+ X-SC-Category: Work
136
+ X-SC-Cond: Mon Thu
137
+ X-SC-Duration: 20140401-20140430
138
+ X-SC-Record-Id: FEDA4C97-21C2-46AA-A395-075856FBD5C3
139
+ EOF
140
+ from = Mhc::PropertyValue::Date.new(2014,04,7)
141
+ to = Mhc::PropertyValue::Date.new(2014,04,24)
142
+ # range.first is effective in narrowing the scan region so we will not have "2014-04-03"
143
+ expect(ev.occurrences(range:from..to).take(30).map{|occurrence| occurrence.date.to_s}).to eq \
144
+ ["20140407", "20140414", "20140417", "20140421", "20140424"]
145
+ end
146
+
147
+ it "should occur yearly on March 21" do
148
+ ev = Mhc::Event.parse <<-EOF.strip_heredoc
149
+ X-SC-Subject: Yearly Event on 21 March
150
+ X-SC-Location: Office
151
+ X-SC-Day:
152
+ X-SC-Time: 12:40-14:10
153
+ X-SC-Category: Work
154
+ X-SC-Cond: Mar 21
155
+ X-SC-Duration: 20140401-20200401
156
+ X-SC-Record-Id: FEDA4C97-21C2-46AA-A395-075856FBD5C3
157
+ EOF
158
+ expect(ev.occurrences.take(30).map{|o| o.date.to_s}).to eq \
159
+ ["20150321", "20160321", "20170321", "20180321", "20190321", "20200321"]
160
+ end
161
+
162
+ it "should show single day in X-SC-Day:" do
163
+ ev = Mhc::Event.parse <<-EOF.strip_heredoc
164
+ X-SC-Subject: Party
165
+ X-SC-Day: 20140509
166
+ X-SC-Time: 18:00-22:00
167
+ X-SC-Record-Id: 1653B99D-DED2-4758-934F-B868BFCA9E9F
168
+ EOF
169
+ expect(ev.occurrences.take(30).map{|o| o.date.to_s}).to eq \
170
+ ["20140509"]
171
+ end
172
+
173
+ it "should show three enumerated days listed in X-SC-Day:" do
174
+ ev = Mhc::Event.parse <<-EOF.strip_heredoc
175
+ X-SC-Subject: Three enumerated events in X-SC-Day:
176
+ X-SC-Day: 20140203 20140509 20140831 20140901-20140902
177
+ X-SC-Duration: 20140101-20141231
178
+ X-SC-Record-Id: FEDA4C97-21C2-46AA-A395-075856FBD5C3
179
+ EOF
180
+ expect(ev.occurrences.take(30).map{|o| o.to_s}).to eq \
181
+ ["20140203", "20140509", "20140831", "20140901-20140902"]
182
+ end
183
+
184
+ it "should show three day's event even if scan range is started from the middle of event" do
185
+ ev = Mhc::Event.parse <<-EOF.strip_heredoc
186
+ X-SC-Subject: Three day's event
187
+ X-SC-Day: 20140514-20140516
188
+ EOF
189
+ from = Mhc::PropertyValue::Date.new(2014, 5, 15)
190
+ to = Mhc::PropertyValue::Date.new(2014, 5, 16)
191
+ expect(ev.occurrences(range:from..to).take(30).map{|o| o.to_s}).to eq \
192
+ ["20140514-20140516"]
193
+ end
194
+
195
+ it "should produce a list of occurrences, and each occurrence has different date" do
196
+ ev = Mhc::Event.parse <<-EOF.strip_heredoc
197
+ X-SC-Subject: TEST
198
+ X-SC-Time: 10:00-12:00
199
+ X-SC-Day: 20140203 20140509 20140831
200
+ X-SC-Duration: 20140101-20141231
201
+ X-SC-Record-Id: FEDA4C97-21C2-46AA-A395-075856FBD5C3
202
+ EOF
203
+ expect(ev.occurrences.take(30).map{|o| "#{o.date} #{o.time_range} #{o.subject}"}).to eq \
204
+ ["20140203 10:00-12:00 TEST", "20140509 10:00-12:00 TEST", "20140831 10:00-12:00 TEST"]
205
+ end
206
+
207
+ it "should return true when #allday? is called if X-SC-Time: is blank" do
208
+ ev = Mhc::Event.parse <<-EOF.strip_heredoc
209
+ X-SC-Subject: TEST
210
+ X-SC-Time:
211
+ X-SC-Day: 20140203 20140509 20140831
212
+ X-SC-Duration: 20140101-20141231
213
+ X-SC-Record-Id: FEDA4C97-21C2-46AA-A395-075856FBD5C3
214
+ EOF
215
+ expect(ev.occurrences.take(30).all? {|o| o.allday? }).to eq true
216
+ end
217
+
218
+ it "should return false when #allday? is called if X-SC-Time: is not blank" do
219
+ ev = Mhc::Event.parse <<-EOF.strip_heredoc
220
+ X-SC-Subject: TEST
221
+ X-SC-Time: 10:00-12:00
222
+ X-SC-Day: 20140203 20140509 20140831
223
+ X-SC-Duration: 20140101-20141231
224
+ X-SC-Record-Id: FEDA4C97-21C2-46AA-A395-075856FBD5C3
225
+ EOF
226
+ expect(ev.occurrences.take(30).all? {|o| not o.allday? }).to eq true
227
+ end
228
+
229
+ it "should return almost infinit number of entries: 1970-1-1 to 50 years future, if X-SC-Duration: is empty" do
230
+ ev = Mhc::Event.parse <<-EOF.strip_heredoc
231
+ X-SC-Subject: New Year Day
232
+ X-SC-Cond: 1 Jan
233
+ X-SC-Duration:
234
+ X-SC-Record-Id: FEDA4C97-21C2-46AA-A395-075856FBD5C3
235
+ EOF
236
+ times = Date.today.year + 50 - Date.new(1970, 1, 1).year + 1
237
+ expect(ev.occurrences.map{|o| o.date.to_s}.length).to eq times
238
+ end
239
+
240
+ it "should return ``yearly by monthday'' icalendar rrule string" do
241
+ ev = Mhc::Event.parse <<-EOF.strip_heredoc
242
+ X-SC-Subject: New Year Day
243
+ X-SC-Cond: 1 Jan
244
+ X-SC-Duration:
245
+ X-SC-Record-Id: FEDA4C97-21C2-46AA-A395-075856FBD5C3
246
+ EOF
247
+ expect(ev.recurrence_condition.to_ics).to eq "FREQ=YEARLY;INTERVAL=1;WKST=MO;BYMONTH=1;BYMONTHDAY=1"
248
+ end
249
+
250
+ it "should return ``yearly by day'' icalendar rrule string" do
251
+ ev = Mhc::Event.parse <<-EOF.strip_heredoc
252
+ X-SC-Subject: Mother's Day
253
+ X-SC-Cond: 2nd Sun May
254
+ X-SC-Duration:
255
+ X-SC-Record-Id: FEDA4C97-21C2-46AA-A395-075856FBD5C3
256
+ EOF
257
+ expect(ev.recurrence_condition.to_ics).to eq "FREQ=YEARLY;INTERVAL=1;WKST=MO;BYMONTH=5;BYDAY=2SU"
258
+ end
259
+
260
+ it "should return ``weekly'' icalendar rrule string" do
261
+ ev = Mhc::Event.parse <<-EOF.strip_heredoc
262
+ X-SC-Subject: Wednesday and Sunday Weekly event
263
+ X-SC-Cond: Wed Sun
264
+ X-SC-Duration: 20140401-20140424
265
+ X-SC-Record-Id: FEDA4C97-21C2-46AA-A395-075856FBD5C3
266
+ EOF
267
+ expect(ev.recurrence_condition.to_ics(nil, ev.duration.last)).to eq "FREQ=WEEKLY;INTERVAL=1;WKST=MO;BYDAY=WE,SU;UNTIL=20140424"
268
+ end
269
+
270
+ it "should return icalendar VEVENT string with RRULE field" do
271
+ ev = Mhc::Event.parse <<-EOF.strip_heredoc
272
+ X-SC-Subject: Wednesday and Sunday Weekly event
273
+ X-SC-Cond: Wed Sun
274
+ X-SC-Category: Work
275
+ X-SC-Location: Office
276
+ X-SC-Duration: 20140401-20140424
277
+ X-SC-Record-Id: FEDA4C97-21C2-46AA-A395-075856FBD5C3
278
+
279
+ this is description
280
+ EOF
281
+ expect(ev.to_ics).to eq <<-'EOF'.strip_heredoc
282
+ BEGIN:VEVENT
283
+ CREATED;VALUE=DATE-TIME:20140101T000000Z
284
+ DTEND;VALUE=DATE:20140403
285
+ DTSTART;VALUE=DATE:20140402
286
+ DTSTAMP;VALUE=DATE-TIME:20140101T000000Z
287
+ CATEGORIES:Work
288
+ LAST-MODIFIED;VALUE=DATE-TIME:20140101T000000Z
289
+ UID:FEDA4C97-21C2-46AA-A395-075856FBD5C3
290
+ DESCRIPTION:this is description\n
291
+ SUMMARY:Wednesday and Sunday Weekly event
292
+ RRULE:FREQ=WEEKLY;INTERVAL=1;WKST=MO;BYDAY=WE,SU;UNTIL=20140424
293
+ LOCATION:Office
294
+ SEQUENCE:0
295
+ END:VEVENT
296
+ EOF
297
+ end
298
+
299
+ it "should return icalendar VEVENT string taking DTSTART from the first entry of X-SC-Day: and RDATE from remains" do
300
+ ev = Mhc::Event.parse <<-EOF.strip_heredoc
301
+ X-SC-Subject: thee events on 20140203 20140509 20140831
302
+ X-SC-Day: 20140203 20140509 20140831
303
+ X-SC-Record-Id: FEDA4C97-21C2-46AA-A395-075856FBD5C3
304
+
305
+ this is description
306
+ EOF
307
+ expect(ev.to_ics).to eq <<-'EOF'.strip_heredoc
308
+ BEGIN:VEVENT
309
+ RDATE;VALUE=DATE:20140509,20140831
310
+ CREATED;VALUE=DATE-TIME:20140101T000000Z
311
+ DTEND;VALUE=DATE:20140204
312
+ DTSTART;VALUE=DATE:20140203
313
+ DTSTAMP;VALUE=DATE-TIME:20140101T000000Z
314
+ LAST-MODIFIED;VALUE=DATE-TIME:20140101T000000Z
315
+ UID:FEDA4C97-21C2-46AA-A395-075856FBD5C3
316
+ DESCRIPTION:this is description\n
317
+ SUMMARY:thee events on 20140203 20140509 20140831
318
+ SEQUENCE:0
319
+ END:VEVENT
320
+ EOF
321
+ end
322
+
323
+ it "should return icalendar VEVENT string taking EXDATE from the entries of X-SC-Day: !YYYYMMDD" do
324
+ ev = Mhc::Event.parse <<-EOF.strip_heredoc
325
+ X-SC-Subject: Wednesdays in 2014-04 (2, 9, 16, ..., 30) with exceptions of 2, 16
326
+ X-SC-Cond: Wed
327
+ X-SC-Duration: 20140401-20140430
328
+ X-SC-Day: !20140402 !20140416
329
+ X-SC-Record-Id: FEDA4C97-21C2-46AA-A395-075856FBD5C3
330
+
331
+ this is description
332
+ EOF
333
+ expect(ev.to_ics).to eq <<-'EOF'.strip_heredoc
334
+ BEGIN:VEVENT
335
+ EXDATE;VALUE=DATE:20140402,20140416
336
+ CREATED;VALUE=DATE-TIME:20140101T000000Z
337
+ DTEND;VALUE=DATE:20140403
338
+ DTSTART;VALUE=DATE:20140402
339
+ DTSTAMP;VALUE=DATE-TIME:20140101T000000Z
340
+ LAST-MODIFIED;VALUE=DATE-TIME:20140101T000000Z
341
+ UID:FEDA4C97-21C2-46AA-A395-075856FBD5C3
342
+ DESCRIPTION:this is description\n
343
+ SUMMARY:Wednesdays in 2014-04 (2\, 9\, 16\, ...\, 30) with exceptions of 2\, 16
344
+ RRULE:FREQ=WEEKLY;INTERVAL=1;WKST=MO;BYDAY=WE;UNTIL=20140430
345
+ SEQUENCE:0
346
+ END:VEVENT
347
+ EOF
348
+ end
349
+
350
+ it "should return icalendar VEVENT string taking EXDATE from the entries of X-SC-Day: !YYYYMMDD and X-SC-Time:" do
351
+ ev = Mhc::Event.parse <<-EOF.strip_heredoc
352
+ X-SC-Subject: CS1
353
+ X-SC-Time: 08:40-10:10
354
+ X-SC-Category: Lecture
355
+ X-SC-Day: !20140514
356
+ X-SC-Cond: Wed
357
+ X-SC-Duration: 20140409-20140723
358
+ X-SC-Record-Id: 69CFD0DF-4058-425B-8C2B-40D81E6A2392
359
+ EOF
360
+ expect(ev.to_ics).to eq <<-'EOF'.strip_heredoc
361
+ BEGIN:VEVENT
362
+ EXDATE;VALUE=DATE-TIME:20140514T084000Z
363
+ CREATED;VALUE=DATE-TIME:20140101T000000Z
364
+ DTEND;VALUE=DATE-TIME:20140409T101000Z
365
+ DTSTART;VALUE=DATE-TIME:20140409T084000Z
366
+ DTSTAMP;VALUE=DATE-TIME:20140101T000000Z
367
+ CATEGORIES:Lecture
368
+ LAST-MODIFIED;VALUE=DATE-TIME:20140101T000000Z
369
+ UID:69CFD0DF-4058-425B-8C2B-40D81E6A2392
370
+ DESCRIPTION:
371
+ SUMMARY:CS1
372
+ RRULE:FREQ=WEEKLY;INTERVAL=1;WKST=MO;BYDAY=WE;UNTIL=20140723T084000Z
373
+ SEQUENCE:0
374
+ END:VEVENT
375
+ EOF
376
+ end
377
+
378
+ it "should return icalendar VEVENT over 24h event" do
379
+ ev = Mhc::Event.parse <<-EOF.strip_heredoc
380
+ X-SC-Subject: CS1
381
+ X-SC-Time: 12:00-10:10
382
+ X-SC-Day: 20140508-20140509
383
+ X-SC-Record-Id: 69CFD0DF-4058-425B-8C2B-40D81E6A2392
384
+ EOF
385
+ expect(ev.to_ics).to eq <<-'EOF'.strip_heredoc
386
+ BEGIN:VEVENT
387
+ CREATED;VALUE=DATE-TIME:20140101T000000Z
388
+ DTEND;VALUE=DATE-TIME:20140509T101000Z
389
+ DTSTART;VALUE=DATE-TIME:20140508T120000Z
390
+ DTSTAMP;VALUE=DATE-TIME:20140101T000000Z
391
+ LAST-MODIFIED;VALUE=DATE-TIME:20140101T000000Z
392
+ UID:69CFD0DF-4058-425B-8C2B-40D81E6A2392
393
+ DESCRIPTION:
394
+ SUMMARY:CS1
395
+ SEQUENCE:0
396
+ END:VEVENT
397
+ EOF
398
+ end
399
+
400
+ it "should return icalendar VEVENT two day's allday event" do
401
+ ev = Mhc::Event.parse <<-EOF.strip_heredoc
402
+ X-SC-Subject: CS1
403
+ X-SC-Day: 20140508-20140509
404
+ X-SC-Record-Id: 69CFD0DF-4058-425B-8C2B-40D81E6A2392
405
+ EOF
406
+ expect(ev.to_ics).to eq <<-'EOF'.strip_heredoc
407
+ BEGIN:VEVENT
408
+ CREATED;VALUE=DATE-TIME:20140101T000000Z
409
+ DTEND;VALUE=DATE:20140510
410
+ DTSTART;VALUE=DATE:20140508
411
+ DTSTAMP;VALUE=DATE-TIME:20140101T000000Z
412
+ LAST-MODIFIED;VALUE=DATE-TIME:20140101T000000Z
413
+ UID:69CFD0DF-4058-425B-8C2B-40D81E6A2392
414
+ DESCRIPTION:
415
+ SUMMARY:CS1
416
+ SEQUENCE:0
417
+ END:VEVENT
418
+ EOF
419
+ end
420
+
421
+ it "should convert 2014-03-11 10:30-12:00 (+0900 Asia/Tokyo) event to UTC Event" do
422
+ ev = Mhc::Event.new_from_ics <<-EOF.strip_heredoc
423
+ BEGIN:VCALENDAR
424
+ PRODID;X-RICAL-TZSOURCE=TZINFO:-//Quickhack.net//MHC 0.25.0//EN
425
+ CALSCALE:GREGORIAN
426
+ VERSION:2.0
427
+ BEGIN:VEVENT
428
+ CREATED;VALUE=DATE-TIME:20140101T000000Z
429
+ DTSTART;TZID=Asia/Tokyo;VALUE=DATE-TIME:20100311T103000
430
+ DTEND;TZID=Asia/Tokyo;VALUE=DATE-TIME:20100311T120000
431
+ DTSTAMP;VALUE=DATE-TIME:20140101T000000Z
432
+ LAST-MODIFIED;VALUE=DATE-TIME:20140101T000000Z
433
+ UID:69CFD0DF-4058-425B-8C2B-40D81E6A2392
434
+ DESCRIPTION:This is Description.
435
+ SUMMARY:CS1
436
+ SEQUENCE:0
437
+ END:VEVENT
438
+ END:VCALENDAR
439
+ EOF
440
+ expect(ev.dump).to eq <<-'EOF'.strip_heredoc
441
+ X-SC-Subject: CS1
442
+ X-SC-Location:
443
+ X-SC-Day: 20100311
444
+ X-SC-Time: 01:30-03:00
445
+ X-SC-Category:
446
+ X-SC-Mission-Tag:
447
+ X-SC-Recurrence-Tag:
448
+ X-SC-Cond:
449
+ X-SC-Duration:
450
+ X-SC-Alarm:
451
+ X-SC-Record-Id: 69CFD0DF-4058-425B-8C2B-40D81E6A2392
452
+ X-SC-Sequence: 0
453
+
454
+ This is Description.
455
+ EOF
456
+ end
457
+
458
+ it "should convert 2014-10-18 22:00-23:00 (Asia/Tokyo) iCalendar to 2014-10-18 15:00-16:00 (Europe/Paris) MHC Event" do
459
+ Mhc.default_tzid = "Europe/Paris"
460
+ ev = Mhc::Event.new_from_ics <<-EOF.strip_heredoc
461
+ BEGIN:VCALENDAR
462
+ PRODID;X-RICAL-TZSOURCE=TZINFO:-//Quickhack.net//MHC 0.25.0//EN
463
+ CALSCALE:GREGORIAN
464
+ VERSION:2.0
465
+ BEGIN:VEVENT
466
+ DTSTART;TZID=Asia/Tokyo;VALUE=DATE-TIME:20141018T220000
467
+ DTEND;VALUE=DATE-TIME:20141018T140000Z
468
+ UID:69CFD0DF-4058-425B-8C2B-40D81E6A2392
469
+ DESCRIPTION:This is Description.
470
+ SUMMARY:CS1
471
+ SEQUENCE:0
472
+ END:VEVENT
473
+ END:VCALENDAR
474
+ EOF
475
+ expect(ev.dump).to eq <<-'EOF'.strip_heredoc
476
+ X-SC-Subject: CS1
477
+ X-SC-Location:
478
+ X-SC-Day: 20141018
479
+ X-SC-Time: 15:00-16:00
480
+ X-SC-Category:
481
+ X-SC-Mission-Tag:
482
+ X-SC-Recurrence-Tag:
483
+ X-SC-Cond:
484
+ X-SC-Duration:
485
+ X-SC-Alarm:
486
+ X-SC-Record-Id: 69CFD0DF-4058-425B-8C2B-40D81E6A2392
487
+ X-SC-Sequence: 0
488
+
489
+ This is Description.
490
+ EOF
491
+ end
492
+
493
+ it "should create all-day event 20140508-20140509 from iCalendar" do
494
+ ev = Mhc::Event.new_from_ics <<-EOF.strip_heredoc
495
+ BEGIN:VCALENDAR
496
+ PRODID;X-RICAL-TZSOURCE=TZINFO:-//Quickhack.net//MHC 0.25.0//EN
497
+ CALSCALE:GREGORIAN
498
+ VERSION:2.0
499
+ BEGIN:VEVENT
500
+ CREATED;VALUE=DATE-TIME:20140101T000000Z
501
+ DTEND;VALUE=DATE:20140510
502
+ DTSTART;VALUE=DATE:20140508
503
+ DTSTAMP;VALUE=DATE-TIME:20140101T000000Z
504
+ LAST-MODIFIED;VALUE=DATE-TIME:20140101T000000Z
505
+ UID:69CFD0DF-4058-425B-8C2B-40D81E6A2392
506
+ DESCRIPTION:This is Description.
507
+ SUMMARY:CS1
508
+ SEQUENCE:0
509
+ END:VEVENT
510
+ END:VCALENDAR
511
+ EOF
512
+ expect(ev.dump).to eq <<-'EOF'.strip_heredoc
513
+ X-SC-Subject: CS1
514
+ X-SC-Location:
515
+ X-SC-Day: 20140508-20140509
516
+ X-SC-Time:
517
+ X-SC-Category:
518
+ X-SC-Mission-Tag:
519
+ X-SC-Recurrence-Tag:
520
+ X-SC-Cond:
521
+ X-SC-Duration:
522
+ X-SC-Alarm:
523
+ X-SC-Record-Id: 69CFD0DF-4058-425B-8C2B-40D81E6A2392
524
+ X-SC-Sequence: 0
525
+
526
+ This is Description.
527
+ EOF
528
+ end
529
+
530
+ it "should create recurrence condition from iCalendar string" do
531
+ ev = Mhc::Event.new_from_ics <<-EOF.strip_heredoc
532
+ BEGIN:VCALENDAR
533
+ PRODID;X-RICAL-TZSOURCE=TZINFO:-//Quickhack.net//MHC 0.25.0//EN
534
+ CALSCALE:GREGORIAN
535
+ VERSION:2.0
536
+ BEGIN:VEVENT
537
+ CREATED;VALUE=DATE-TIME:20140101T000000Z
538
+ DTEND;VALUE=DATE:20140403
539
+ DTSTART;VALUE=DATE:20140402
540
+ DTSTAMP;VALUE=DATE-TIME:20140101T000000Z
541
+ CATEGORIES:Work
542
+ LAST-MODIFIED;VALUE=DATE-TIME:20140101T000000Z
543
+ UID:FEDA4C97-21C2-46AA-A395-075856FBD5C3
544
+ DESCRIPTION:this is description\n
545
+ SUMMARY:Wednesday and Sunday Weekly event
546
+ RRULE:FREQ=WEEKLY;INTERVAL=1;WKST=MO;BYDAY=WE,SU;UNTIL=20140424
547
+ LOCATION:Office
548
+ SEQUENCE:0
549
+ END:VEVENT
550
+ END:VCALENDAR
551
+ EOF
552
+ expect(ev.dump).to eq <<-'EOF'.strip_heredoc
553
+ X-SC-Subject: Wednesday and Sunday Weekly event
554
+ X-SC-Location: Office
555
+ X-SC-Day:
556
+ X-SC-Time:
557
+ X-SC-Category: Work
558
+ X-SC-Mission-Tag:
559
+ X-SC-Recurrence-Tag:
560
+ X-SC-Cond: Wed Sun
561
+ X-SC-Duration: 20140402-20140424
562
+ X-SC-Alarm:
563
+ X-SC-Record-Id: FEDA4C97-21C2-46AA-A395-075856FBD5C3
564
+ X-SC-Sequence: 0
565
+
566
+ this is description
567
+ EOF
568
+ end
569
+
570
+ it "should create recurrence condition from iCalendar string with RDATE" do
571
+ Mhc.default_tzid = "Asia/Tokyo"
572
+ ev = Mhc::Event.new_from_ics <<-EOF.strip_heredoc
573
+ BEGIN:VCALENDAR
574
+ BEGIN:VEVENT
575
+ RDATE;TZID=Asia/Tokyo;VALUE=DATE-TIME:20141114T124500
576
+ EXDATE;TZID=Asia/Tokyo;VALUE=DATE-TIME:20141022T124500,20141119T124500,20
577
+ 141231T124500,20150107T124500
578
+ CREATED;VALUE=DATE-TIME:20140924T004619Z
579
+ DTEND;TZID=Asia/Tokyo;VALUE=DATE-TIME:20141001T141500
580
+ DTSTART;TZID=Asia/Tokyo;VALUE=DATE-TIME:20141001T124500
581
+ DTSTAMP;VALUE=DATE-TIME:20141017T061129Z
582
+ CATEGORIES:Lecture
583
+ LAST-MODIFIED;VALUE=DATE-TIME:20140924T004619Z
584
+ UID:FEDA4C97-21C2-46AA-A395-075856FBD5C3
585
+ DESCRIPTION:this is description\n
586
+ SUMMARY:PP
587
+ RRULE:FREQ=WEEKLY;INTERVAL=1;WKST=MO;BYDAY=WE;UNTIL=20150128T034500Z
588
+ LOCATION:Room11
589
+ SEQUENCE:4
590
+ END:VEVENT
591
+ END:VCALENDAR
592
+ EOF
593
+ expect(ev.dump).to eq <<-'EOF'.strip_heredoc
594
+ X-SC-Subject: PP
595
+ X-SC-Location: Room11
596
+ X-SC-Day: 20141114 !20141022 !20141119 !20141231 !20150107
597
+ X-SC-Time: 12:45-14:15
598
+ X-SC-Category: Lecture
599
+ X-SC-Mission-Tag:
600
+ X-SC-Recurrence-Tag:
601
+ X-SC-Cond: Wed
602
+ X-SC-Duration: 20141001-20150128
603
+ X-SC-Alarm:
604
+ X-SC-Record-Id: FEDA4C97-21C2-46AA-A395-075856FBD5C3
605
+ X-SC-Sequence: 4
606
+
607
+ this is description
608
+ EOF
609
+ end
610
+
611
+ it "should create duration-end considering timezone" do
612
+ Mhc.default_tzid = "Asia/Tokyo"
613
+ ev = Mhc::Event.new_from_ics <<-EOF.strip_heredoc
614
+ BEGIN:VCALENDAR
615
+ BEGIN:VEVENT
616
+ EXDATE;TZID=Asia/Tokyo;VALUE=DATE-TIME:20140514T084000,20140723T084000
617
+ DTEND;TZID=Asia/Tokyo;VALUE=DATE-TIME:20140409T101000
618
+ DTSTART;VALUE=DATE-TIME:20140408T234000Z
619
+ CATEGORIES:Lecture
620
+ UID:FEDA4C97-21C2-46AA-A395-075856FBD5C3
621
+ DESCRIPTION:this is description\n
622
+ SUMMARY:CS1
623
+ RRULE:FREQ=WEEKLY;INTERVAL=1;WKST=MO;BYDAY=WE;UNTIL=20140729T234000Z
624
+ LOCATION:Room11
625
+ SEQUENCE:4
626
+ END:VEVENT
627
+ END:VCALENDAR
628
+ EOF
629
+ expect(ev.dump).to eq <<-'EOF'.strip_heredoc
630
+ X-SC-Subject: CS1
631
+ X-SC-Location: Room11
632
+ X-SC-Day: !20140514 !20140723
633
+ X-SC-Time: 08:40-10:10
634
+ X-SC-Category: Lecture
635
+ X-SC-Mission-Tag:
636
+ X-SC-Recurrence-Tag:
637
+ X-SC-Cond: Wed
638
+ X-SC-Duration: 20140409-20140730
639
+ X-SC-Alarm:
640
+ X-SC-Record-Id: FEDA4C97-21C2-46AA-A395-075856FBD5C3
641
+ X-SC-Sequence: 4
642
+
643
+ this is description
644
+ EOF
645
+ end
646
+ end
647
+
648
+ describe RiCal do
649
+ it "creates RiCal::Event form ics string" do
650
+ Mhc.default_tzid = "Asia/Tokyo"
651
+ ics = RiCal.parse_string <<-EOF.strip_heredoc
652
+ BEGIN:VCALENDAR
653
+ BEGIN:VEVENT
654
+ EXDATE;TZID=Asia/Tokyo;VALUE=DATE-TIME:20140514T084000,20140723T084000
655
+ DTEND;TZID=Asia/Tokyo;VALUE=DATE-TIME:20140409T101000
656
+ DTSTART;VALUE=DATE-TIME:20140408T234000Z
657
+ CATEGORIES:Lecture
658
+ UID:FEDA4C97-21C2-46AA-A395-075856FBD5C3
659
+ DESCRIPTION:this is description\n
660
+ SUMMARY:CS1
661
+ RRULE:FREQ=WEEKLY;INTERVAL=1;WKST=MO;BYDAY=WE;UNTIL=20140729T234000Z
662
+ LOCATION:Room11
663
+ SEQUENCE:4
664
+ END:VEVENT
665
+ END:VCALENDAR
666
+ EOF
667
+ iev = ics.first.events.first
668
+ expect(iev.occurrences.first.dtstart.tzid).to eq "UTC"
669
+ end
670
+ end
671
+
672
+ describe Mhc::DateFrame::Yearly do
673
+ end
674
+
675
+ describe Mhc::DateFrame::Monthly do
676
+ end
677
+
678
+ describe Mhc::DateFrame::Weekly do
679
+ end
680
+
681
+ describe Mhc::DateFrame::Daily do
682
+ end