Sam Roberts
2006-Feb-23 07:37 UTC
[Vpim-talk] vcard ruby lib, trailing spaces problem and other questions
Quoting justin at kiko.com, on Wed, Feb 22, 2006 at 10:11:59PM -0500:> Thanks for the great work on the vcard ruby library. One thing I found > you might want to add: when I tried to use the library to decode a > vcard from plaxo, it errored due to the fact that plaxo left a > trailing space after "BEGIN: VCARD " and which wasn''t present at the > "END: VCARD", causing the check that makes sure the tags are the same > to fail. You could easily fix this by changing the value? function in > field.rb to strip whitespace: > > # Is the value of this field +value+? The check is case insensitive. > def value?(value) > @value && @value.downcase.strip == value.downcase.strip > end > > Also, I was just wondering, is there any reason there is a special > accessor function for nickname, but none for any of the other fields? > Thanks,Thanks for your feedback. The two issues are related, surprisingly. Its unusual to have whitespace on either side of a field value in vCards. I''m not even entirely sure it is valid. I had trouble with Nickname values that were entirely whitespace, which is why I wrote Vcard at nickname. I changed the decoder so that at a fairly low level it now strips whitespace from both sides of a value. I''ll rerelease sometime in the next week. That makes the #value? work as it is, and also allows me to remove much of Vcard#nickname''s implementation. It''s a bit of a hack, but I try to add useful APIs based on my experience, and other people''s request. For this: BEGIN:vcard ... NICKNAME: END:vcard card.nickname => nil card["nickname"] => "" It allows me to treat a Nickname with no value as if it wasn''t there, which was useful to me. Its kind of a special case... or maybe it isn''t? Maybe I should discard any field that doesn''t have a value? But what about: X-Always-Authenticate;key=priv.pem: Its possible that all the necessary information is in the field name and params, so maybe its not such a good idea for me to pretend fields aren''t there. But on the other hand, the array index [] API only returns values, not fields, maybe it should skip over fields that don''t have values. The vCard format is incredibly flexible, more than most people need, I''m sure. The thing is, I''m not sure what of the features are being used, so I''m not eager to make some too-easy-to-use API, that turns out to be useless to people because it doesn''t reflect the complexity of real world cards. For example, I get requests for these APIs fairly frequently Vcard#email => String Vcard#name => String But vCards can and do have many email addresses, they can even be UUCP email addresses, which one do they want? And it has two fields for name, different formats, but both mandatory! If you work with the API a little, and have any suggestions on new APIs, or things that surprised you, I''d like to know. Oh, and you ask why #nickname but no others. Actually, there is #nickname, #birthday, and #version. Version is mandatory and you can only have one, so I can implement. There is nothing in the spec saying you can''t have the BDAY field more than once, but I think most people only have one, and I wanted to convert it to a Date. As for NICKNAME, you can have multiple NICKNAME fields, the API as it is will only return the first. I''m waiting for a bug report, actually. Maybe I should make it return an array of nicknames. So, thats a really long answer. I''ve just started to relook at reworking the API to make it easier to use based on my experience over the last year or so, but mostly I add things as I need them, or as people make suggestions, so please make suggestions! Sam -------------- next part -------------- Index: lib/vpim/vcard.rb ==================================================================--- lib/vpim/vcard.rb (revision 287) +++ lib/vpim/vcard.rb (working copy) @@ -150,10 +150,15 @@ def [](name, type=nil) fields = enum_by_name(name).find_all { |f| type == nil || f.type?(type) } + valued = fields.select { |f| f.value != '''' } + if valued.first + fields = valued + end + # limit to preferred, if possible - pref = fields.find_all { |f| f.pref? } + pref = fields.select { |f| f.pref? } - if(pref.first) + if pref.first fields = pref end @@ -163,10 +168,8 @@ # The nickname or nil if there is none. def nickname nn = self[''nickname''] - if nn - nn = nn.sub(/^\s+/, '''') - nn = nn.sub(/\s+$/, '''') - nn = nil if nn == '''' + if nn && nn == '''' + nn = nil end nn end Index: lib/vpim/field.rb ==================================================================--- lib/vpim/field.rb (revision 287) +++ lib/vpim/field.rb (working copy) @@ -105,6 +105,11 @@ paramslist = $3 atvalue = $~[-1] + # I''ve seen space that shouldn''t be there, as in "BEGIN:VCARD ", so + # strip it. I''m not absolutely sure this is allowed... it certainly + # breaks round-trip encoding. + atvalue.strip! + if atgroup.length > 0 atgroup.chomp!(''.'') else Index: lib/vpim/dirinfo.rb ==================================================================--- lib/vpim/dirinfo.rb (revision 287) +++ lib/vpim/dirinfo.rb (working copy) @@ -100,6 +100,7 @@ # The value of the first field named +name+, or nil if no # match is found. def [](name) + enum_by_name(name).each { |f| return f.value if f.value != ''''} enum_by_name(name).each { |f| return f.value } nil end