lotus 0.0.12
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 +16 -0
- data/README.md +233 -0
- data/Rakefile +7 -0
- data/lib/lotus.rb +232 -0
- data/lib/lotus/activity.rb +134 -0
- data/lib/lotus/atom/account.rb +50 -0
- data/lib/lotus/atom/address.rb +56 -0
- data/lib/lotus/atom/author.rb +167 -0
- data/lib/lotus/atom/category.rb +41 -0
- data/lib/lotus/atom/entry.rb +159 -0
- data/lib/lotus/atom/feed.rb +174 -0
- data/lib/lotus/atom/generator.rb +40 -0
- data/lib/lotus/atom/link.rb +79 -0
- data/lib/lotus/atom/name.rb +57 -0
- data/lib/lotus/atom/organization.rb +62 -0
- data/lib/lotus/atom/portable_contacts.rb +117 -0
- data/lib/lotus/atom/source.rb +168 -0
- data/lib/lotus/atom/thread.rb +60 -0
- data/lib/lotus/author.rb +177 -0
- data/lib/lotus/category.rb +45 -0
- data/lib/lotus/crypto.rb +146 -0
- data/lib/lotus/feed.rb +190 -0
- data/lib/lotus/generator.rb +53 -0
- data/lib/lotus/identity.rb +59 -0
- data/lib/lotus/link.rb +56 -0
- data/lib/lotus/notification.rb +220 -0
- data/lib/lotus/publisher.rb +40 -0
- data/lib/lotus/subscription.rb +117 -0
- data/lib/lotus/version.rb +3 -0
- data/lotus.gemspec +27 -0
- data/spec/activity_spec.rb +84 -0
- data/spec/atom/feed_spec.rb +681 -0
- data/spec/author_spec.rb +150 -0
- data/spec/crypto_spec.rb +138 -0
- data/spec/feed_spec.rb +252 -0
- data/spec/helper.rb +8 -0
- data/spec/identity_spec.rb +67 -0
- data/spec/link_spec.rb +30 -0
- data/spec/notification_spec.rb +77 -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 +204 -0
data/lotus.gemspec
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "lotus/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "lotus"
|
7
|
+
s.version = Lotus::VERSION
|
8
|
+
s.platform = Gem::Platform::RUBY
|
9
|
+
s.authors = ['Hackers of the Severed Hand']
|
10
|
+
s.email = ['hotsh@xomb.org']
|
11
|
+
s.homepage = "http://github.com/hotsh/lotus"
|
12
|
+
s.summary = %q{Generalized federated system backend for social networks with ActivityStreams/OStatus/pump.io.}
|
13
|
+
s.description = %q{This gem allows easier implementation and utilization of distributed, federated social networks.}
|
14
|
+
|
15
|
+
s.add_dependency "ratom", "~> 0.7.2"
|
16
|
+
s.add_dependency "ruby-hmac"
|
17
|
+
s.add_dependency "rsa"
|
18
|
+
s.add_dependency "nokogiri"
|
19
|
+
|
20
|
+
s.add_development_dependency "rspec", "~> 2.10.0"
|
21
|
+
s.add_development_dependency "rake", "~> 0.9.2"
|
22
|
+
|
23
|
+
s.files = `git ls-files`.split("\n")
|
24
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
25
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
26
|
+
s.require_paths = ["lib"]
|
27
|
+
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
require_relative 'helper'
|
2
|
+
require_relative '../lib/lotus/activity.rb'
|
3
|
+
|
4
|
+
describe Lotus::Activity do
|
5
|
+
describe "#initialize" do
|
6
|
+
it "should store an object" do
|
7
|
+
Lotus::Activity.new(:object => "object").object.must_equal "object"
|
8
|
+
end
|
9
|
+
|
10
|
+
it "should store an type" do
|
11
|
+
Lotus::Activity.new(:type => :audio).type.must_equal :audio
|
12
|
+
end
|
13
|
+
|
14
|
+
it "should store a verb" do
|
15
|
+
Lotus::Activity.new(:verb => :follow).verb.must_equal :follow
|
16
|
+
end
|
17
|
+
|
18
|
+
it "should store a target" do
|
19
|
+
Lotus::Activity.new(:target => "target").target.must_equal "target"
|
20
|
+
end
|
21
|
+
|
22
|
+
it "should store a title" do
|
23
|
+
Lotus::Activity.new(:title => "My Title").title.must_equal "My Title"
|
24
|
+
end
|
25
|
+
|
26
|
+
it "should store an actor" do
|
27
|
+
actor = mock('author')
|
28
|
+
Lotus::Activity.new(:actor => actor).actor.must_equal actor
|
29
|
+
end
|
30
|
+
|
31
|
+
it "should store content" do
|
32
|
+
Lotus::Activity.new(:content => "Hello").content.must_equal "Hello"
|
33
|
+
end
|
34
|
+
|
35
|
+
it "should store the content type" do
|
36
|
+
Lotus::Activity.new(:content_type => "txt").content_type.must_equal "txt"
|
37
|
+
end
|
38
|
+
|
39
|
+
it "should store the published date" do
|
40
|
+
time = mock('date')
|
41
|
+
Lotus::Activity.new(:published => time).published.must_equal time
|
42
|
+
end
|
43
|
+
|
44
|
+
it "should store the updated date" do
|
45
|
+
time = mock('date')
|
46
|
+
Lotus::Activity.new(:updated => time).updated.must_equal time
|
47
|
+
end
|
48
|
+
|
49
|
+
it "should store a source feed" do
|
50
|
+
feed = mock('feed')
|
51
|
+
Lotus::Activity.new(:source => feed).source.must_equal feed
|
52
|
+
end
|
53
|
+
|
54
|
+
it "should store a url" do
|
55
|
+
Lotus::Activity.new(:url => "url").url.must_equal "url"
|
56
|
+
end
|
57
|
+
|
58
|
+
it "should store an id" do
|
59
|
+
Lotus::Activity.new(:id => "id").id.must_equal "id"
|
60
|
+
end
|
61
|
+
|
62
|
+
it "should store an array of threads" do
|
63
|
+
thread = mock('entry')
|
64
|
+
Lotus::Activity.new(:in_reply_to => [thread]).in_reply_to.must_equal [thread]
|
65
|
+
end
|
66
|
+
|
67
|
+
it "should store an array of threads when only given one entry" do
|
68
|
+
thread = mock('entry')
|
69
|
+
Lotus::Activity.new(:in_reply_to => thread).in_reply_to.must_equal [thread]
|
70
|
+
end
|
71
|
+
|
72
|
+
it "should store an empty array of threads by default" do
|
73
|
+
Lotus::Activity.new.in_reply_to.must_equal []
|
74
|
+
end
|
75
|
+
|
76
|
+
it "should default the content to '' if not given" do
|
77
|
+
Lotus::Activity.new.content.must_equal ''
|
78
|
+
end
|
79
|
+
|
80
|
+
it "should default the title to 'Untitled' if not given" do
|
81
|
+
Lotus::Activity.new.title.must_equal "Untitled"
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
@@ -0,0 +1,681 @@
|
|
1
|
+
require_relative '../helper'
|
2
|
+
require_relative '../../lib/lotus/feed.rb'
|
3
|
+
require_relative '../../lib/lotus/atom/feed.rb'
|
4
|
+
|
5
|
+
# Sanity checks on atom generation because I don't trust ratom completely.
|
6
|
+
#
|
7
|
+
# Since I can't be completely sure how to test the implementations since they
|
8
|
+
# are patchy inheritance, I'll just do big acceptance tests and overtest.
|
9
|
+
# Somehow, these are still really fast.
|
10
|
+
describe Lotus::Atom do
|
11
|
+
before do
|
12
|
+
author = Lotus::Author.new(:uri => "http://example.com/users/1",
|
13
|
+
:email => "user@example.com",
|
14
|
+
:name => "wilkie",
|
15
|
+
:id => "1",
|
16
|
+
:nickname => "wilkie",
|
17
|
+
:extended_name => {:formatted => "Dave Wilkinson",
|
18
|
+
:family_name => "Wilkinson",
|
19
|
+
:given_name => "Dave",
|
20
|
+
:middle_name => "William",
|
21
|
+
:honorific_prefix => "Mr.",
|
22
|
+
:honorific_suffix => "II"},
|
23
|
+
:address => {:formatted => "123 Cherry Lane\nFoobar, PA, USA\n15206",
|
24
|
+
:street_address => "123 Cherry Lane",
|
25
|
+
:locality => "Foobar",
|
26
|
+
:region => "PA",
|
27
|
+
:postal_code => "15206",
|
28
|
+
:country => "USA"},
|
29
|
+
:organization => {:name => "Hackers of the Severed Hand",
|
30
|
+
:department => "Making Shit",
|
31
|
+
:title => "Founder",
|
32
|
+
:type => "open source",
|
33
|
+
:start_date => Date.today,
|
34
|
+
:end_date => Date.today,
|
35
|
+
:location => "everywhere",
|
36
|
+
:description => "I make ostatus work"},
|
37
|
+
:account => {:domain => "example.com",
|
38
|
+
:username => "wilkie",
|
39
|
+
:userid => "1"},
|
40
|
+
:gender => "androgynous",
|
41
|
+
:note => "cool dude",
|
42
|
+
:display_name => "Dave Wilkinson",
|
43
|
+
:preferred_username => "wilkie",
|
44
|
+
:updated => Time.now,
|
45
|
+
:published => Time.now,
|
46
|
+
:birthday => Date.today,
|
47
|
+
:anniversary => Date.today)
|
48
|
+
|
49
|
+
source_feed = Lotus::Feed.new(:title => "moo",
|
50
|
+
:authors => [author],
|
51
|
+
:rights => "CC")
|
52
|
+
|
53
|
+
reply_to = Lotus::Activity.new(:title => "My First Entry",
|
54
|
+
:type => :note,
|
55
|
+
:actor => author,
|
56
|
+
:content => "Hello",
|
57
|
+
:content_type => "html",
|
58
|
+
:id => "54321",
|
59
|
+
:url => "http://example.com/entries/1",
|
60
|
+
:published => Time.now,
|
61
|
+
:updated => Time.now)
|
62
|
+
|
63
|
+
entry = Lotus::Activity.new(:title => "My Entry",
|
64
|
+
:actor => author,
|
65
|
+
:type => :note,
|
66
|
+
:content => "Hello",
|
67
|
+
:content_type => "html",
|
68
|
+
:source => source_feed,
|
69
|
+
:id => "54321",
|
70
|
+
:url => "http://example.com/entries/1",
|
71
|
+
:published => Time.now,
|
72
|
+
:in_reply_to => reply_to,
|
73
|
+
:updated => Time.now)
|
74
|
+
|
75
|
+
@master = Lotus::Feed.new(:title => "My Feed",
|
76
|
+
:title_type => "html",
|
77
|
+
:subtitle => "Subtitle",
|
78
|
+
:subtitle_type => "html",
|
79
|
+
:url => "http://example.com/feeds/1",
|
80
|
+
:rights => "CC0",
|
81
|
+
:icon => "http://example.com/icon.png",
|
82
|
+
:logo => "http://example.com/logo.png",
|
83
|
+
:hubs => ["http://hub.example.com",
|
84
|
+
"http://hub2.example.com"],
|
85
|
+
:published => Time.now,
|
86
|
+
:updated => Time.now,
|
87
|
+
:authors => [author],
|
88
|
+
:entries => [entry],
|
89
|
+
:id => "12345")
|
90
|
+
end
|
91
|
+
|
92
|
+
it "should be able to reform canonical structure using Atom" do
|
93
|
+
xml = Lotus::Atom::Feed.from_canonical(@master).to_xml
|
94
|
+
new_feed = Lotus::Atom::Feed.new(XML::Reader.string(xml)).to_canonical
|
95
|
+
|
96
|
+
old_hash = @master.to_hash
|
97
|
+
new_hash = new_feed.to_hash
|
98
|
+
|
99
|
+
old_hash[:authors] = old_hash[:authors].map(&:to_hash)
|
100
|
+
new_hash[:authors] = new_hash[:authors].map(&:to_hash)
|
101
|
+
|
102
|
+
old_hash[:entries] = old_hash[:entries].map(&:to_hash)
|
103
|
+
new_hash[:entries] = new_hash[:entries].map(&:to_hash)
|
104
|
+
|
105
|
+
old_hash[:entries][0][:in_reply_to] = []
|
106
|
+
new_hash[:entries][0][:in_reply_to] = []
|
107
|
+
|
108
|
+
old_hash[:entries][0][:actor] = old_hash[:entries][0][:actor].to_hash
|
109
|
+
new_hash[:entries][0][:actor] = new_hash[:entries][0][:actor].to_hash
|
110
|
+
|
111
|
+
old_hash[:entries][0][:source] = old_hash[:entries][0][:source].to_hash
|
112
|
+
new_hash[:entries][0][:source] = new_hash[:entries][0][:source].to_hash
|
113
|
+
|
114
|
+
old_hash[:entries][0][:source][:authors] = old_hash[:entries][0][:source][:authors].map(&:to_hash)
|
115
|
+
new_hash[:entries][0][:source][:authors] = new_hash[:entries][0][:source][:authors].map(&:to_hash)
|
116
|
+
|
117
|
+
# Flatten all keys to their to_s
|
118
|
+
# We want to compare the to_s for all keys
|
119
|
+
def flatten_keys!(hash)
|
120
|
+
hash.keys.each do |k|
|
121
|
+
if hash[k].is_a? Array
|
122
|
+
# Go inside arrays (doesn't handle arrays of arrays)
|
123
|
+
hash[k].map! do |e|
|
124
|
+
if e.is_a? Hash
|
125
|
+
flatten_keys! e
|
126
|
+
e
|
127
|
+
else
|
128
|
+
e.to_s
|
129
|
+
end
|
130
|
+
end
|
131
|
+
elsif hash[k].is_a? Hash
|
132
|
+
# Go inside hashes
|
133
|
+
flatten_keys!(hash[k])
|
134
|
+
elsif hash[k].is_a? Time
|
135
|
+
# Ensure all Time classes become DateTimes for comparison
|
136
|
+
hash[k] = hash[k].to_datetime.to_s
|
137
|
+
else
|
138
|
+
# Ensure all fields become Strings
|
139
|
+
hash[k] = hash[k].to_s
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
flatten_keys!(old_hash)
|
145
|
+
flatten_keys!(new_hash)
|
146
|
+
|
147
|
+
old_hash.must_equal new_hash
|
148
|
+
end
|
149
|
+
|
150
|
+
describe "<xml>" do
|
151
|
+
before do
|
152
|
+
@xml_str = Lotus::Atom::Feed.from_canonical(@master).to_xml
|
153
|
+
@xml = XML::Parser.string(@xml_str).parse
|
154
|
+
end
|
155
|
+
|
156
|
+
it "should publish a version of 1.0" do
|
157
|
+
@xml_str.must_match /^<\?xml[^>]*\sversion="1\.0"/
|
158
|
+
end
|
159
|
+
|
160
|
+
it "should encode in utf-8" do
|
161
|
+
@xml_str.must_match /^<\?xml[^>]*\sencoding="UTF-8"/
|
162
|
+
end
|
163
|
+
|
164
|
+
describe "<feed>" do
|
165
|
+
before do
|
166
|
+
@feed = @xml.root
|
167
|
+
end
|
168
|
+
|
169
|
+
it "should contain the Atom namespace" do
|
170
|
+
@feed.namespaces.find_by_href("http://www.w3.org/2005/Atom").to_s
|
171
|
+
.must_equal "http://www.w3.org/2005/Atom"
|
172
|
+
end
|
173
|
+
|
174
|
+
it "should contain the PortableContacts namespace" do
|
175
|
+
@feed.namespaces.find_by_prefix('poco').to_s
|
176
|
+
.must_equal "poco:http://portablecontacts.net/spec/1.0"
|
177
|
+
end
|
178
|
+
|
179
|
+
it "should contain the ActivityStreams namespace" do
|
180
|
+
@feed.namespaces.find_by_prefix('activity').to_s
|
181
|
+
.must_equal "activity:http://activitystrea.ms/spec/1.0/"
|
182
|
+
end
|
183
|
+
|
184
|
+
describe "<id>" do
|
185
|
+
it "should contain the id from Lotus::Feed" do
|
186
|
+
@feed.find_first('xmlns:id', 'xmlns:http://www.w3.org/2005/Atom')
|
187
|
+
.content.must_equal @master.id
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
describe "<rights>" do
|
192
|
+
it "should contain the rights from Lotus::Feed" do
|
193
|
+
@feed.find_first('xmlns:rights', 'xmlns:http://www.w3.org/2005/Atom')
|
194
|
+
.content.must_equal @master.rights
|
195
|
+
end
|
196
|
+
end
|
197
|
+
|
198
|
+
describe "<logo>" do
|
199
|
+
it "should contain the logo from Lotus::Feed" do
|
200
|
+
@feed.find_first('xmlns:logo', 'xmlns:http://www.w3.org/2005/Atom')
|
201
|
+
.content.must_equal @master.logo
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
describe "<icon>" do
|
206
|
+
it "should contain the icon from Lotus::Feed" do
|
207
|
+
@feed.find_first('xmlns:icon', 'xmlns:http://www.w3.org/2005/Atom')
|
208
|
+
.content.must_equal @master.icon
|
209
|
+
end
|
210
|
+
end
|
211
|
+
|
212
|
+
describe "<published>" do
|
213
|
+
it "should contain the time in the published field in Lotus::Feed" do
|
214
|
+
time = @feed.find_first('xmlns:published',
|
215
|
+
'xmlns:http://www.w3.org/2005/Atom').content
|
216
|
+
DateTime::rfc3339(time).to_s.must_equal @master.published.to_datetime.to_s
|
217
|
+
end
|
218
|
+
end
|
219
|
+
|
220
|
+
describe "<updated>" do
|
221
|
+
it "should contain the time in the updated field in Lotus::Feed" do
|
222
|
+
time = @feed.find_first('xmlns:updated',
|
223
|
+
'xmlns:http://www.w3.org/2005/Atom').content
|
224
|
+
DateTime::rfc3339(time).to_s.must_equal @master.updated.to_datetime.to_s
|
225
|
+
end
|
226
|
+
end
|
227
|
+
|
228
|
+
describe "<link>" do
|
229
|
+
it "should contain a link for the hub" do
|
230
|
+
@feed.find_first('xmlns:link[@rel="hub"]',
|
231
|
+
'xmlns:http://www.w3.org/2005/Atom').attributes
|
232
|
+
.get_attribute('href').value.must_equal(@master.hubs.first)
|
233
|
+
end
|
234
|
+
|
235
|
+
it "should allow a second link for the hub" do
|
236
|
+
@feed.find('xmlns:link[@rel="hub"]',
|
237
|
+
'xmlns:http://www.w3.org/2005/Atom')[1].attributes
|
238
|
+
.get_attribute('href').value.must_equal(@master.hubs[1])
|
239
|
+
end
|
240
|
+
|
241
|
+
it "should contain a link for self" do
|
242
|
+
@feed.find_first('xmlns:link[@rel="self"]',
|
243
|
+
'xmlns:http://www.w3.org/2005/Atom').attributes
|
244
|
+
.get_attribute('href').value.must_equal(@master.url)
|
245
|
+
end
|
246
|
+
end
|
247
|
+
|
248
|
+
describe "<title>" do
|
249
|
+
before do
|
250
|
+
@title = @feed.find_first('xmlns:title', 'xmlns:http://www.w3.org/2005/Atom')
|
251
|
+
end
|
252
|
+
|
253
|
+
it "should contain the title from Lotus::Feed" do
|
254
|
+
@title.content.must_equal @master.title
|
255
|
+
end
|
256
|
+
|
257
|
+
it "should contain the type attribute from Lotus::Feed" do
|
258
|
+
@title.attributes.get_attribute('type').value.must_equal @master.title_type
|
259
|
+
end
|
260
|
+
end
|
261
|
+
|
262
|
+
describe "<subtitle>" do
|
263
|
+
before do
|
264
|
+
@subtitle = @feed.find_first('xmlns:subtitle', 'xmlns:http://www.w3.org/2005/Atom')
|
265
|
+
end
|
266
|
+
|
267
|
+
it "should contain the subtitle from Lotus::Feed" do
|
268
|
+
@subtitle.content.must_equal @master.subtitle
|
269
|
+
end
|
270
|
+
|
271
|
+
it "should contain the type attribute from Lotus::Feed" do
|
272
|
+
@subtitle.attributes.get_attribute('type').value.must_equal @master.subtitle_type
|
273
|
+
end
|
274
|
+
end
|
275
|
+
|
276
|
+
describe "<author>" do
|
277
|
+
before do
|
278
|
+
@author = @feed.find_first('xmlns:author', 'xmlns:http://www.w3.org/2005/Atom')
|
279
|
+
end
|
280
|
+
|
281
|
+
describe "<activity:object-type>" do
|
282
|
+
it "should identify this tag as a person object" do
|
283
|
+
@author.find_first('activity:object-type').content
|
284
|
+
.must_equal "http://activitystrea.ms/schema/1.0/person"
|
285
|
+
end
|
286
|
+
end
|
287
|
+
|
288
|
+
describe "<email>" do
|
289
|
+
it "should list the author's email" do
|
290
|
+
@author.find_first('xmlns:email',
|
291
|
+
'xmlns:http://www.w3.org/2005/Atom').content.must_equal @master.authors.first.email
|
292
|
+
end
|
293
|
+
end
|
294
|
+
|
295
|
+
describe "<uri>" do
|
296
|
+
it "should list the author's uri" do
|
297
|
+
@author.find_first('xmlns:uri',
|
298
|
+
'xmlns:http://www.w3.org/2005/Atom').content.must_equal @master.authors.first.uri
|
299
|
+
end
|
300
|
+
end
|
301
|
+
|
302
|
+
describe "<name>" do
|
303
|
+
it "should list the author's name" do
|
304
|
+
@author.find_first('xmlns:name',
|
305
|
+
'xmlns:http://www.w3.org/2005/Atom').content.must_equal @master.authors.first.name
|
306
|
+
end
|
307
|
+
end
|
308
|
+
|
309
|
+
describe "<poco:id>" do
|
310
|
+
it "should list the author's portable contact id" do
|
311
|
+
@author.find_first('poco:id',
|
312
|
+
'http://portablecontacts.net/spec/1.0').content.must_equal @master.authors.first.id
|
313
|
+
end
|
314
|
+
end
|
315
|
+
|
316
|
+
describe "<poco:name>" do
|
317
|
+
before do
|
318
|
+
@poco_name = @author.find_first('poco:name',
|
319
|
+
'http://portablecontacts.net/spec/1.0')
|
320
|
+
end
|
321
|
+
|
322
|
+
describe "<formatted>" do
|
323
|
+
it "should list the author's portable contact formatted name" do
|
324
|
+
@poco_name.find_first('xmlns:formatted',
|
325
|
+
'xmlns:http://www.w3.org/2005/Atom')
|
326
|
+
.content.must_equal @master.authors.first.extended_name[:formatted]
|
327
|
+
end
|
328
|
+
end
|
329
|
+
|
330
|
+
describe "<familyName>" do
|
331
|
+
it "should list the author's portable contact family name" do
|
332
|
+
@poco_name.find_first('xmlns:familyName',
|
333
|
+
'xmlns:http://www.w3.org/2005/Atom')
|
334
|
+
.content.must_equal @master.authors.first.extended_name[:family_name]
|
335
|
+
end
|
336
|
+
end
|
337
|
+
|
338
|
+
describe "<givenName>" do
|
339
|
+
it "should list the author's portable contact given name" do
|
340
|
+
@poco_name.find_first('xmlns:givenName',
|
341
|
+
'xmlns:http://www.w3.org/2005/Atom')
|
342
|
+
.content.must_equal @master.authors.first.extended_name[:given_name]
|
343
|
+
end
|
344
|
+
end
|
345
|
+
|
346
|
+
describe "<middleName>" do
|
347
|
+
it "should list the author's portable contact middle name" do
|
348
|
+
@poco_name.find_first('xmlns:middleName',
|
349
|
+
'xmlns:http://www.w3.org/2005/Atom')
|
350
|
+
.content.must_equal @master.authors.first.extended_name[:middle_name]
|
351
|
+
end
|
352
|
+
end
|
353
|
+
|
354
|
+
describe "<honorificPrefix>" do
|
355
|
+
it "should list the author's portable contact honorific prefix" do
|
356
|
+
@poco_name.find_first('xmlns:honorificPrefix',
|
357
|
+
'xmlns:http://www.w3.org/2005/Atom')
|
358
|
+
.content.must_equal @master.authors.first.extended_name[:honorific_prefix]
|
359
|
+
end
|
360
|
+
end
|
361
|
+
|
362
|
+
describe "<honorificSuffix>" do
|
363
|
+
it "should list the author's portable contact honorific suffix" do
|
364
|
+
@poco_name.find_first('xmlns:honorificSuffix',
|
365
|
+
'xmlns:http://www.w3.org/2005/Atom')
|
366
|
+
.content.must_equal @master.authors.first.extended_name[:honorific_suffix]
|
367
|
+
end
|
368
|
+
end
|
369
|
+
end
|
370
|
+
|
371
|
+
describe "<poco:organization>" do
|
372
|
+
before do
|
373
|
+
@poco_org = @author.find_first('poco:organization',
|
374
|
+
'http://portablecontacts.net/spec/1.0')
|
375
|
+
end
|
376
|
+
|
377
|
+
describe "<name>" do
|
378
|
+
it "should list the author's portable contact organization name" do
|
379
|
+
@poco_org.find_first('xmlns:name',
|
380
|
+
'xmlns:http://www.w3.org/2005/Atom')
|
381
|
+
.content.must_equal @master.authors.first.organization[:name]
|
382
|
+
end
|
383
|
+
end
|
384
|
+
|
385
|
+
describe "<department>" do
|
386
|
+
it "should list the author's portable contact organization department" do
|
387
|
+
@poco_org.find_first('xmlns:department',
|
388
|
+
'xmlns:http://www.w3.org/2005/Atom')
|
389
|
+
.content.must_equal @master.authors.first.organization[:department]
|
390
|
+
end
|
391
|
+
end
|
392
|
+
|
393
|
+
describe "<title>" do
|
394
|
+
it "should list the author's portable contact organization title" do
|
395
|
+
@poco_org.find_first('xmlns:title',
|
396
|
+
'xmlns:http://www.w3.org/2005/Atom')
|
397
|
+
.content.must_equal @master.authors.first.organization[:title]
|
398
|
+
end
|
399
|
+
end
|
400
|
+
|
401
|
+
describe "<type>" do
|
402
|
+
it "should list the author's portable contact organization type" do
|
403
|
+
@poco_org.find_first('xmlns:type',
|
404
|
+
'xmlns:http://www.w3.org/2005/Atom')
|
405
|
+
.content.must_equal @master.authors.first.organization[:type]
|
406
|
+
end
|
407
|
+
end
|
408
|
+
|
409
|
+
describe "<startDate>" do
|
410
|
+
it "should list the author's portable contact organization startDate" do
|
411
|
+
time = @poco_org.find_first('xmlns:startDate',
|
412
|
+
'xmlns:http://www.w3.org/2005/Atom').content
|
413
|
+
DateTime::parse(time).to_s
|
414
|
+
.must_equal @master.authors.first.organization[:start_date].to_datetime.to_s
|
415
|
+
end
|
416
|
+
end
|
417
|
+
|
418
|
+
describe "<endDate>" do
|
419
|
+
it "should list the author's portable contact organization endDate" do
|
420
|
+
time = @poco_org.find_first('xmlns:endDate',
|
421
|
+
'xmlns:http://www.w3.org/2005/Atom').content
|
422
|
+
DateTime::parse(time).to_s
|
423
|
+
.must_equal @master.authors.first.organization[:end_date].to_datetime.to_s
|
424
|
+
end
|
425
|
+
end
|
426
|
+
|
427
|
+
describe "<location>" do
|
428
|
+
it "should list the author's portable contact organization location" do
|
429
|
+
@poco_org.find_first('xmlns:location',
|
430
|
+
'xmlns:http://www.w3.org/2005/Atom')
|
431
|
+
.content.must_equal @master.authors.first.organization[:location]
|
432
|
+
end
|
433
|
+
end
|
434
|
+
|
435
|
+
describe "<description>" do
|
436
|
+
it "should list the author's portable contact organization description" do
|
437
|
+
@poco_org.find_first('xmlns:description',
|
438
|
+
'xmlns:http://www.w3.org/2005/Atom')
|
439
|
+
.content.must_equal @master.authors.first.organization[:description]
|
440
|
+
end
|
441
|
+
end
|
442
|
+
end
|
443
|
+
|
444
|
+
describe "<poco:address>" do
|
445
|
+
before do
|
446
|
+
@poco_address = @author.find_first('poco:address',
|
447
|
+
'http://portablecontacts.net/spec/1.0')
|
448
|
+
end
|
449
|
+
|
450
|
+
describe "<formatted>" do
|
451
|
+
it "should list the author's portable contact formatted address" do
|
452
|
+
@poco_address.find_first('xmlns:formatted',
|
453
|
+
'xmlns:http://www.w3.org/2005/Atom')
|
454
|
+
.content.must_equal @master.authors.first.address[:formatted]
|
455
|
+
end
|
456
|
+
end
|
457
|
+
|
458
|
+
describe "<streetAddress>" do
|
459
|
+
it "should list the author's portable contact address streetAddress" do
|
460
|
+
@poco_address.find_first('xmlns:streetAddress',
|
461
|
+
'xmlns:http://www.w3.org/2005/Atom')
|
462
|
+
.content.must_equal @master.authors.first.address[:street_address]
|
463
|
+
end
|
464
|
+
end
|
465
|
+
|
466
|
+
describe "<locality>" do
|
467
|
+
it "should list the author's portable contact address locality" do
|
468
|
+
@poco_address.find_first('xmlns:locality',
|
469
|
+
'xmlns:http://www.w3.org/2005/Atom')
|
470
|
+
.content.must_equal @master.authors.first.address[:locality]
|
471
|
+
end
|
472
|
+
end
|
473
|
+
|
474
|
+
describe "<region>" do
|
475
|
+
it "should list the author's portable contact address region" do
|
476
|
+
@poco_address.find_first('xmlns:region',
|
477
|
+
'xmlns:http://www.w3.org/2005/Atom')
|
478
|
+
.content.must_equal @master.authors.first.address[:region]
|
479
|
+
end
|
480
|
+
end
|
481
|
+
|
482
|
+
describe "<postalCode>" do
|
483
|
+
it "should list the author's portable contact address postalCode" do
|
484
|
+
@poco_address.find_first('xmlns:postalCode',
|
485
|
+
'xmlns:http://www.w3.org/2005/Atom')
|
486
|
+
.content.must_equal @master.authors.first.address[:postal_code]
|
487
|
+
end
|
488
|
+
end
|
489
|
+
|
490
|
+
describe "<country>" do
|
491
|
+
it "should list the author's portable contact address country" do
|
492
|
+
@poco_address.find_first('xmlns:country',
|
493
|
+
'xmlns:http://www.w3.org/2005/Atom')
|
494
|
+
.content.must_equal @master.authors.first.address[:country]
|
495
|
+
end
|
496
|
+
end
|
497
|
+
end
|
498
|
+
|
499
|
+
describe "<poco:account>" do
|
500
|
+
before do
|
501
|
+
@poco_account = @author.find_first('poco:account',
|
502
|
+
'http://portablecontacts.net/spec/1.0')
|
503
|
+
end
|
504
|
+
|
505
|
+
describe "<domain>" do
|
506
|
+
it "should list the author's portable contact account domain" do
|
507
|
+
@poco_account.find_first('xmlns:domain',
|
508
|
+
'xmlns:http://www.w3.org/2005/Atom')
|
509
|
+
.content.must_equal @master.authors.first.account[:domain]
|
510
|
+
end
|
511
|
+
end
|
512
|
+
|
513
|
+
describe "<username>" do
|
514
|
+
it "should list the author's portable contact account username" do
|
515
|
+
@poco_account.find_first('xmlns:username',
|
516
|
+
'xmlns:http://www.w3.org/2005/Atom')
|
517
|
+
.content.must_equal @master.authors.first.account[:username]
|
518
|
+
end
|
519
|
+
end
|
520
|
+
|
521
|
+
describe "<userid>" do
|
522
|
+
it "should list the author's portable contact account userid" do
|
523
|
+
@poco_account.find_first('xmlns:userid',
|
524
|
+
'xmlns:http://www.w3.org/2005/Atom')
|
525
|
+
.content.must_equal @master.authors.first.account[:userid]
|
526
|
+
end
|
527
|
+
end
|
528
|
+
end
|
529
|
+
|
530
|
+
describe "<poco:displayName>" do
|
531
|
+
it "should list the author's portable contact display name" do
|
532
|
+
@author.find_first('poco:displayName',
|
533
|
+
'http://portablecontacts.net/spec/1.0')
|
534
|
+
.content.must_equal @master.authors.first.display_name
|
535
|
+
end
|
536
|
+
end
|
537
|
+
|
538
|
+
describe "<poco:nickname>" do
|
539
|
+
it "should list the author's portable contact nickname" do
|
540
|
+
@author.find_first('poco:nickname',
|
541
|
+
'http://portablecontacts.net/spec/1.0')
|
542
|
+
.content.must_equal @master.authors.first.nickname
|
543
|
+
end
|
544
|
+
end
|
545
|
+
|
546
|
+
describe "<poco:gender>" do
|
547
|
+
it "should list the author's portable contact gender" do
|
548
|
+
@author.find_first('poco:gender',
|
549
|
+
'http://portablecontacts.net/spec/1.0')
|
550
|
+
.content.must_equal @master.authors.first.gender
|
551
|
+
end
|
552
|
+
end
|
553
|
+
|
554
|
+
describe "<poco:note>" do
|
555
|
+
it "should list the author's portable contact note" do
|
556
|
+
@author.find_first('poco:note',
|
557
|
+
'http://portablecontacts.net/spec/1.0')
|
558
|
+
.content.must_equal @master.authors.first.note
|
559
|
+
end
|
560
|
+
end
|
561
|
+
|
562
|
+
describe "<poco:preferredUsername>" do
|
563
|
+
it "should list the author's portable contact preferred username" do
|
564
|
+
@author.find_first('poco:preferredUsername',
|
565
|
+
'http://portablecontacts.net/spec/1.0')
|
566
|
+
.content.must_equal @master.authors.first.preferred_username
|
567
|
+
end
|
568
|
+
end
|
569
|
+
|
570
|
+
describe "<poco:birthday>" do
|
571
|
+
it "should list the author's portable contact birthday" do
|
572
|
+
time = @author.find_first('poco:birthday',
|
573
|
+
'http://portablecontacts.net/spec/1.0').content
|
574
|
+
DateTime::parse(time).to_s.must_equal @master.authors.first
|
575
|
+
.birthday.to_datetime.to_s
|
576
|
+
end
|
577
|
+
end
|
578
|
+
|
579
|
+
describe "<poco:anniversary>" do
|
580
|
+
it "should list the author's portable contact anniversary" do
|
581
|
+
time = @author.find_first('poco:anniversary',
|
582
|
+
'http://portablecontacts.net/spec/1.0').content
|
583
|
+
DateTime::parse(time).to_s.must_equal @master.authors.first
|
584
|
+
.anniversary.to_datetime.to_s
|
585
|
+
end
|
586
|
+
end
|
587
|
+
|
588
|
+
describe "<poco:published>" do
|
589
|
+
it "should list the author's portable contact published date" do
|
590
|
+
time = @author.find_first('poco:published',
|
591
|
+
'http://portablecontacts.net/spec/1.0').content
|
592
|
+
DateTime::parse(time).to_s.must_equal @master.authors.first
|
593
|
+
.published.to_datetime.to_s
|
594
|
+
end
|
595
|
+
end
|
596
|
+
|
597
|
+
describe "<poco:updated>" do
|
598
|
+
it "should list the author's portable contact updated date" do
|
599
|
+
time = @author.find_first('poco:updated',
|
600
|
+
'http://portablecontacts.net/spec/1.0').content
|
601
|
+
DateTime::parse(time).to_s.must_equal @master.authors.first
|
602
|
+
.updated.to_datetime.to_s
|
603
|
+
end
|
604
|
+
end
|
605
|
+
end
|
606
|
+
|
607
|
+
describe "<entry>" do
|
608
|
+
before do
|
609
|
+
@entry = @feed.find_first('xmlns:entry', 'xmlns:http://www.w3.org/2005/Atom')
|
610
|
+
end
|
611
|
+
|
612
|
+
it "should have the thread namespace" do
|
613
|
+
@entry.namespaces.find_by_prefix('thr').to_s
|
614
|
+
.must_equal "thr:http://purl.org/syndication/thread/1.0"
|
615
|
+
end
|
616
|
+
|
617
|
+
it "should have the activity streams namespace" do
|
618
|
+
@entry.namespaces.find_by_prefix('activity').to_s
|
619
|
+
.must_equal "activity:http://activitystrea.ms/spec/1.0/"
|
620
|
+
end
|
621
|
+
|
622
|
+
describe "<title>" do
|
623
|
+
it "should contain the entry title" do
|
624
|
+
@entry.find_first('xmlns:title', 'xmlns:http://www.w3.org/2005/Atom')
|
625
|
+
.content.must_equal @master.entries.first.title
|
626
|
+
end
|
627
|
+
end
|
628
|
+
|
629
|
+
describe "<id>" do
|
630
|
+
it "should contain the entry id" do
|
631
|
+
@entry.find_first('xmlns:id', 'xmlns:http://www.w3.org/2005/Atom')
|
632
|
+
.content.must_equal @master.entries.first.id
|
633
|
+
end
|
634
|
+
end
|
635
|
+
|
636
|
+
describe "<link>" do
|
637
|
+
it "should contain a link for self" do
|
638
|
+
@entry.find_first('xmlns:link[@rel="self"]',
|
639
|
+
'xmlns:http://www.w3.org/2005/Atom').attributes
|
640
|
+
.get_attribute('href').value.must_equal(@master.entries.first.url)
|
641
|
+
end
|
642
|
+
end
|
643
|
+
|
644
|
+
describe "<updated>" do
|
645
|
+
it "should contain the entry updated date" do
|
646
|
+
time = @entry.find_first('xmlns:updated',
|
647
|
+
'xmlns:http://www.w3.org/2005/Atom').content
|
648
|
+
DateTime.parse(time).to_s.must_equal @master.entries.first.updated.to_datetime.to_s
|
649
|
+
end
|
650
|
+
end
|
651
|
+
|
652
|
+
describe "<published>" do
|
653
|
+
it "should contain the entry published date" do
|
654
|
+
time = @entry.find_first('xmlns:published',
|
655
|
+
'xmlns:http://www.w3.org/2005/Atom').content
|
656
|
+
DateTime.parse(time).to_s.must_equal @master.entries.first.published.to_datetime.to_s
|
657
|
+
end
|
658
|
+
end
|
659
|
+
|
660
|
+
describe "<activity:object-type>" do
|
661
|
+
it "should reflect the activity for this entry" do
|
662
|
+
@entry.find_first('activity:object-type').content
|
663
|
+
.must_equal "http://activitystrea.ms/schema/1.0/note"
|
664
|
+
end
|
665
|
+
end
|
666
|
+
|
667
|
+
describe "<content>" do
|
668
|
+
it "should contain the entry content" do
|
669
|
+
@entry.find_first('xmlns:content', 'xmlns:http://www.w3.org/2005/Atom')
|
670
|
+
.content.must_equal @master.entries.first.content
|
671
|
+
end
|
672
|
+
|
673
|
+
it "should have the corresponding type attribute" do
|
674
|
+
@entry.find_first('xmlns:content', 'xmlns:http://www.w3.org/2005/Atom')
|
675
|
+
.attributes.get_attribute('type').value.must_equal @master.entries.first.content_type
|
676
|
+
end
|
677
|
+
end
|
678
|
+
end
|
679
|
+
end
|
680
|
+
end
|
681
|
+
end
|