vpim 0.604 → 0.619

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.
data/CHANGES CHANGED
@@ -1,3 +1,19 @@
1
+ 0.619 - 2008-03-30
2
+
3
+ - Fixed some problems with rescue statements not being specific enough.
4
+
5
+ - Vcard#birthday may now return a DateTime.
6
+
7
+ - Added Vcard#urls
8
+
9
+ - Fixed a mispelled Uri in Vcard#url
10
+
11
+ - Global fix of misspellings of "occurrence"
12
+
13
+ - KAddressBook compatibility fix - allow / in field names, even though it is
14
+ illegal in vCard 3.0.
15
+
16
+
1
17
  0.604 - 2008-03-13
2
18
 
3
19
  - Fixed a bug with lower-case UTF-16 encoded cards not being detected properly.
data/README CHANGED
@@ -36,9 +36,9 @@ subscribe to "vpim-talk":
36
36
 
37
37
  = Thanks
38
38
 
39
- - Ruby Forge: for their generous hosting of this project.
40
- - ZipDX.com: for sponsoring support for FREQ=weekly and BYSETPOS in recurrence
41
- rules.
39
+ - http://RubyForge.org: for their generous hosting of this project.
40
+ - http://ZipDX.com: for sponsoring development of FREQ=weekly and BYSETPOS in
41
+ recurrence rules.
42
42
 
43
43
  = Examples
44
44
 
@@ -117,8 +117,8 @@ end
117
117
 
118
118
  puts
119
119
 
120
- def start_of_first_occurence(t0, t1, e)
121
- e.occurences.each_until(t1).each do |t|
120
+ def start_of_first_occurrence(t0, t1, e)
121
+ e.occurrences.each_until(t1).each do |t|
122
122
  # An event might start before t0, but end after it..., in which case
123
123
  # we are still interested.
124
124
  if (t + (e.duration || 0)) >= t0
@@ -129,7 +129,7 @@ def start_of_first_occurence(t0, t1, e)
129
129
  end
130
130
 
131
131
  all_events.sort! do |lhs, rhs|
132
- start_of_first_occurence(t0, t1, lhs) <=> start_of_first_occurence(t0, t1, rhs)
132
+ start_of_first_occurrence(t0, t1, lhs) <=> start_of_first_occurrence(t0, t1, rhs)
133
133
  end
134
134
 
135
135
  all_events.each do |e|
@@ -145,7 +145,7 @@ all_events.each do |e|
145
145
  end
146
146
 
147
147
  i = 1
148
- e.occurences.each_until(t1).each do |t|
148
+ e.occurrences.each_until(t1).each do |t|
149
149
  # An event might start before t0, but end after it..., in which case
150
150
  # we are still interested.
151
151
  dstr = ''
@@ -61,7 +61,7 @@ class Date
61
61
  # +mon+, and day-of-the-week +wday+.
62
62
  #
63
63
  # The nth, +n+, occurrence of +wday+ within the period will be generated
64
- # (+n+ defaults to 1). If +n+ is positive, the nth occurence from the
64
+ # (+n+ defaults to 1). If +n+ is positive, the nth occurrence from the
65
65
  # beginning of the period will be returned, if negative, the nth occurrence
66
66
  # from the end of the period will be returned.
67
67
  #
@@ -154,7 +154,7 @@ class DateGen
154
154
  # 0-6, where 0 is Sunday).
155
155
  #
156
156
  # If +n+ is specified, only the nth occurrence of +wday+ within the period
157
- # will be generated. If +n+ is positive, the nth occurence from the
157
+ # will be generated. If +n+ is positive, the nth occurrence from the
158
158
  # beginning of the period will be returned, if negative, the nth occurrence
159
159
  # from the end of the period will be returned.
160
160
  #
@@ -25,18 +25,20 @@ module Vpim
25
25
  # need it, contact me and implementation will get on the schedule.
26
26
  module Recurrence
27
27
  # The times this event occurs, as a Vpim::Rrule.
28
- def occurences
28
+ def occurrences
29
29
  start = dtstart
30
30
  unless start
