nelumba 0.0.13

Sign up to get free protection for your applications and to get access to all the features.
Files changed (95) hide show
  1. data/.gitignore +6 -0
  2. data/.travis.yml +9 -0
  3. data/Gemfile +20 -0
  4. data/README.md +242 -0
  5. data/Rakefile +7 -0
  6. data/assets/lotus_logo_purple.png +0 -0
  7. data/assets/lotus_logo_purple.svg +262 -0
  8. data/lib/nelumba.rb +47 -0
  9. data/lib/nelumba/activity.rb +250 -0
  10. data/lib/nelumba/application.rb +11 -0
  11. data/lib/nelumba/article.rb +11 -0
  12. data/lib/nelumba/atom/account.rb +50 -0
  13. data/lib/nelumba/atom/address.rb +56 -0
  14. data/lib/nelumba/atom/author.rb +176 -0
  15. data/lib/nelumba/atom/category.rb +41 -0
  16. data/lib/nelumba/atom/comment.rb +96 -0
  17. data/lib/nelumba/atom/entry.rb +216 -0
  18. data/lib/nelumba/atom/feed.rb +198 -0
  19. data/lib/nelumba/atom/generator.rb +40 -0
  20. data/lib/nelumba/atom/link.rb +79 -0
  21. data/lib/nelumba/atom/name.rb +57 -0
  22. data/lib/nelumba/atom/organization.rb +62 -0
  23. data/lib/nelumba/atom/person.rb +179 -0
  24. data/lib/nelumba/atom/portable_contacts.rb +117 -0
  25. data/lib/nelumba/atom/source.rb +179 -0
  26. data/lib/nelumba/atom/thread.rb +60 -0
  27. data/lib/nelumba/audio.rb +39 -0
  28. data/lib/nelumba/badge.rb +11 -0
  29. data/lib/nelumba/binary.rb +52 -0
  30. data/lib/nelumba/bookmark.rb +30 -0
  31. data/lib/nelumba/category.rb +49 -0
  32. data/lib/nelumba/collection.rb +34 -0
  33. data/lib/nelumba/comment.rb +47 -0
  34. data/lib/nelumba/crypto.rb +144 -0
  35. data/lib/nelumba/device.rb +11 -0
  36. data/lib/nelumba/discover.rb +362 -0
  37. data/lib/nelumba/event.rb +57 -0
  38. data/lib/nelumba/feed.rb +173 -0
  39. data/lib/nelumba/file.rb +43 -0
  40. data/lib/nelumba/generator.rb +53 -0
  41. data/lib/nelumba/group.rb +11 -0
  42. data/lib/nelumba/identity.rb +63 -0
  43. data/lib/nelumba/image.rb +30 -0
  44. data/lib/nelumba/link.rb +56 -0
  45. data/lib/nelumba/note.rb +34 -0
  46. data/lib/nelumba/notification.rb +229 -0
  47. data/lib/nelumba/object.rb +251 -0
  48. data/lib/nelumba/person.rb +306 -0
  49. data/lib/nelumba/place.rb +34 -0
  50. data/lib/nelumba/product.rb +30 -0
  51. data/lib/nelumba/publisher.rb +44 -0
  52. data/lib/nelumba/question.rb +30 -0
  53. data/lib/nelumba/review.rb +30 -0
  54. data/lib/nelumba/service.rb +11 -0
  55. data/lib/nelumba/subscription.rb +117 -0
  56. data/lib/nelumba/version.rb +3 -0
  57. data/lib/nelumba/video.rb +43 -0
  58. data/nelumba.gemspec +28 -0
  59. data/spec/activity_spec.rb +116 -0
  60. data/spec/application_spec.rb +136 -0
  61. data/spec/article_spec.rb +136 -0
  62. data/spec/atom/comment_spec.rb +455 -0
  63. data/spec/atom/feed_spec.rb +684 -0
  64. data/spec/audio_spec.rb +164 -0
  65. data/spec/badge_spec.rb +136 -0
  66. data/spec/binary_spec.rb +218 -0
  67. data/spec/bookmark.rb +150 -0
  68. data/spec/collection_spec.rb +152 -0
  69. data/spec/comment_spec.rb +128 -0
  70. data/spec/crypto_spec.rb +126 -0
  71. data/spec/device_spec.rb +136 -0
  72. data/spec/event_spec.rb +239 -0
  73. data/spec/feed_spec.rb +252 -0
  74. data/spec/file_spec.rb +190 -0
  75. data/spec/group_spec.rb +136 -0
  76. data/spec/helper.rb +10 -0
  77. data/spec/identity_spec.rb +67 -0
  78. data/spec/image_spec.rb +150 -0
  79. data/spec/link_spec.rb +30 -0
  80. data/spec/note_spec.rb +163 -0
  81. data/spec/notification_spec.rb +89 -0
  82. data/spec/person_spec.rb +244 -0
  83. data/spec/place_spec.rb +162 -0
  84. data/spec/product_spec.rb +150 -0
  85. data/spec/question_spec.rb +156 -0
  86. data/spec/review_spec.rb +149 -0
  87. data/spec/service_spec.rb +136 -0
  88. data/spec/video_spec.rb +164 -0
  89. data/test/example_feed.atom +393 -0
  90. data/test/example_feed_empty_author.atom +336 -0
  91. data/test/example_feed_false_connected.atom +359 -0
  92. data/test/example_feed_link_without_href.atom +134 -0
  93. data/test/example_page.html +4 -0
  94. data/test/mime_type_bug_feed.atom +874 -0
  95. metadata +288 -0
