nelumba 0.0.13
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/.gitignore +6 -0
- data/.travis.yml +9 -0
- data/Gemfile +20 -0
- data/README.md +242 -0
- data/Rakefile +7 -0
- data/assets/lotus_logo_purple.png +0 -0
- data/assets/lotus_logo_purple.svg +262 -0
- data/lib/nelumba.rb +47 -0
- data/lib/nelumba/activity.rb +250 -0
- data/lib/nelumba/application.rb +11 -0
- data/lib/nelumba/article.rb +11 -0
- data/lib/nelumba/atom/account.rb +50 -0
- data/lib/nelumba/atom/address.rb +56 -0
- data/lib/nelumba/atom/author.rb +176 -0
- data/lib/nelumba/atom/category.rb +41 -0
- data/lib/nelumba/atom/comment.rb +96 -0
- data/lib/nelumba/atom/entry.rb +216 -0
- data/lib/nelumba/atom/feed.rb +198 -0
- data/lib/nelumba/atom/generator.rb +40 -0
- data/lib/nelumba/atom/link.rb +79 -0
- data/lib/nelumba/atom/name.rb +57 -0
- data/lib/nelumba/atom/organization.rb +62 -0
- data/lib/nelumba/atom/person.rb +179 -0
- data/lib/nelumba/atom/portable_contacts.rb +117 -0
- data/lib/nelumba/atom/source.rb +179 -0
- data/lib/nelumba/atom/thread.rb +60 -0
- data/lib/nelumba/audio.rb +39 -0
- data/lib/nelumba/badge.rb +11 -0
- data/lib/nelumba/binary.rb +52 -0
- data/lib/nelumba/bookmark.rb +30 -0
- data/lib/nelumba/category.rb +49 -0
- data/lib/nelumba/collection.rb +34 -0
- data/lib/nelumba/comment.rb +47 -0
- data/lib/nelumba/crypto.rb +144 -0
- data/lib/nelumba/device.rb +11 -0
- data/lib/nelumba/discover.rb +362 -0
- data/lib/nelumba/event.rb +57 -0
- data/lib/nelumba/feed.rb +173 -0
- data/lib/nelumba/file.rb +43 -0
- data/lib/nelumba/generator.rb +53 -0
- data/lib/nelumba/group.rb +11 -0
- data/lib/nelumba/identity.rb +63 -0
- data/lib/nelumba/image.rb +30 -0
- data/lib/nelumba/link.rb +56 -0
- data/lib/nelumba/note.rb +34 -0
- data/lib/nelumba/notification.rb +229 -0
- data/lib/nelumba/object.rb +251 -0
- data/lib/nelumba/person.rb +306 -0
- data/lib/nelumba/place.rb +34 -0
- data/lib/nelumba/product.rb +30 -0
- data/lib/nelumba/publisher.rb +44 -0
- data/lib/nelumba/question.rb +30 -0
- data/lib/nelumba/review.rb +30 -0
- data/lib/nelumba/service.rb +11 -0
- data/lib/nelumba/subscription.rb +117 -0
- data/lib/nelumba/version.rb +3 -0
- data/lib/nelumba/video.rb +43 -0
- data/nelumba.gemspec +28 -0
- data/spec/activity_spec.rb +116 -0
- data/spec/application_spec.rb +136 -0
- data/spec/article_spec.rb +136 -0
- data/spec/atom/comment_spec.rb +455 -0
- data/spec/atom/feed_spec.rb +684 -0
- data/spec/audio_spec.rb +164 -0
- data/spec/badge_spec.rb +136 -0
- data/spec/binary_spec.rb +218 -0
- data/spec/bookmark.rb +150 -0
- data/spec/collection_spec.rb +152 -0
- data/spec/comment_spec.rb +128 -0
- data/spec/crypto_spec.rb +126 -0
- data/spec/device_spec.rb +136 -0
- data/spec/event_spec.rb +239 -0
- data/spec/feed_spec.rb +252 -0
- data/spec/file_spec.rb +190 -0
- data/spec/group_spec.rb +136 -0
- data/spec/helper.rb +10 -0
- data/spec/identity_spec.rb +67 -0
- data/spec/image_spec.rb +150 -0
- data/spec/link_spec.rb +30 -0
- data/spec/note_spec.rb +163 -0
- data/spec/notification_spec.rb +89 -0
- data/spec/person_spec.rb +244 -0
- data/spec/place_spec.rb +162 -0
- data/spec/product_spec.rb +150 -0
- data/spec/question_spec.rb +156 -0
- data/spec/review_spec.rb +149 -0
- data/spec/service_spec.rb +136 -0
- data/spec/video_spec.rb +164 -0
- data/test/example_feed.atom +393 -0
- data/test/example_feed_empty_author.atom +336 -0
- data/test/example_feed_false_connected.atom +359 -0
- data/test/example_feed_link_without_href.atom +134 -0
- data/test/example_page.html +4 -0
- data/test/mime_type_bug_feed.atom +874 -0
- metadata +288 -0
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'nelumba/category'
|
2
|
+
|
3
|
+
module Nelumba
|
4
|
+
require 'atom'
|
5
|
+
|
6
|
+
module Atom
|
7
|
+
# This class represents an Nelumba Category object.
|
8
|
+
class Category < ::Atom::Category
|
9
|
+
require 'open-uri'
|
10
|
+
|
11
|
+
attribute :'xml:base'
|
12
|
+
attribute :'xml:lang'
|
13
|
+
attribute :scheme
|
14
|
+
attribute :term
|
15
|
+
attribute :label
|
16
|
+
|
17
|
+
def self.from_canonical(obj)
|
18
|
+
hash = obj.to_hash
|
19
|
+
if hash[:base]
|
20
|
+
hash[:xml_base] = hash[:base]
|
21
|
+
end
|
22
|
+
if hash[:lang]
|
23
|
+
hash[:xml_lang] = hash[:lang]
|
24
|
+
end
|
25
|
+
hash.delete :base
|
26
|
+
hash.delete :lang
|
27
|
+
self.new(hash)
|
28
|
+
end
|
29
|
+
|
30
|
+
def to_canonical
|
31
|
+
Nelumba::Category.new(:base => self.xml_base,
|
32
|
+
:lang => self.xml_lang,
|
33
|
+
:scheme => self.scheme,
|
34
|
+
:lable => self.label,
|
35
|
+
:term => self.term)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
|
@@ -0,0 +1,96 @@
|
|
1
|
+
module Nelumba
|
2
|
+
require 'atom'
|
3
|
+
require 'nelumba/atom/thread'
|
4
|
+
|
5
|
+
module Atom
|
6
|
+
# This class represents an ActivityStreams Comment object.
|
7
|
+
class Comment
|
8
|
+
include ::Atom::Xml::Parseable
|
9
|
+
|
10
|
+
# The XML namespace that identifies the conforming specification.
|
11
|
+
ACTIVITY_NAMESPACE = 'http://activitystrea.ms/spec/1.0/'
|
12
|
+
|
13
|
+
# The XML namespace that identifies the conforming specification of 'thr'
|
14
|
+
# elements.
|
15
|
+
THREAD_NAMESPACE = "http://purl.org/syndication/thread/1.0"
|
16
|
+
|
17
|
+
# The XML schema that identifies the conforming schema for objects.
|
18
|
+
SCHEMA_ROOT = 'http://activitystrea.ms/schema/1.0/'
|
19
|
+
|
20
|
+
add_extension_namespace :activity, ACTIVITY_NAMESPACE
|
21
|
+
element 'activity:object-type'
|
22
|
+
|
23
|
+
element :author, :class => Nelumba::Atom::Author
|
24
|
+
element :content, :class => ::Atom::Content
|
25
|
+
element :displayName
|
26
|
+
element :id
|
27
|
+
element :title
|
28
|
+
element :url
|
29
|
+
element :summary
|
30
|
+
element :updated, :published, :class => DateTime, :content_only => true
|
31
|
+
|
32
|
+
add_extension_namespace :thr, THREAD_NAMESPACE
|
33
|
+
elements 'thr:in-reply-to', :class => Nelumba::Atom::Thread
|
34
|
+
|
35
|
+
def initialize(o = {})
|
36
|
+
o[:activity_object_type] = SCHEMA_ROOT + "comment"
|
37
|
+
|
38
|
+
case o
|
39
|
+
when XML::Reader
|
40
|
+
o.read
|
41
|
+
parse(o)
|
42
|
+
when Hash
|
43
|
+
o.each do |k, v|
|
44
|
+
self.send("#{k.to_s}=", v)
|
45
|
+
end
|
46
|
+
else
|
47
|
+
raise ArgumentError, "Got #{o.class} but expected a Hash or XML::Reader"
|
48
|
+
end
|
49
|
+
|
50
|
+
yield(self) if block_given?
|
51
|
+
end
|
52
|
+
|
53
|
+
def to_hash
|
54
|
+
{
|
55
|
+
}
|
56
|
+
end
|
57
|
+
|
58
|
+
def self.from_canonical(obj)
|
59
|
+
entry_hash = obj.to_hash
|
60
|
+
|
61
|
+
entry_hash.delete :text
|
62
|
+
entry_hash.delete :html
|
63
|
+
|
64
|
+
entry_hash[:id] = entry_hash[:uid]
|
65
|
+
entry_hash.delete :uid
|
66
|
+
|
67
|
+
entry_hash[:displayName] = entry_hash[:display_name]
|
68
|
+
entry_hash.delete :display_name
|
69
|
+
|
70
|
+
entry_hash[:thr_in_reply_to] = entry_hash[:in_reply_to].map do |t|
|
71
|
+
Nelumba::Atom::Thread.new(:href => t.url,
|
72
|
+
:ref => t.uid)
|
73
|
+
end
|
74
|
+
entry_hash.delete :in_reply_to
|
75
|
+
|
76
|
+
if entry_hash[:author]
|
77
|
+
entry_hash[:author] = Nelumba::Atom::Author.from_canonical(entry_hash[:author])
|
78
|
+
end
|
79
|
+
|
80
|
+
node = XML::Node.new("content")
|
81
|
+
node['type'] = "html"
|
82
|
+
node << entry_hash[:content]
|
83
|
+
|
84
|
+
xml = XML::Reader.string(node.to_s)
|
85
|
+
xml.read
|
86
|
+
entry_hash[:content] = ::Atom::Content.parse(xml)
|
87
|
+
|
88
|
+
self.new entry_hash
|
89
|
+
end
|
90
|
+
|
91
|
+
def to_canonical
|
92
|
+
to_hash
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
@@ -0,0 +1,216 @@
|
|
1
|
+
module Nelumba
|
2
|
+
module Atom
|
3
|
+
require 'atom'
|
4
|
+
|
5
|
+
class Entry < ::Atom::Entry
|
6
|
+
require 'nelumba/activity'
|
7
|
+
require 'nelumba/person'
|
8
|
+
require 'nelumba/link'
|
9
|
+
|
10
|
+
require 'nelumba/atom/person'
|
11
|
+
require 'nelumba/atom/author'
|
12
|
+
require 'nelumba/atom/thread'
|
13
|
+
require 'nelumba/atom/link'
|
14
|
+
require 'nelumba/atom/comment'
|
15
|
+
require 'nelumba/atom/source'
|
16
|
+
|
17
|
+
require 'libxml'
|
18
|
+
|
19
|
+
# The XML namespace that identifies the conforming specification of 'thr'
|
20
|
+
# elements.
|
21
|
+
THREAD_NAMESPACE = "http://purl.org/syndication/thread/1.0"
|
22
|
+
|
23
|
+
# The XML namespace that identifies the conforming specification.
|
24
|
+
ACTIVITY_NAMESPACE = 'http://activitystrea.ms/spec/1.0/'
|
25
|
+
|
26
|
+
# The XML schema that identifies the conforming schema for objects.
|
27
|
+
SCHEMA_ROOT = 'http://activitystrea.ms/schema/1.0/'
|
28
|
+
|
29
|
+
include ::Atom::SimpleExtensions
|
30
|
+
|
31
|
+
add_extension_namespace :activity, ACTIVITY_NAMESPACE
|
32
|
+
element 'activity:object-type'
|
33
|
+
element 'activity:object'
|
34
|
+
element 'activity:verb'
|
35
|
+
element 'activity:target'
|
36
|
+
|
37
|
+
add_extension_namespace :thr, THREAD_NAMESPACE
|
38
|
+
elements 'thr:in-reply-to', :class => Nelumba::Atom::Thread
|
39
|
+
|
40
|
+
# This is for backwards compatibility with some implementations of Activity
|
41
|
+
# Streams. It should not be generated for Atom representation of Activity
|
42
|
+
# Streams (although it is used in JSON)
|
43
|
+
element 'activity:actor', :class => Nelumba::Atom::Author
|
44
|
+
|
45
|
+
element :source, :class => Nelumba::Atom::Source
|
46
|
+
|
47
|
+
namespace ::Atom::NAMESPACE
|
48
|
+
element :title, :id, :summary
|
49
|
+
element :updated, :published, :class => DateTime, :content_only => true
|
50
|
+
elements :links, :class => Nelumba::Atom::Link
|
51
|
+
|
52
|
+
elements :replies, :class => Nelumba::Atom::Entry
|
53
|
+
|
54
|
+
elements :shares, :class => Nelumba::Atom::Person
|
55
|
+
elements :likes, :class => Nelumba::Atom::Person
|
56
|
+
elements :mentions, :class => Nelumba::Atom::Person
|
57
|
+
|
58
|
+
elements :categories, :class => ::Atom::Category
|
59
|
+
element :content, :class => ::Atom::Content
|
60
|
+
elements :authors, :class => Nelumba::Atom::Author
|
61
|
+
|
62
|
+
# ActivityStreams
|
63
|
+
element :displayName
|
64
|
+
|
65
|
+
def url
|
66
|
+
if links.alternate
|
67
|
+
links.alternate.href
|
68
|
+
elsif links.self
|
69
|
+
links.self.href
|
70
|
+
else
|
71
|
+
links.map.each do |l|
|
72
|
+
l.href
|
73
|
+
end.compact.first
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
def link
|
78
|
+
link_list = links.group_by { |l| l.rel.intern if l.rel }
|
79
|
+
end
|
80
|
+
|
81
|
+
def link= options
|
82
|
+
links.clear << ::Atom::Link.new(options)
|
83
|
+
end
|
84
|
+
|
85
|
+
def self.from_canonical(obj)
|
86
|
+
entry_hash = obj.to_hash
|
87
|
+
|
88
|
+
# Ensure that the content type is encoded.
|
89
|
+
object = obj.object
|
90
|
+
|
91
|
+
title = object.title
|
92
|
+
|
93
|
+
content = object.text
|
94
|
+
content = object.html if object.html
|
95
|
+
|
96
|
+
content_type = nil
|
97
|
+
content_type = "html" if object.html
|
98
|
+
|
99
|
+
if object.is_a? Nelumba::Note
|
100
|
+
elsif object.is_a? Nelumba::Comment
|
101
|
+
content = nil
|
102
|
+
content_type = nil
|
103
|
+
title = nil
|
104
|
+
object = Nelumba::Atom::Comment.from_canonical(object.to_hash)
|
105
|
+
entry_hash[:activity_object] = object
|
106
|
+
else
|
107
|
+
content = nil
|
108
|
+
content_type = nil
|
109
|
+
title = nil
|
110
|
+
entry_hash[:activity_object] = object if object.is_a? Nelumba::Person
|
111
|
+
end
|
112
|
+
|
113
|
+
if content
|
114
|
+
node = XML::Node.new("content")
|
115
|
+
node['type'] = content_type if content_type
|
116
|
+
node << content
|
117
|
+
|
118
|
+
xml = XML::Reader.string(node.to_s)
|
119
|
+
xml.read
|
120
|
+
entry_hash[:content] = ::Atom::Content.parse(xml)
|
121
|
+
entry_hash.delete :content_type
|
122
|
+
end
|
123
|
+
|
124
|
+
entry_hash[:title] = title if title
|
125
|
+
|
126
|
+
if entry_hash[:source]
|
127
|
+
entry_hash[:source] = Nelumba::Atom::Source.from_canonical(entry_hash[:source])
|
128
|
+
end
|
129
|
+
|
130
|
+
if entry_hash[:actor]
|
131
|
+
entry_hash[:authors] = [Nelumba::Atom::Author.from_canonical(entry_hash[:actor])]
|
132
|
+
end
|
133
|
+
entry_hash.delete :actor
|
134
|
+
|
135
|
+
# Encode in-reply-to fields
|
136
|
+
entry_hash[:thr_in_reply_to] = entry_hash[:in_reply_to].map do |t|
|
137
|
+
Nelumba::Atom::Thread.new(:href => t.url,
|
138
|
+
:ref => t.uid)
|
139
|
+
end
|
140
|
+
entry_hash.delete :in_reply_to
|
141
|
+
|
142
|
+
entry_hash[:links] ||= []
|
143
|
+
|
144
|
+
if entry_hash[:url]
|
145
|
+
entry_hash[:links] << ::Atom::Link.new(:rel => "self", :href => entry_hash[:url])
|
146
|
+
end
|
147
|
+
entry_hash.delete :url
|
148
|
+
|
149
|
+
object_type = entry_hash[:type]
|
150
|
+
if object_type
|
151
|
+
entry_hash[:activity_object_type] = SCHEMA_ROOT + object_type.to_s
|
152
|
+
end
|
153
|
+
if entry_hash[:verb]
|
154
|
+
entry_hash[:activity_verb] = SCHEMA_ROOT + entry_hash[:verb].to_s
|
155
|
+
end
|
156
|
+
entry_hash[:activity_target] = entry_hash[:target] if entry_hash[:target]
|
157
|
+
|
158
|
+
entry_hash[:id] = entry_hash[:uid]
|
159
|
+
entry_hash.delete :uid
|
160
|
+
|
161
|
+
entry_hash.delete :object
|
162
|
+
entry_hash.delete :verb
|
163
|
+
entry_hash.delete :target
|
164
|
+
entry_hash.delete :type
|
165
|
+
|
166
|
+
entry_hash[:displayName] = entry_hash[:display_name]
|
167
|
+
entry_hash.delete :display_name
|
168
|
+
|
169
|
+
# Remove empty entries
|
170
|
+
entry_hash.keys.each do |key|
|
171
|
+
if entry_hash[key].nil? || entry_hash[key] == ""
|
172
|
+
entry_hash.delete key
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
self.new(entry_hash)
|
177
|
+
end
|
178
|
+
|
179
|
+
def to_canonical
|
180
|
+
# Reform the activity type
|
181
|
+
# TODO: Add new Base schema verbs
|
182
|
+
object_type = self.activity_object_type
|
183
|
+
if object_type && object_type.start_with?(SCHEMA_ROOT)
|
184
|
+
object_type.gsub!(/^#{Regexp.escape(SCHEMA_ROOT)}/, "")
|
185
|
+
end
|
186
|
+
|
187
|
+
object_type = "note" if object_type == "status"
|
188
|
+
|
189
|
+
if self.activity_object
|
190
|
+
object = self.activity_object.to_canonical
|
191
|
+
else
|
192
|
+
case object_type
|
193
|
+
when "note"
|
194
|
+
object = Nelumba::Note.new(:html => self.content.to_s,
|
195
|
+
:title => self.title)
|
196
|
+
end
|
197
|
+
end
|
198
|
+
|
199
|
+
source = self.source
|
200
|
+
source = source.to_canonical if source
|
201
|
+
Nelumba::Activity.new(:actor => self.authors ? self.authors.first.to_canonical : nil,
|
202
|
+
:uid => self.id,
|
203
|
+
:url => self.url,
|
204
|
+
:source => source,
|
205
|
+
:display_name => self.displayName,
|
206
|
+
:in_reply_to => self.thr_in_reply_to.map(&:to_canonical),
|
207
|
+
:object => object,
|
208
|
+
:type => object_type,
|
209
|
+
:verb => self.activity_verb,
|
210
|
+
:target => self.activity_target,
|
211
|
+
:published => self.published,
|
212
|
+
:updated => self.updated)
|
213
|
+
end
|
214
|
+
end
|
215
|
+
end
|
216
|
+
end
|
@@ -0,0 +1,198 @@
|
|
1
|
+
require 'nelumba/activity'
|
2
|
+
require 'nelumba/person'
|
3
|
+
require 'nelumba/category'
|
4
|
+
require 'nelumba/generator'
|
5
|
+
|
6
|
+
require 'nelumba/atom/entry'
|
7
|
+
require 'nelumba/atom/generator'
|
8
|
+
require 'nelumba/atom/category'
|
9
|
+
require 'nelumba/atom/person'
|
10
|
+
require 'nelumba/atom/author'
|
11
|
+
require 'nelumba/atom/link'
|
12
|
+
|
13
|
+
module Nelumba
|
14
|
+
require 'atom'
|
15
|
+
|
16
|
+
module Atom
|
17
|
+
# This class represents an OStatus Feed object.
|
18
|
+
class Feed < ::Atom::Feed
|
19
|
+
require 'open-uri'
|
20
|
+
|
21
|
+
include ::Atom::SimpleExtensions
|
22
|
+
|
23
|
+
# The XML namespace the specifies this content.
|
24
|
+
POCO_NAMESPACE = 'http://portablecontacts.net/spec/1.0'
|
25
|
+
|
26
|
+
# The XML namespace that identifies the conforming specification.
|
27
|
+
ACTIVITY_NAMESPACE = 'http://activitystrea.ms/spec/1.0/'
|
28
|
+
|
29
|
+
namespace ::Atom::NAMESPACE
|
30
|
+
|
31
|
+
add_extension_namespace :poco, POCO_NAMESPACE
|
32
|
+
add_extension_namespace :activity, ACTIVITY_NAMESPACE
|
33
|
+
element :id, :rights, :icon, :logo
|
34
|
+
element :generator, :class => Nelumba::Atom::Generator
|
35
|
+
element :title, :class => ::Atom::Content
|
36
|
+
element :subtitle, :class => ::Atom::Content
|
37
|
+
element :published, :class => Time, :content_only => true
|
38
|
+
element :updated, :class => Time, :content_only => true
|
39
|
+
elements :links, :class => ::Atom::Link
|
40
|
+
elements :authors, :class => Nelumba::Atom::Author
|
41
|
+
elements :contributors, :class => Nelumba::Atom::Person
|
42
|
+
elements :categories, :class => Nelumba::Atom::Category
|
43
|
+
elements :entries, :class => Nelumba::Atom::Entry
|
44
|
+
|
45
|
+
# Activity Streams
|
46
|
+
element :totalItems
|
47
|
+
element :displayName
|
48
|
+
element :content
|
49
|
+
element :summary
|
50
|
+
|
51
|
+
# Creates an Atom generator for the given Nelumba::Feed.
|
52
|
+
def self.from_canonical(obj)
|
53
|
+
hash = obj.to_hash
|
54
|
+
hash[:items].map! {|e|
|
55
|
+
Nelumba::Atom::Entry.from_canonical(e)
|
56
|
+
}
|
57
|
+
|
58
|
+
hash.delete :text
|
59
|
+
hash.delete :html
|
60
|
+
|
61
|
+
# Ensure that the generator is encoded.
|
62
|
+
if hash[:generator]
|
63
|
+
hash[:generator] = Nelumba::Atom::Generator.from_canonical(hash[:generator])
|
64
|
+
end
|
65
|
+
|
66
|
+
hash[:links] ||= []
|
67
|
+
|
68
|
+
if hash[:salmon_url]
|
69
|
+
hash[:links] << ::Atom::Link.new(:rel => "salmon", :href => hash[:salmon_url])
|
70
|
+
end
|
71
|
+
hash.delete :salmon_url
|
72
|
+
|
73
|
+
if hash[:url]
|
74
|
+
hash[:links] << ::Atom::Link.new(:rel => "self", :href => hash[:url])
|
75
|
+
end
|
76
|
+
hash.delete :url
|
77
|
+
|
78
|
+
hash[:hubs].each {|h|
|
79
|
+
hash[:links] << ::Atom::Link.new(:rel => "hub", :href => h)
|
80
|
+
}
|
81
|
+
hash.delete :hubs
|
82
|
+
|
83
|
+
hash[:authors].map! {|a|
|
84
|
+
Nelumba::Atom::Author.from_canonical(a)
|
85
|
+
}
|
86
|
+
|
87
|
+
hash[:contributors].map! {|a|
|
88
|
+
Nelumba::Atom::Person.from_canonical(a)
|
89
|
+
}
|
90
|
+
|
91
|
+
hash[:categories].map! {|c|
|
92
|
+
Nelumba::Atom::Category.from_canonical(c)
|
93
|
+
}
|
94
|
+
|
95
|
+
hash.delete :author
|
96
|
+
|
97
|
+
hash[:displayName] = hash[:display_name]
|
98
|
+
hash.delete :display_name
|
99
|
+
|
100
|
+
hash[:entries] = hash[:items]
|
101
|
+
hash.delete :items
|
102
|
+
|
103
|
+
hash[:totalItems] = hash[:total_items]
|
104
|
+
hash.delete :total_items
|
105
|
+
|
106
|
+
# title/subtitle content type
|
107
|
+
node = XML::Node.new("title")
|
108
|
+
node['type'] = hash[:title_type] if hash[:title_type]
|
109
|
+
node << hash[:title]
|
110
|
+
|
111
|
+
xml = XML::Reader.string(node.to_s)
|
112
|
+
xml.read
|
113
|
+
hash[:title] = ::Atom::Content.parse(xml)
|
114
|
+
hash.delete :title_type
|
115
|
+
|
116
|
+
hash[:id] = hash[:uid]
|
117
|
+
hash.delete :uid
|
118
|
+
|
119
|
+
if hash[:subtitle]
|
120
|
+
node = XML::Node.new("subtitle")
|
121
|
+
node['type'] = hash[:subtitle_type] if hash[:subtitle_type]
|
122
|
+
node << hash[:subtitle]
|
123
|
+
|
124
|
+
xml = XML::Reader.string(node.to_s)
|
125
|
+
xml.read
|
126
|
+
hash[:subtitle] = ::Atom::Content.parse(xml)
|
127
|
+
else
|
128
|
+
hash.delete :subtitle
|
129
|
+
end
|
130
|
+
hash.delete :subtitle_type
|
131
|
+
|
132
|
+
self.new(hash)
|
133
|
+
end
|
134
|
+
|
135
|
+
def to_canonical
|
136
|
+
generator = nil
|
137
|
+
generator = self.generator.to_canonical if self.generator
|
138
|
+
|
139
|
+
salmon_url = nil
|
140
|
+
if self.link('salmon').any?
|
141
|
+
salmon_url = self.link('salmon').first.href
|
142
|
+
end
|
143
|
+
|
144
|
+
url = self.url
|
145
|
+
|
146
|
+
categories = self.categories.map(&:to_canonical)
|
147
|
+
|
148
|
+
Nelumba::Feed.new(:title => self.title.to_s,
|
149
|
+
:title_type => self.title ? self.title.type : nil,
|
150
|
+
:subtitle => self.subtitle.to_s,
|
151
|
+
:subtitle_type => self.subtitle ? self.subtitle.type : nil,
|
152
|
+
:uid => self.id,
|
153
|
+
:url => url,
|
154
|
+
:categories => categories,
|
155
|
+
:icon => self.icon,
|
156
|
+
:logo => self.logo,
|
157
|
+
:rights => self.rights,
|
158
|
+
:published => self.published,
|
159
|
+
:updated => self.updated,
|
160
|
+
:items => self.entries.map(&:to_canonical),
|
161
|
+
:authors => self.authors.map(&:to_canonical),
|
162
|
+
:contributors => self.contributors.map(&:to_canonical),
|
163
|
+
:hubs => self.hubs,
|
164
|
+
:salmon_url => salmon_url,
|
165
|
+
:generator => generator)
|
166
|
+
end
|
167
|
+
|
168
|
+
# Returns an array of ::Atom::Link instances for all link tags
|
169
|
+
# that have a rel equal to that given by attribute.
|
170
|
+
#
|
171
|
+
# For example:
|
172
|
+
# link(:hub).first.href -- Gets the first link tag with rel="hub" and
|
173
|
+
# returns the contents of the href attribute.
|
174
|
+
#
|
175
|
+
def link(attribute)
|
176
|
+
links.find_all { |l| l.rel == attribute.to_s }
|
177
|
+
end
|
178
|
+
|
179
|
+
# Returns an array of URLs for each hub link tag.
|
180
|
+
def hubs
|
181
|
+
link('hub').map { |link| link.href }
|
182
|
+
end
|
183
|
+
|
184
|
+
# Returns a string of the url for this feed.
|
185
|
+
def url
|
186
|
+
if links.alternate
|
187
|
+
links.alternate.href
|
188
|
+
elsif links.self
|
189
|
+
links.self.href
|
190
|
+
else
|
191
|
+
links.map.each do |l|
|
192
|
+
l.href
|
193
|
+
end.compact.first
|
194
|
+
end
|
195
|
+
end
|
196
|
+
end
|
197
|
+
end
|
198
|
+
end
|