31
- raise ArgumentError, "Components with no DTSTART: don't have occurences!"
31
+ raise ArgumentError, "Components with no DTSTART: don't have occurrences!"
32
32
  end
33
33
  Vpim::Rrule.new(start, propvalue('RRULE'))
34
34
  end
35
35
 
36
+ alias occurences occurrences #:nodoc: backwards compatibility
37
+
36
38
  # Check if this event overlaps with the time period later than or equal to +t0+, but
37
39
  # earlier than +t1+.
38
40
  def occurs_in?(t0, t1)
39
- occurences.each_until(t1).detect { |t| tend = t + (duration || 0); tend > t0 }
41
+ occurrences.each_until(t1).detect { |t| tend = t + (duration || 0); tend > t0 }
40
42
  end
41
43
 
42
44
  def rdates
@@ -15,7 +15,8 @@ module Vpim
15
15
  # 1*(ALPHA / DIGIT / "-")
16
16
  # Note: I think I can add A-Z here, and get rid of the "i" matches elsewhere.
17
17
  # Note: added '_' to allowed because its produced by Notes - X-LOTUS-CHILD_UID
18
- NAME = '[-a-z0-9_]+'
18
+ # Note: added '/' to allowed because its produced by KAddressBook - X-messaging/xmpp-All:
19
+ NAME = '[-a-z0-9_/]+'
19
20
 
20
21
  # <"> <Any character except CTLs, DQUOTE> <">
21
22
  QSTR = '"([^"]*)"'
@@ -51,7 +52,7 @@ module Vpim
51
52
  # time-second = 2 DIGIT
52
53
  # time-secfrac = "," 1*DIGIT
53
54
  # time-zone = "Z" / time-numzone
54
- # time-numzome = sign time-hour [":"] time-minute
55
+ # time-numzone = sign time-hour [":"] time-minute
55
56
  TIME = '(\d\d):?(\d\d):?(\d\d)(\.\d+)?(Z|[-+]\d\d:?\d\d)?'
56
57
 
57
58
  # integer = (["+"] / "-") 1*DIGIT
@@ -111,7 +112,7 @@ module Vpim
111
112
  [$1.to_i, $2.to_i, $3.to_i]
112
113
  end
113
114
 
114
- # Convert a RFC 2425 date into an array of Date objects.
115
+ # Convert a RFC 2425 date into a Date object.
115
116
  def self.decode_date_to_date(v)
116
117
  Date.new(*decode_date(v))
117
118
  end
@@ -174,6 +175,12 @@ module Vpim
174
175
  ]
175
176
  end
176
177
 
178
+ def Vpim.decode_date_time_to_datetime(v) #:nodoc:
179
+ year, month, day, hour, min, sec, secfrac, tz = Vpim.decode_date_time(v)
180
+ # TODO - DateTime understands timezones, so we could decode tz and use it.
181
+ DateTime.civil(year, month, day, hour, min, sec, 0)
182
+ end
183
+
177
184
  # Vpim.decode_boolean
178
185
  #
179
186
  # float
@@ -32,7 +32,7 @@ end
32
32
 
33
33
  module Vpim
34
34
 
35
- # Implements the iCalendar recurence rule syntax. See etc/rrule.txt for the
35
+ # Implements the iCalendar recurrence rule syntax. See etc/rrule.txt for the
36
36
  # syntax description and examples from RFC 2445. The description is pretty
37
37
  # hard to understand, but the examples are more helpful.
38
38
  #
@@ -124,7 +124,7 @@ module Vpim
124
124
  end
125
125
  end
126
126
 
127
- # Return an Enumerable, it's #each() will yield over all occurences up to
127
+ # Return an Enumerable, it's #each() will yield over all occurrences up to
128
128
  # (and not including) time +dountil+.
129
129
  def each_until(dountil)
130
130
  Vpim::Enumerator.new(self, dountil)
@@ -133,7 +133,7 @@ module Vpim
133
133
  # Yields for each +ytime+ in the recurring set of events.
134
134
  #
135
135
  # Warning: the set may be infinite! If you need an upper bound on the
136
- # number of occurences, you need to implement a count, or pass a time,
136
+ # number of occurrences, you need to implement a count, or pass a time,
137
137
  # +dountil+, which will not be iterated past (i.e. all times yielded will be
