Class: Vcard::Vcard::Maker
- Inherits:
-
Object
- Object
- Vcard::Vcard::Maker
- Defined in:
- lib/vcard/vcard.rb
Overview
A class to make and make changes to vCards.
It can be used to create completely new vCards using Vcard#make2.
Its is also yielded from Vcard::Vcard#make, in which case it allows a kind of transactional approach to changing vCards, so their values can be validated after any changes have been made.
Examples:
-
ex_mkvcard.txt: example of creating a vCard
-
ex_cpvcard.txt: example of copying and them modifying a vCard
-
ex_mkv21vcard.txt: example of creating version 2.1 vCard
-
ex_mkyourown.txt: example of adding support for new fields to Vcard::Maker
Class Method Summary collapse
-
.make(full_name = nil, &block) ⇒ Object
Deprecated, use #make2.
-
.make2(card = ::Vcard::Vcard.create, &block) ⇒ Object
Make a vCard.
Instance Method Summary collapse
-
#add_addr {|x| ... } ⇒ Object
Add an address field, ADR.
-
#add_email(email) ⇒ Object
Add an email field, EMAIL.
-
#add_field(field) ⇒ Object
Add a Field,
field
. -
#add_impp(url) ⇒ Object
Add an instant-messaging/point of presence address field, IMPP.
-
#add_note(note) ⇒ Object
Add a note field, NOTE.
-
#add_photo {|x| ... } ⇒ Object
Add a photo field, PHOTO.
-
#add_role(role) ⇒ Object
Add a role field, ROLE.
-
#add_tel(number) ⇒ Object
Add a telephone field, TEL.
-
#add_url(url) ⇒ Object
Add a URL field, URL.
-
#add_x_aim(xaim) ⇒ Object
Add an X-AIM account name where
xaim
is an AIM screen name. -
#birthday=(birthday) ⇒ Object
Add a birthday field, BDAY.
-
#copy(card) ⇒ Object
Copy the fields from
card
into self using #add_field. -
#delete_if ⇒ Object
Delete
line
if block yields true. -
#fullname=(fullname) ⇒ Object
Deprecated, see #name.
-
#make {|_self| ... } ⇒ Object
:nodoc:.
-
#name {|x| ... } ⇒ Object
(also: #add_name)
Set the name fields, N and FN.
-
#nickname=(nickname) ⇒ Object
Set the nickname field, NICKNAME.
-
#org=(org) ⇒ Object
Set the org field, ORG.
-
#title=(title) ⇒ Object
Set the title field, TITLE.
Class Method Details
.make(full_name = nil, &block) ⇒ Object
Deprecated, use #make2.
If set, the FN field will be set to full_name
. Otherwise, FN will be set from the values in #name.
1026 1027 1028 |
# File 'lib/vcard/vcard.rb', line 1026 def self.make(full_name = nil, &block) # :yields: maker new(full_name, ::Vcard::Vcard.create).make(&block) end |
.make2(card = ::Vcard::Vcard.create, &block) ⇒ Object
Make a vCard.
Yields maker
, a Vcard::Vcard::Maker which allows fields to be added to card
, and returns card
, a Vcard::Vcard.
If card
is nil or not provided a new Vcard::Vcard is created and the fields are added to it.
Defaults:
-
vCards must have both an N and an FN field, #make2 will fail if there is no N field in the
card
when your block is finished adding fields. -
If there is an N field, but no FN field, FN will be set from the information in N, see Vcard::Name#preformatted for more information.
-
vCards must have a VERSION field. If one does not exist when your block is is finished it will be set to 3.0.
1018 1019 1020 |
# File 'lib/vcard/vcard.rb', line 1018 def self.make2(card = ::Vcard::Vcard.create, &block) # :yields: maker new(nil, card).make(&block) end |
Instance Method Details
#add_addr {|x| ... } ⇒ Object
Add an address field, ADR. address
is a Vcard::Vcard::Address.
1114 1115 1116 1117 1118 1119 |
# File 'lib/vcard/vcard.rb', line 1114 def add_addr # :yield: address x = ::Vcard::Vcard::Address.new yield x @card << x.encode self end |
#add_email(email) ⇒ Object
Add an email field, EMAIL. email
is a Vcard::Vcard::Email.
The block is optional, its only necessary if you want to specify the optional attributes.
1138 1139 1140 1141 1142 1143 1144 1145 |
# File 'lib/vcard/vcard.rb', line 1138 def add_email(email) # :yield: email x = ::Vcard::Vcard::Email.new(email) if block_given? yield x end @card << x.encode self end |
#add_field(field) ⇒ Object
Add a Field, field
.
1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 |
# File 'lib/vcard/vcard.rb', line 1333 def add_field(field) fieldname = field.name.upcase case when [ "BEGIN", "END" ].include?(fieldname) raise ::Vcard::InvalidEncodingError, "Not allowed to manually add #{field.name} to a vCard." when [ "VERSION", "N", "FN" ].include?(fieldname) if @card.field(fieldname) raise ::Vcard::InvalidEncodingError, "Not allowed to add more than one #{fieldname} to a vCard." end @card << field else @card << field end end |
#add_impp(url) ⇒ Object
Add an instant-messaging/point of presence address field, IMPP. The address is a URL, with the syntax depending on the protocol.
Attributes of IMPP are:
-
preferred: true - set if this is the preferred address
-
location: home, work, mobile - location of address
-
purpose: personal,business - purpose of communications
All attributes are optional, and so is the block.
The URL syntaxes for the messaging schemes is fairly complicated, so I don’t try and build the URLs here, maybe in the future. This forces the user to know the URL for their own address, hopefully not too much of a burden.
IMPP is defined in draft-jennings-impp-vcard-04.txt. It refers to the URI scheme of a number of messaging protocols, but doesn’t give references to all of them:
-
“xmpp” indicates to use XMPP, draft-saintandre-xmpp-uri-06.txt
-
“irc” or “ircs” indicates to use IRC, draft-butcher-irc-url-04.txt
-
“sip” indicates to use SIP/SIMPLE, RFC 3261
-
“im” or “pres” indicates to use a CPIM or CPP gateway, RFC 3860 and RFC 3859
-
“ymsgr” indicates to use yahoo
-
“msn” might indicate to use Microsoft messenger
-
“aim” indicates to use AOL
1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 |
# File 'lib/vcard/vcard.rb', line 1202 def add_impp(url) # :yield: impp params = {} if block_given? x = Struct.new( :location, :preferred, :purpose ).new yield x x[:preferred] = "PREF" if x[:preferred] types = x.to_a.flatten.compact.map { |s| s.downcase }.uniq params["TYPE"] = types if types.first end @card << ::Vcard::DirectoryInfo::Field.create( "IMPP", url, params) self end |
#add_note(note) ⇒ Object
Add a note field, NOTE. The note
String can contain newlines, they will be escaped.
1172 1173 1174 |
# File 'lib/vcard/vcard.rb', line 1172 def add_note(note) @card << ::Vcard::DirectoryInfo::Field.create( "NOTE", ::Vcard.encode_text(note) ); end |
#add_photo {|x| ... } ⇒ Object
Add a photo field, PHOTO.
Attributes of PHOTO are:
-
image: set to image data to include inline
-
link: set to the URL of the image data
-
type: string identifying the image type, supposed to be an “IANA registered image format”,
or a non-registered image format (usually these start with an x-)
An error will be raised if neither image or link is set, or if both image and link is set.
Setting type is optional for a link image, because either the URL, the image file extension, or a HTTP Content-Type may specify the type. If it’s not a link, setting type is mandatory, though it can be set to an empty string, ''
, if the type is unknown.
TODO - I’m not sure about this API. I’m thinking maybe it should be #add_photo(image, type), and that I should detect when the image is a URL, and make type mandatory if it wasn’t a URL.
1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 |
# File 'lib/vcard/vcard.rb', line 1271 def add_photo # :yield: photo x = Struct.new(:image, :link, :type).new yield x if x[:image] && x[:link] raise ::Vcard::InvalidEncodingError, "Image is not allowed to be both inline and a link." end value = x[:image] || x[:link] if !value raise ::Vcard::InvalidEncodingError, "A image link or inline data must be provided." end params = {} # Don't set type to the empty string. params["TYPE"] = x[:type] if( x[:type] && x[:type].length > 0 ) if x[:link] params["VALUE"] = "URI" else # it's inline, base-64 encode it params["ENCODING"] = :b64 if !x[:type] raise ::Vcard::InvalidEncodingError, "Inline image data must have it's type set." end end @card << ::Vcard::DirectoryInfo::Field.create( "PHOTO", value, params ) self end |
#add_role(role) ⇒ Object
Add a role field, ROLE.
It can be set to a single String.
1323 1324 1325 |
# File 'lib/vcard/vcard.rb', line 1323 def add_role(role) @card << ::Vcard::DirectoryInfo::Field.create("ROLE", ::Vcard.encode_text(role)); end |
#add_tel(number) ⇒ Object
Add a telephone field, TEL. tel
is a Vcard::Vcard::Telephone.
The block is optional, its only necessary if you want to specify the optional attributes.
1125 1126 1127 1128 1129 1130 1131 1132 |
# File 'lib/vcard/vcard.rb', line 1125 def add_tel(number) # :yield: tel x = ::Vcard::Vcard::Telephone.new(number) if block_given? yield x end @card << x.encode self end |
#add_url(url) ⇒ Object
Add a URL field, URL.
1328 1329 1330 |
# File 'lib/vcard/vcard.rb', line 1328 def add_url(url) @card << ::Vcard::DirectoryInfo::Field.create( "URL", url.to_str ); end |
#add_x_aim(xaim) ⇒ Object
Add an X-AIM account name where xaim
is an AIM screen name.
I don’t know if this is conventional, or supported by anything other than AddressBook.app, but an example is:
X-AIM;type=HOME;type=pref:exampleaccount
Attributes of X-AIM are:
-
preferred: true - set if this is the preferred address
-
location: home, work, mobile - location of address
All attributes are optional, and so is the block.
1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 |
# File 'lib/vcard/vcard.rb', line 1232 def add_x_aim(xaim) # :yield: xaim params = {} if block_given? x = Struct.new( :location, :preferred ).new yield x x[:preferred] = "PREF" if x[:preferred] types = x.to_a.flatten.compact.map { |s| s.downcase }.uniq params["TYPE"] = types if types.first end @card << ::Vcard::DirectoryInfo::Field.create( "X-AIM", xaim, params) self end |
#birthday=(birthday) ⇒ Object
Add a birthday field, BDAY.
birthday
must be a time or date object.
Warning: It may confuse both humans and software if you add multiple birthdays.
1162 1163 1164 1165 1166 1167 1168 |
# File 'lib/vcard/vcard.rb', line 1162 def birthday=(birthday) if !birthday.respond_to? :month raise ArgumentError, "birthday must be a date or time object." end delete_if { |l| l.name == "BDAY" } @card << ::Vcard::DirectoryInfo::Field.create( "BDAY", birthday ); end |
#copy(card) ⇒ Object
Copy the fields from card
into self using #add_field. If a block is provided, each Field from card
is yielded. The block should return a Field to add, or nil. The Field doesn’t have to be the one yielded, allowing the field to be copied and modified (see Field#copy) before adding, or not added at all if the block yields nil.
The vCard fields BEGIN and END aren’t copied, and VERSION, N, and FN are copied only if the card doesn’t have them already.
1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 |
# File 'lib/vcard/vcard.rb', line 1358 def copy(card) # :yields: Field card.each do |field| fieldname = field.name.upcase case when [ "BEGIN", "END" ].include?(fieldname) # Never copy these when [ "VERSION", "N", "FN" ].include?(fieldname) && @card.field(fieldname) # Copy these only if they don't already exist. else if block_given? field = yield field end if field add_field(field) end end end end |
#delete_if ⇒ Object
Delete line
if block yields true.
1381 1382 1383 1384 1385 1386 1387 1388 |
# File 'lib/vcard/vcard.rb', line 1381 def delete_if #:yield: line @card.delete_if do |line| yield line end rescue NoMethodError # FIXME - this is a hideous hack, allowing a DirectoryInfo to # be passed instead of a Vcard, and for it to almost work. Yuck. end |
#fullname=(fullname) ⇒ Object
Deprecated, see #name.
Use
maker.name do |n| n.fullname = "foo" end
to set just fullname, or set the other fields to set fullname and the name.
1066 1067 1068 1069 1070 1071 |
# File 'lib/vcard/vcard.rb', line 1066 def fullname=(fullname) #:nodoc: bacwards compat if @card.field("FN") raise ::Vcard::InvalidEncodingError, "Not allowed to add more than one FN field to a vCard." end @card << ::Vcard::DirectoryInfo::Field.create( "FN", fullname ); end |
#make {|_self| ... } ⇒ Object
:nodoc:
1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 |
# File 'lib/vcard/vcard.rb', line 1030 def make # :nodoc: yield self unless @card["N"] raise ::Vcard::Unencodeable, "N field is mandatory" end fn = @card.field("FN") if fn && fn.value.strip.length == 0 @card.delete(fn) fn = nil end unless fn @card << ::Vcard::DirectoryInfo::Field.create("FN", ::Vcard::Vcard::Name.new(@card["N"], "").formatted) end unless @card["VERSION"] @card << ::Vcard::DirectoryInfo::Field.create("VERSION", "3.0") end @card end |
#name {|x| ... } ⇒ Object Also known as: add_name
Set the name fields, N and FN.
Attributes of name
are:
-
family: family name
-
given: given name
-
additional: additional names
-
prefix: such as “Ms.” or “Dr.”
-
suffix: such as “BFA”, or “Sensei”
name
is a Vcard::Name.
All attributes are optional, though have all names be zero-length strings isn’t really in the spirit of things. FN’s value will be set to Vcard::Name#formatted if Vcard::Name#fullname isn’t given a specific value.
Warning: This is the only mandatory field.
1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 |
# File 'lib/vcard/vcard.rb', line 1090 def name #:yield:name x = begin @card.name.dup rescue ::Vcard::Vcard::Name.new end yield x x.fullname.strip! delete_if do |line| line.name == "N" end @card << x.encode @card << x.encode_fn self end |
#nickname=(nickname) ⇒ Object
Set the nickname field, NICKNAME.
It can be set to a single String or an Array of String.
1150 1151 1152 1153 1154 |
# File 'lib/vcard/vcard.rb', line 1150 def nickname=(nickname) delete_if { |l| l.name == "NICKNAME" } @card << ::Vcard::DirectoryInfo::Field.create( "NICKNAME", nickname ); end |
#org=(org) ⇒ Object
Set the org field, ORG.
It can be set to a single String or an Array of String.
1314 1315 1316 1317 1318 |
# File 'lib/vcard/vcard.rb', line 1314 def org=(org) delete_if { |l| l.name == "ORG" } @card << ::Vcard::DirectoryInfo::Field.create( "ORG", org ); end |
#title=(title) ⇒ Object
Set the title field, TITLE.
It can be set to a single String.
1305 1306 1307 1308 1309 |
# File 'lib/vcard/vcard.rb', line 1305 def title=(title) delete_if { |l| l.name == "TITLE" } @card << ::Vcard::DirectoryInfo::Field.create( "TITLE", title ); end |