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