138
138
  # less than +dountil+).
139
139
  #
@@ -152,7 +152,7 @@ module Vpim
152
152
  end
153
153
  count = 1
154
154
 
155
- # With no recurrence, DTSTART is the only occurence.
155
+ # With no recurrence, DTSTART is the only occurrence.
156
156
  if !@rrule
157
157
  return self
158
158
  end
@@ -171,7 +171,7 @@ module Vpim
171
171
 
172
172
  case @freq
173
173
  #when 'YEARLY' then
174
- # Don't need to keep track of year, all occurences are within t's
174
+ # Don't need to keep track of year, all occurrences are within t's
175
175
  # year.
176
176
  when 'MONTHLY' then days.month = t.month
177
177
  when 'WEEKLY' then #days.month = t.month
@@ -298,7 +298,7 @@ module Vpim
298
298
  end.compact # set positions out of scope will be nil, RFC says ignore them
299
299
  end
300
300
 
301
- # Yield the occurence, if we haven't gone over COUNT, or past UNTIL, or
301
+ # Yield the occurrence, if we haven't gone over COUNT, or past UNTIL, or
302
302
  # past the end of representable time.
303
303
 
304
304
  yset.each do |y|
@@ -446,11 +446,9 @@ module Vpim
446
446
  def decode_date_or_datetime(field) #:nodoc:
447
447
  date = nil
448
448
  begin
449
- date = Vpim.decode_date(field.value_raw)
450
- date = Date.new(*date)
449
+ date = Vpim.decode_date_to_date(field.value_raw)
451
450
  rescue Vpim::InvalidEncodingError
452
- # FIXME - try and decode as DATE-TIME
453
- raise
451
+ date = Vpim.decode_date_time_to_datetime(field.value_raw)
454
452
  end
455
453
  Line.new( field.group, field.name, date )
456
454
  end
@@ -460,7 +458,9 @@ module Vpim
460
458
  return decode_date_or_datetime(field)
461
459
 
462
460
  rescue Vpim::InvalidEncodingError
463
- if field.value =~ /(\d+)-(\d+)-(\d+)/
461
+ # Hack around BDAY dates hat are correct in the month and day, but have
462
+ # some kind of garbage in the year.
463
+ if field.value =~ /^\s*(\d+)-(\d+)-(\d+)\s*$/
464
464
  y = $1.to_i
465
465
  m = $2.to_i
466
466
  d = $3.to_i
@@ -502,7 +502,7 @@ module Vpim
502
502
  end
503
503
 
504
504
  def decode_uri(field) #:nodoc:
505
- Line.new( field.group, field.name, Uri.new(field.value) )
505
+ Line.new( field.group, field.name, Attachment::Uri.new(field.value, nil) )
506
506
  end
507
507
 
508
508
  def decode_agent(field) #:nodoc:
@@ -586,7 +586,11 @@ module Vpim
586
586
 
587
587
  # Return line for a field
588
588
  def f2l(field) #:nodoc:
589
- Line.decode(@@decode, self, field) rescue nil
589
+ begin
590
+ Line.decode(@@decode, self, field)
591
+ rescue InvalidEncodingError
592
+ # Skip invalidly encoded fields.
593
+ end
590
594
  end
591
595
 
592
596
  # With no block, returns an Array of Line. If +name+ is specified, the
@@ -769,7 +773,10 @@ module Vpim
769
773
  end
770
774
 
771
775
  if fields.first
772
- line = Line.decode(@@decode, self, fields.first) rescue nil
776
+ line = begin
777
+ Line.decode(@@decode, self, fields.first)
778
+ rescue Vpim::InvalidEncodingError
779
+ end
773
780
 
774
781
  if line
775
782
  return line.value
@@ -955,11 +962,16 @@ module Vpim
955
962
 
956
963
  ## UID
957
964
 
958
- # The URL value, a Uri. A wrapper around #value('NOTE').
965
+ # The URL value, a Attachment::Uri. A wrapper around #value('URL').
959
966
  def url
960
967
  value('URL')
961
968
  end
962
969
 