@@ -0,0 +1,47 @@
1
+ # Base Activity Objects
2
+ require 'nelumba/object'
3
+ require 'nelumba/activity'
4
+ require 'nelumba/collection'
5
+
6
+ # Activity Objects
7
+ require 'nelumba/article'
8
+ require 'nelumba/audio'
9
+ require 'nelumba/badge'
10
+ require 'nelumba/binary'
11
+ require 'nelumba/bookmark'
12
+ require 'nelumba/comment'
13
+ require 'nelumba/device'
14
+ require 'nelumba/event'
15
+ require 'nelumba/file'
16
+ require 'nelumba/group'
17
+ require 'nelumba/image'
18
+ require 'nelumba/note'
19
+ require 'nelumba/place'
20
+ require 'nelumba/question'
21
+ require 'nelumba/review'
22
+ require 'nelumba/service'
23
+ require 'nelumba/video'
24
+
25
+ # Data Structures
26
+ require 'nelumba/feed'
27
+ require 'nelumba/person'
28
+ require 'nelumba/identity'
29
+ require 'nelumba/notification'
30
+ require 'nelumba/link'
31
+
32
+ # Crypto
33
+ require 'nelumba/crypto'
34
+
35
+ # Pub-Sub
36
+ require 'nelumba/subscription'
37
+ require 'nelumba/publisher'
38
+
39
+ # Discovery
40
+ require 'nelumba/discover'
41
+
42
+ # This module contains elements that allow federated interaction. It also
43
+ # contains methods to construct these objects from external sources.
44
+ module Nelumba
45
+ # This module isolates Atom generation.
46
+ module Atom; end
47
+ end
@@ -0,0 +1,250 @@
1
+ module Nelumba
2
+ # This class represents an Activity object that represents an action taken
3
+ # by a Person.
4
+ class Activity
5
+ require 'time-lord/units'
6
+ require 'time-lord/scale'
7
+ require 'time-lord/period'
8
+
9
+ include Nelumba::Object
10
+
11
+ STANDARD_TYPES = [:article, :audio, :bookmark, :comment, :file, :folder,
12
+ :group, :list, :note, :person, :image,
13
+ :place, :playlist, :product, :review, :service, :status,
14
+ :video]
15
+
16
+ # Holds a hash containing the information about interactions where keys
17
+ # are verbs.
18
+ #
19
+ # For instance, it could have a :share key, with a hash containing the
20
+ # number of times it has been shared.
21
+ attr_reader :interactions
22
+
23
+ # The object of this activity.
24
+ attr_reader :object
25
+
26
+ # The type of object for this activity.
27
+ #
28
+ # The field can be a String for uncommon types. Several are standard:
29
+ # :article, :audio, :bookmark, :comment, :file, :folder, :group,
30
+ # :list, :note, :person, :image, :place, :playlist,
31
+ # :product, :review, :service, :video
32
+ attr_reader :type
33
+
34
+ # The action being invoked in this activity.
35
+ #
36
+ # The field can be a String for uncommon verbs. Several are standard:
37
+ # :favorite, :follow, :like, :"make-friend", :join, :play,
38
+ # :post, :save, :share, :tag, :update
39
+ attr_reader :verb
40
+
41
+ # The target of the action.
42
+ attr_reader :target
43
+
44
+ # Holds an Nelumba::Person.
45
+ attr_reader :actor
46
+
47
+ # Holds the source of this entry as an Nelumba::Feed.
48
+ attr_reader :source
49
+
50
+ # Holds an array of related Nelumba::Activity's that this entry is a response
51
+ # to.
52
+ attr_reader :in_reply_to
53
+
54
+ # Holds an array of related Nelumba::Activity's that are replies to this one.
55
+ attr_reader :replies
56
+
57
+ # Holds an array of Nelumba::Person's that have favorited this activity.
58
+ attr_reader :likes
59
+
60
+ # Holds an array of Nelumba::Person's that have shared this activity.
61
+ attr_reader :shares
62
+
63
+ # Holds an array of Nelumba::Person's that are mentioned in this activity.
64
+ attr_reader :mentions
65
+
66
+ # Create a new entry with the given action and object.
67
+ #
68
+ # options:
69
+ # :object => The object of this activity.
70
+ # :type => The type of object for this activity.
71
+ # :target => The target of this activity.
72
+ # :verb => The action of the activity.
73
+ #
74
+ # :actor => An Nelumba::Person responsible for generating this entry.
75
+ # :source => An Nelumba::Feed where this Entry originated. This
76
+ # should be used when an Entry is copied into this feed
77
+ # from another.
78
+ # :published => The DateTime depicting when the entry was originally
79
+ # published.
80
+ # :updated => The DateTime depicting when the entry was modified.
81
+ # :url => The canonical url of the entry.
82
+ # :uid => The unique id that identifies this entry.
83
+ # :in_reply_to => An Nelumba::Entry for which this entry is a response.
84
+ # Or an array of Nelumba::Entry's that this entry is a
85
+ # response to. Use this when this Entry is a reply
86
+ # to an existing Entry.
87
+ def initialize(options = {}, &blk)
88
+ super(options, &blk)
89
+
90
+ @object = options[:object]
91
+
92
+ @type = options[:type]
93
+ if STANDARD_TYPES.map(&:to_s).include? @type
94
+ @type = @type.intern
95
+ end
96
+
97
+ @target = options[:target]
98
+ @verb = options[:verb]
99
+
100
+ @actor = options[:actor]
101
+ @source = options[:source]
102
+ @published = options[:published]
103
+ @updated = options[:updated]
104
+ @url = options[:url]
105
+ @uid = options[:uid]
106
+
107
+ unless options[:in_reply_to].nil? or options[:in_reply_to].is_a?(Array)
108
+ options[:in_reply_to] = [options[:in_reply_to]]
109
+ end
110
+
111
+ @in_reply_to = options[:in_reply_to] || []
112
+ @replies = options[:replies] || []
113
+
114
+ @mentions = options[:mentions] || []
115
+ @likes = options[:likes] || []
116
+ @shares = options[:shares] || []
117
+
118
+ @interactions = options[:interactions] || {}
119
+ end
120
+
121
+ # Returns the number of times the given verb has been used with this
122
+ # Activity.
123
+ def interaction_count(verb)
124
+ hash = self.interactions
125
+ if hash && hash.has_key?(verb)
126
+ hash[verb][:count] || 0
127
+ else
128
+ 0
129
+ end
130
+ end
131
+
132
+ def published_ago_in_words
133
+ TimeLord::Period.new(self.published.to_time, Time.now).to_words
134
+ end
135
+
136
+ def updated_ago_in_words
137
+ TimeLord::Period.new(self.updated.to_time, Time.now).to_words
138
+ end
139
+
140
+ # Returns a hash of all relevant fields.
141
+ def to_hash(scheme = 'https', domain = 'example.org', port = nil)
142
+ {
143
+ :source => self.source,
144
+
145
+ :in_reply_to => self.in_reply_to.dup,
146
+ :replies => self.replies.dup,
147
+
148
+ :mentions => self.mentions.dup,
149
+ :likes => self.likes.dup,
150
+ :shares => self.shares.dup,
151
+
152
+ :object => self.object,
153
+ :target => self.target,
154
+ :actor => self.actor,
155
+ :verb => self.verb,
156
+ :type => self.type,
157
+ }.merge(super(scheme, domain, port))
158
+ end
159
+
160
+ # Returns a string containing the Atom representation of this Activity.
161
+ def to_atom
162
+ require 'nelumba/atom/entry'
163
+
164
+ Nelumba::Atom::Entry.from_canonical(self).to_xml
165
+ end
166
+
167
+ # Returns a hash of all relevant fields with JSON activity streams
168
+ # conventions.
169
+ def to_json_hash(scheme = 'https', domain = 'example.org', port = nil)
170
+ {
171
+ :objectType => "activity",
172
+ :object => @object,
173
+ :actor => @actor,
174
+ :target => @target,
175
+ :type => @type,
176
+ :verb => @verb,
177
+ :source => self.source,
178
+ :in_reply_to => self.in_reply_to.dup,
179
+ :replies => self.replies.dup,
180
+ :mentions => self.mentions.dup,
181
+ :likes => self.likes.dup,
182
+ :shares => self.shares.dup,
183
+ }.merge(super(scheme, domain, port))
184
+ end
185
+
186
+ # Generates a sentence describing this activity in the current or given
187
+ # locale.
188
+ #
189
+ # Usage:
190
+ # # The default locale
191
+ # Nelumba::Activity.new(:verb => :post,
192
+ # :object => Nelumba::Note(:content => "hello"),
193
+ # :actor => Nelumba::Person.new(:name => "wilkie"))
194
+ # .sentence
195
+ # # => "wilkie posted a note"
196
+ #
197
+ # Nelumba::Activity.new(:verb => :follow,
198
+ # :object => Nelumba::Person.new(:name => "carol"),
199
+ # :actor => Nelumba::Person.new(:name => "wilkie"))
200
+ # .sentence
201
+ # # => "wilkie followed carol"
202
+ #
203
+ # # In Spanish
204
+ # Nelumba::Activity.new(:verb => :post,
205
+ # :object => Nelumba::Note(:content => "hello"),
206
+ # :actor => Nelumba::Person.new(:name => "wilkie"))
207
+ # .sentence(:locale => :es)
208
+ # # => "wilkie puso una nota"
209
+ def sentence(options = {})
210
+ object_owner = nil
211
+
212
+ if self.verb == :favorite || self.verb == :share
213
+ if self.object.author
214
+ object_owner = self.object.author.name
215
+ elsif self.object.actor.is_a? Nelumba::Person
216
+ object_owner = self.object.actor.name
217
+ end
218
+ end
219
+
220
+ object = self.type
221
+
222
+ if self.verb == :favorite || self.verb == :share
223
+ if self.object
224
+ object = self.object.type
225
+ end
226
+ end
227
+
228
+ actor = nil
229
+
230
+ if self.actor
231
+ actor = self.actor.preferred_display_name
232
+ end
233
+
234
+ person = nil
235
+
236
+ if self.object.is_a?(Nelumba::Person)
237
+ person = self.object.name
238
+ end
239
+
240
+ Nelumba::I18n.sentence({
241
+ :actor => actor,
242
+ :object => object,
243
+ :object_owner => object_owner,
244
+ :person => person,
245
+ :verb => self.verb,
246
+ :target => self.target ? self.target.preferred_display_name : nil
247
+ }.merge(options))
248
+ end
249
+ end
250
+ end
@@ -0,0 +1,11 @@
1
+ module Nelumba
2
+ class Application
3
+ include Nelumba::Object
4
+
5
+ def to_json_hash
6
+ {
7
+ :objectType => "application"
8
+ }.merge(super)
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ module Nelumba
2
+ class Article
3
+ include Nelumba::Object
4
+
5
+ def to_json_hash
6
+ {
7
+ :objectType => "article"
8
+ }.merge(super)
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,50 @@
1
+ module Nelumba
2
+ require 'atom'
3
+
4
+ module Atom
5
+ # This class represents an PortableContacts Account object.
6
+ class Account
7
+ include ::Atom::Xml::Parseable
8
+
9
+ # The XML namespace the specifies this content.
10
+ POCO_NAMESPACE = 'http://portablecontacts.net/spec/1.0'
11
+
12
+ namespace POCO_NAMESPACE
13
+
14
+ element :domain
15
+ element :username
16
+ element :userid
17
+
18
+ def initialize(o = {})
19
+ case o
20
+ when XML::Reader
21
+ o.read
22
+ parse(o)
23
+ when Hash
24
+ o.each do |k, v|
25
+ if k.to_s.include? '_'
26
+ k = k.to_s.gsub(/_(.)/){"#{$1.upcase}"}.intern
27
+ end
28
+ self.send("#{k.to_s}=", v)
29
+ end
30
+ else
31
+ raise ArgumentError, "Got #{o.class} but expected a Hash or XML::Reader"
32
+ end
33
+
34
+ yield(self) if block_given?
35
+ end
36
+
37
+ def to_hash
38
+ {
39
+ :domain => self.domain,
40
+ :username => self.username,
41
+ :userid => self.userid
42
+ }
43
+ end
44
+
45
+ def to_canonical
46
+ to_hash
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,56 @@
1
+ module Nelumba
2
+ require 'atom'
3
+
4
+ module Atom
5
+ # This class represents an OStatus PortableContacts Address object.
6
+ class Address
7
+ include ::Atom::Xml::Parseable
8
+
9
+ # The XML namespace the specifies this content.
10
+ POCO_NAMESPACE = 'http://portablecontacts.net/spec/1.0'
11
+
12
+ namespace POCO_NAMESPACE
13
+
14
+ element :formatted
15
+ element :streetAddress
16
+ element :locality
17
+ element :region
18
+ element :postalCode
19
+ element :country
20
+
21
+ def initialize(o = {})
22
+ case o
23
+ when XML::Reader
24
+ o.read
25
+ parse(o, :test=>true)
26
+ when Hash
27
+ o.each do |k, v|
28
+ if k.to_s.include? '_'
29
+ k = k.to_s.gsub(/_(.)/){"#{$1.upcase}"}.intern
30
+ end
31
+ self.send("#{k.to_s}=", v)
32
+ end
33
+ else
34
+ raise ArgumentError, "Got #{o.class} but expected a Hash or XML::Reader"
35
+ end
36
+
37
+ yield(self) if block_given?
38
+ end
39
+
40
+ def to_hash
41
+ {
42
+ :formatted => self.formatted,
43
+ :street_address => self.streetAddress,
44
+ :locality => self.locality,
45
+ :region => self.region,
46
+ :postal_code => self.postalCode,
47
+ :country => self.country
48
+ }
49
+ end
50
+
51
+ def to_canonical
52
+ to_hash
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,176 @@
1
+ module Nelumba
2
+ require 'atom'
3
+
4
+ module Atom
5
+ # Holds information about the author of the Feed.
6
+ class Author < ::Atom::Person
7
+ require 'date'
8
+
9
+ include ::Atom::SimpleExtensions
10
+
11
+ # The XML namespace the specifies this content.
12
+ POCO_NAMESPACE = 'http://portablecontacts.net/spec/1.0'
13
+
14
+ # The XML namespace that identifies the conforming specification.
15
+ ACTIVITY_NAMESPACE = 'http://activitystrea.ms/spec/1.0/'
16
+
17
+ add_extension_namespace :activity, ACTIVITY_NAMESPACE
18
+ element 'activity:object-type'
19
+
20
+ namespace ::Atom::NAMESPACE
21
+ element :email
22
+ element :uri
23
+
24
+ elements :links, :class => ::Atom::Link
25
+
26
+ add_extension_namespace :poco, POCO_NAMESPACE
27
+ element 'poco:id'
28
+ element 'poco:organization', :class => Nelumba::Atom::Organization
29
+ element 'poco:address', :class => Nelumba::Atom::Address
30
+ element 'poco:account', :class => Nelumba::Atom::Account
31
+ element 'poco:displayName'
32
+ element 'poco:nickname'
33
+ element 'poco:updated', :class => DateTime, :content_only => true
34
+ element 'poco:published', :class => DateTime, :content_only => true
35
+ element 'poco:birthday', :class => Date, :content_only => true
36
+ element 'poco:anniversary', :class => Date, :content_only => true
37
+ element 'poco:gender'
38
+ element 'poco:note'
39
+ element 'poco:preferredUsername'
40
+
41
+ element 'pronoun'
42
+
43
+ # unfortunately ratom doesn't handle elements with the same local name well.
44
+ # this is a workaround for that.
45
+ attr_writer :name, :poco_name
46
+
47
+ def name
48
+ @name or self[::Atom::NAMESPACE, 'name'].first
49
+ end
50
+
51
+ def poco_name
52
+ return @poco_name if @poco_name
53
+ name = self[POCO_NAMESPACE, 'name'].first
54
+ if name
55
+ name = "<name>#{name}</name>"
56
+ reader = XML::Reader.string(name)
57
+ reader.read
58
+ reader.read
59
+ Nelumba::Atom::Name.new(reader)
60
+ else
61
+ nil
62
+ end
63
+ end
64
+
65
+ def to_xml(*args)
66
+ x = super(true)
67
+
68
+ if self.name
69
+ node = XML::Node.new('name')
70
+ node << self.name
71
+ x << node
72
+ end
73
+
74
+ if self.poco_name
75
+ x << self.poco_name.to_xml(true, root_name = 'poco:name')
76
+ end
77
+
78
+ x
79
+ end
80
+
81
+ def initialize *args
82
+ self.activity_object_type = "http://activitystrea.ms/schema/1.0/person"
83
+ super(*args)
84
+ end
85
+
86
+ # Gives an instance of an Nelumba::Activity that parses the fields
87
+ # having an activity prefix.
88
+ def activity
89
+ Nelumba::Activity.new(self)
90
+ end
91
+
92
+ def self.from_canonical(obj)
93
+ hash = obj.to_hash
94
+ hash.keys.each do |k|
95
+ to_k = k
96
+ if k == :display_name
97
+ to_k = :displayName
98
+ elsif k == :preferred_username
99
+ to_k = :preferredUsername
100
+ end
101
+
102
+ if k == :extended_name
103
+ if hash[:extended_name]
104
+ hash[:"poco_name"] = Nelumba::Atom::Name.new(hash[:extended_name])
105
+ end
106
+ hash.delete :extended_name
107
+ elsif k == :organization
108
+ if hash[:organization]
109
+ hash[:"poco_organization"] = Nelumba::Atom::Organization.new(hash[:organization])
110
+ end
111
+ hash.delete :organization
112
+ elsif k == :address
113
+ if hash[:address]
114
+ hash[:"poco_address"] = Nelumba::Atom::Address.new(hash[:address])
115
+ end
116
+ hash.delete :address
117
+ elsif k == :account
118
+ if hash[:account]
119
+ hash[:"poco_account"] = Nelumba::Atom::Account.new(hash[:account])
120
+ end
121
+ hash.delete :account
122
+ elsif k == :uid
123
+ if hash[:uid]
124
+ hash[:"poco_id"] = hash[:uid]
125
+ end
126
+ hash.delete :uid
127
+ elsif k == :pronoun
128
+ elsif (k != :uri) && (k != :name) && (k != :email)
129
+ hash[:"poco_#{to_k}"] = hash[k]
130
+ hash.delete k
131
+ end
132
+ end
133
+
134
+ # Remove any blank entries
135
+ hash.keys.each do |key|
136
+ if hash[key].nil? || hash[key] == ""
137
+ hash.delete key
138
+ end
139
+ end
140
+
141
+ self.new(hash)
142
+ end
143
+
144
+ def to_canonical
145
+ organization = self.poco_organization
146
+ organization = organization.to_canonical if organization
147
+
148
+ address = self.poco_address
149
+ address = address.to_canonical if address
150
+
151
+ account = self.poco_account
152
+ account = account.to_canonical if account
153
+
154
+ ext_name = self.poco_name
155
+ ext_name = ext_name.to_canonical if ext_name
156
+ Nelumba::Person.new(:uid => self.poco_id,
157
+ :extended_name => ext_name,
158
+ :organization => organization,
159
+ :address => address,
160
+ :account => account,
161
+ :gender => self.poco_gender,
162
+ :note => self.poco_note,
163
+ :nickname => self.poco_nickname,
164
+ :display_name => self.poco_displayName,
165
+ :preferred_username => self.poco_preferredUsername,
166
+ :updated => self.poco_updated,
167
+ :published => self.poco_published,
168
+ :birthday => self.poco_birthday,
169
+ :anniversary => self.poco_anniversary,
170
+ :uri => self.uri,
171
+ :email => self.email,
172
+ :name => self.name)
173
+ end
174
+ end
175
+ end
176
+ end