vpim 0.604 → 0.619

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