970
+ # The URL values, an Attachment::Uri. A wrapper around #values('URL').
971
+ def urls
972
+ values('URL')
973
+ end
974
+
963
975
  # The VERSION multiplied by 10 as an Integer. For example, a VERSION:2.1
964
976
  # vCard would have a version of 21, and a VERSION:3.0 vCard would have a
965
977
  # version of 30.
@@ -7,9 +7,9 @@
7
7
  =end
8
8
 
9
9
  module Vpim
10
- PRODID = '-//Ensemble Independent//vPim 0.604//EN'
10
+ PRODID = '-//Ensemble Independent//vPim 0.619//EN'
11
11
 
12
- VERSION = '0.604'
12
+ VERSION = '0.619'
13
13
 
14
14
  # Return the API version as a string.
15
15
  def Vpim.version
@@ -94,7 +94,7 @@ ARGV.each do |file|
94
94
  puts "Organized by: #{e.organizer.to_s}"
95
95
 
96
96
  # TODO - spec as hours/mins/secs
97
- e.occurences.each_with_index do |t, i|
97
+ e.occurrences.each_with_index do |t, i|
98
98
  if(i < 1)
99
99
  puts "At time: #{t}" +( e.duration ? " for #{Duration.secs(e.duration).to_s}" : '' )
100
100
  else
@@ -155,7 +155,7 @@ def puts_properties(c)
155
155
  end
156
156
 
157
157
  begin
158
- c.occurences.each_with_index do |t, i|
158
+ c.occurrences.each_with_index do |t, i|
159
159
  if(i < 10)
160
160
  puts " #{i+1} -> #{t}"
161
161
  else
@@ -164,7 +164,7 @@ def puts_properties(c)
164
164
  end
165
165
  end
166
166
  rescue ArgumentError
167
- # No occurences.
167
+ # No occurrences.
168
168
  end
169
169
 
170
170
  end
@@ -117,8 +117,8 @@ end
117
117
 
118
118
  puts
119
119
 
120
- def start_of_first_occurence(t0, t1, e)
121
- e.occurences.each_until(t1).each do |t|
120
+ def start_of_first_occurrence(t0, t1, e)
121
+ e.occurrences.each_until(t1).each do |t|
122
122
  # An event might start before t0, but end after it..., in which case
123
123
  # we are still interested.
124
124
  if (t + (e.duration || 0)) >= t0
@@ -129,7 +129,7 @@ def start_of_first_occurence(t0, t1, e)
129
129
  end
130
130
 
131
131
  all_events.sort! do |lhs, rhs|
132
- start_of_first_occurence(t0, t1, lhs) <=> start_of_first_occurence(t0, t1, rhs)
132
+ start_of_first_occurrence(t0, t1, lhs) <=> start_of_first_occurrence(t0, t1, rhs)
133
133
  end
134
134
 
135
135
  all_events.each do |e|
@@ -145,7 +145,7 @@ all_events.each do |e|
145
145
  end
146
146
 
147
147
  i = 1
148
- e.occurences.each_until(t1).each do |t|
148
+ e.occurrences.each_until(t1).each do |t|
149
149
  # An event might start before t0, but end after it..., in which case
150
150
  # we are still interested.
151
151
  dstr = ''
@@ -100,6 +100,25 @@ ___
100
100
  assert_equal(icstodo, cal.to_s)
101
101
  end
102
102
 
103
+ # Tracker #18920
104
+ def test_recurring_todos
105
+ icstodo =<<___
106
+ BEGIN:VCALENDAR
107
+ VERSION:2.0
108
+ BEGIN:VTODO
109
+ SUMMARY:todo
110
+ DTSTART:20040415T120000
111
+ RRULE:FREQ=WEEKLY;COUNT=2
112
+ END:VTODO
113
+ END:VCALENDAR
114
+ ___
115
+
116
+ cal = Icalendar.decode(icstodo).first
117
+ todo = cal.todos.first
118
+ assert(todo)
119
+ assert_equal(todo.occurrences.to_a.size, 2)
120
+ end
121
+
103
122
  def test_1
104
123
  req = Icalendar.decode(Req_1).first
105
124
 
@@ -214,7 +214,7 @@ VEC
214
214
  )
215
215
  end
216
216
 
217
- def test_rfc2445_examples_weekly_for_10_occurences
217
+ def test_rfc2445_examples_weekly_for_10_occurrences
218
218
  # Weekly for 10 occurrences
219
219
  #
220
220
  # DTSTART;TZID=US-Eastern:19970902T090000
@@ -16,7 +16,7 @@ def assert_equal_nospace(expected, got)
16
16
  end
17
17
 
18
18
 
19
- # Test cases: multiple occurences of type
19
+ # Test cases: multiple occurrences of type
20
20
  =begin
21
21
  begin:VCARD
22
22
  version:2.1
@@ -743,6 +743,65 @@ ___
743
743
 
744
744
  end
745
745
 
746
+ def test_slash_in_field_name
747
+ cin = <<___
748
+ BEGIN:VCARD
749
+ X-messaging/xmpp-All:some@jabber.id
750
+ END:VCARD
751
+ ___
752
+
753
+ card = Vpim::Vcard.decode(cin).first
754
+ assert_equal(card.value("X-messaging/xmpp-All"), "some@jabber.id")
755
+ assert_equal(card["X-messaging/xmpp-All"], "some@jabber.id")
756
+ end
757
+
758
+ def test_url_decode
759
+ cin=<<'---'
760
+ BEGIN:VCARD
761
+ URL:www.email.com
762
+ URL:www.work.com
763
+ END:VCARD
764
+ ---
765
+ card = Vpim::Vcard.decode(cin).first
766
+
767
+ assert_equal("www.email.com", card.url.uri)
768
+ assert_equal("www.email.com", card.url.uri.to_s)
769
+ assert_equal("www.email.com", card.urls.first.uri)
770
+ assert_equal("www.work.com", card.urls.last.uri)
771
+ end
772
+
773
+ def test_bday_decode
774
+ cin=<<'---'
775
+ BEGIN:VCARD
776
+ BDAY:1970-07-14
777
+ END:VCARD
778
+ ---
779
+ card = Vpim::Vcard.decode(cin).first
780
+
781
+ card.birthday
782
+
783
+ assert_equal(Date.new(1970, 7, 14), card.birthday)
784
+ assert_equal(1, card.values("bday").size)
785
+
786
+ # Nobody should have multiple bdays, I hope, but its allowed syntactically,
787
+ # so test it, along with some variant forms of BDAY
788
+ cin=<<'---'
789
+ BEGIN:VCARD
790
+ BDAY:1970-07-14
791
+ BDAY:70-7-14
792
+ BDAY:1970-07-15T03:45:12
793
+ BDAY:1970-07-15T03:45:12Z
794
+ END:VCARD
795
+ ---
796
+ card = Vpim::Vcard.decode(cin).first
797
+
798
+ assert_equal(Date.new(1970, 7, 14), card.birthday)
799
+ assert_equal(4, card.values("bday").size)
800
+ assert_equal(Date.new(1970, 7, 14), card.values("bday").first)
801
+ assert_equal(Date.new(Time.now.year, 7, 14), card.values("bday")[1])
802
+ assert_equal(DateTime.new(1970, 7, 15, 3, 45, 12).to_s, card.values("bday")[2].to_s)
803
+ assert_equal(DateTime.new(1970, 7, 15, 3, 45, 12).to_s, card.values("bday").last.to_s)
804
+ end
746
805
 
747
806
  def utf_name_test(c)
748
807
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: vpim
3
3
  version: !ruby/object:Gem::Version
4
- version: "0.604"
4
+ version: "0.619"
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sam Roberts
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2008-03-13 00:00:00 -07:00
12
+ date: 2008-03-30 00:00:00 -07:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -22,7 +22,7 @@ dependencies:
22
22
  version: "0"
23
23
  version:
24
24
  description: This is a pure-ruby library for decoding and encoding vCard and iCalendar data ("personal information") called vPim.
25
- email: viextech+vpimgem@rubyforge.org
25
+ email: vieuxtech@gmail.com
26
26
  executables:
27
27
  - reminder
28
28
  - rrule