lotus 0.0.12

Sign up to get free protection for your applications and to get access to all the features.
Files changed (48) hide show
  1. data/.gitignore +6 -0
  2. data/.travis.yml +9 -0
  3. data/Gemfile +16 -0
  4. data/README.md +233 -0
  5. data/Rakefile +7 -0
  6. data/lib/lotus.rb +232 -0
  7. data/lib/lotus/activity.rb +134 -0
  8. data/lib/lotus/atom/account.rb +50 -0
  9. data/lib/lotus/atom/address.rb +56 -0
  10. data/lib/lotus/atom/author.rb +167 -0
  11. data/lib/lotus/atom/category.rb +41 -0
  12. data/lib/lotus/atom/entry.rb +159 -0
  13. data/lib/lotus/atom/feed.rb +174 -0
  14. data/lib/lotus/atom/generator.rb +40 -0
  15. data/lib/lotus/atom/link.rb +79 -0
  16. data/lib/lotus/atom/name.rb +57 -0
  17. data/lib/lotus/atom/organization.rb +62 -0
  18. data/lib/lotus/atom/portable_contacts.rb +117 -0
  19. data/lib/lotus/atom/source.rb +168 -0
  20. data/lib/lotus/atom/thread.rb +60 -0
  21. data/lib/lotus/author.rb +177 -0
  22. data/lib/lotus/category.rb +45 -0
  23. data/lib/lotus/crypto.rb +146 -0
  24. data/lib/lotus/feed.rb +190 -0
  25. data/lib/lotus/generator.rb +53 -0
  26. data/lib/lotus/identity.rb +59 -0
  27. data/lib/lotus/link.rb +56 -0
  28. data/lib/lotus/notification.rb +220 -0
  29. data/lib/lotus/publisher.rb +40 -0
  30. data/lib/lotus/subscription.rb +117 -0
  31. data/lib/lotus/version.rb +3 -0
  32. data/lotus.gemspec +27 -0
  33. data/spec/activity_spec.rb +84 -0
  34. data/spec/atom/feed_spec.rb +681 -0
  35. data/spec/author_spec.rb +150 -0
  36. data/spec/crypto_spec.rb +138 -0
  37. data/spec/feed_spec.rb +252 -0
  38. data/spec/helper.rb +8 -0
  39. data/spec/identity_spec.rb +67 -0
  40. data/spec/link_spec.rb +30 -0
  41. data/spec/notification_spec.rb +77 -0
  42. data/test/example_feed.atom +393 -0
  43. data/test/example_feed_empty_author.atom +336 -0
  44. data/test/example_feed_false_connected.atom +359 -0
  45. data/test/example_feed_link_without_href.atom +134 -0
  46. data/test/example_page.html +4 -0
  47. data/test/mime_type_bug_feed.atom +874 -0
  48. metadata +204 -0
@@ -0,0 +1,134 @@
1
+ module Lotus
2
+ # This class represents an Activity object for an Lotus::Entry.
3
+ class Activity
4
+ # The object of this activity.
5
+ attr_reader :object
6
+
7
+ # The type of object for this activity.
8
+ #
9
+ # The field can be a String for uncommon types. Several are standard:
10
+ # :article, :audio, :bookmark, :comment, :file, :folder, :group,
11
+ # :list, :note, :person, :photo, :"photo-album", :place, :playlist,
12
+ # :product, :review, :service, :status, :video
13
+ attr_reader :type
14
+
15
+ # The action being invoked in this activity.
16
+ #
17
+ # The field can be a String for uncommon verbs. Several are standard:
18
+ # :favorite, :follow, :like, :"make-friend", :join, :play,
19
+ # :post, :save, :share, :tag, :update
20
+ attr_reader :verb
21
+
22
+ # The target of the action.
23
+ attr_reader :target
24
+
25
+ # Holds a String containing the title of the entry.
26
+ attr_reader :title
27
+
28
+ # Holds an Lotus::Author.
29
+ attr_reader :actor
30
+
31
+ # Holds the content.
32
+ attr_reader :content
33
+
34
+ # Holds the MIME type of the content.
35
+ attr_reader :content_type
36
+
37
+ # Holds the id that uniquely identifies this entry.
38
+ attr_reader :id
39
+
40
+ # Holds the url that represents the entry.
41
+ attr_reader :url
42
+
43
+ # Holds the source of this entry as an Lotus::Feed.
44
+ attr_reader :source
45
+
46
+ # Holds the DateTime of when the entry was published originally.
47
+ attr_reader :published
48
+
49
+ # Holds the DateTime of when the entry was last modified.
50
+ attr_reader :updated
51
+
52
+ # Holds an array of related Lotus::Entry's that this entry is a response
53
+ # to.
54
+ attr_reader :in_reply_to
55
+
56
+ # Create a new entry with the given content.
57
+ #
58
+ # options:
59
+ # :object => The object of this activity.
60
+ # :type => The type of object for this activity.
61
+ # :target => The target of this activity.
62
+ # :verb => The action of the activity.
63
+ #
64
+ # :title => The title of the entry. Defaults: "Untitled"
65
+ # :actor => An Lotus::Author responsible for generating this entry.
66
+ # :content => The content of the entry. Defaults: ""
67
+ # :content_type => The MIME type of the content.
68
+ # :source => An Lotus::Feed where this Entry originated. This
69
+ # should be used when an Entry is copied into this feed
70
+ # from another.
71
+ # :published => The DateTime depicting when the entry was originally
72
+ # published.
73
+ # :updated => The DateTime depicting when the entry was modified.
74
+ # :url => The canonical url of the entry.
75
+ # :id => The unique id that identifies this entry.
76
+ # :activity => The activity this entry represents. Either a single string
77
+ # denoting what type of object this entry represents, or an
78
+ # entire Lotus::Activity when a more detailed description is
79
+ # appropriate.
80
+ # :in_reply_to => An Lotus::Entry for which this entry is a response.
81
+ # Or an array of Lotus::Entry's that this entry is a
82
+ # response to. Use this when this Entry is a reply
83
+ # to an existing Entry.
84
+ def initialize(options = {})
85
+ @object = options[:object]
86
+ @type = options[:type]
87
+ @target = options[:target]
88
+ @verb = options[:verb]
89
+
90
+ @title = options[:title] || "Untitled"
91
+ @actor = options[:actor]
92
+ @content = options[:content] || ""
93
+ @content_type = options[:content_type]
94
+ @source = options[:source]
95
+ @published = options[:published]
96
+ @updated = options[:updated]
97
+ @url = options[:url]
98
+ @id = options[:id]
99
+
100
+ unless options[:in_reply_to].nil? or options[:in_reply_to].is_a?(Array)
101
+ options[:in_reply_to] = [options[:in_reply_to]]
102
+ end
103
+ @in_reply_to = options[:in_reply_to] || []
104
+ end
105
+
106
+ # Returns a hash of all relevant fields.
107
+ def to_hash
108
+ {
109
+ :source => self.source,
110
+ :title => self.title,
111
+ :content => self.content,
112
+ :content_type => self.content_type,
113
+ :published => self.published,
114
+ :updated => self.updated,
115
+ :url => self.url,
116
+ :id => self.id,
117
+ :in_reply_to => self.in_reply_to.dup,
118
+
119
+ :object => self.object,
120
+ :target => self.target,
121
+ :actor => self.actor,
122
+ :verb => self.verb,
123
+ :type => self.type
124
+ }
125
+ end
126
+
127
+ # Returns a string containing the Atom representation of this Activity.
128
+ def to_atom
129
+ require 'lotus/atom/entry'
130
+
131
+ Lotus::Atom::Entry.from_canonical(self).to_xml
132
+ end
133
+ end
134
+ end
@@ -0,0 +1,50 @@
1
+ module Lotus
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 Lotus
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,167 @@
1
+ require 'lotus/activity'
2
+ require 'lotus/atom/name'
3
+ require 'lotus/atom/address'
4
+ require 'lotus/atom/account'
5
+ require 'lotus/atom/organization'
6
+
7
+ module Lotus
8
+ require 'atom'
9
+
10
+ module Atom
11
+ # Holds information about the author of the Feed.
12
+ class Author < ::Atom::Person
13
+ require 'date'
14
+
15
+ include ::Atom::SimpleExtensions
16
+
17
+ # The XML namespace the specifies this content.
18
+ POCO_NAMESPACE = 'http://portablecontacts.net/spec/1.0'
19
+
20
+ # The XML namespace that identifies the conforming specification.
21
+ ACTIVITY_NAMESPACE = 'http://activitystrea.ms/spec/1.0/'
22
+
23
+ add_extension_namespace :activity, ACTIVITY_NAMESPACE
24
+ element 'activity:object-type'
25
+
26
+ namespace ::Atom::NAMESPACE
27
+ element :email
28
+ element :uri
29
+
30
+ elements :links, :class => ::Atom::Link
31
+
32
+ add_extension_namespace :poco, POCO_NAMESPACE
33
+ element 'poco:id'
34
+ element 'poco:organization', :class => Lotus::Atom::Organization
35
+ element 'poco:address', :class => Lotus::Atom::Address
36
+ element 'poco:account', :class => Lotus::Atom::Account
37
+ element 'poco:displayName'
38
+ element 'poco:nickname'
39
+ element 'poco:updated', :class => DateTime, :content_only => true
40
+ element 'poco:published', :class => DateTime, :content_only => true
41
+ element 'poco:birthday', :class => Date, :content_only => true
42
+ element 'poco:anniversary', :class => Date, :content_only => true
43
+ element 'poco:gender'
44
+ element 'poco:note'
45
+ element 'poco:preferredUsername'
46
+
47
+ # unfortunately ratom doesn't handle elements with the same local name well.
48
+ # this is a workaround for that.
49
+ attr_writer :name, :poco_name
50
+
51
+ def name
52
+ @name or self[::Atom::NAMESPACE, 'name'].first
53
+ end
54
+
55
+ def poco_name
56
+ return @poco_name if @poco_name
57
+ name = self[POCO_NAMESPACE, 'name'].first
58
+ if name
59
+ name = "<name>#{name}</name>"
60
+ reader = XML::Reader.string(name)
61
+ reader.read
62
+ reader.read
63
+ Lotus::Atom::Name.new(reader)
64
+ else
65
+ nil
66
+ end
67
+ end
68
+
69
+ def to_xml(*args)
70
+ x = super(*args)
71
+
72
+ if self.name
73
+ node = XML::Node.new('name')
74
+ node << self.name
75
+ x << node
76
+ end
77
+
78
+ if self.poco_name
79
+ x << self.poco_name.to_xml(true, root_name = 'poco:name')
80
+ end
81
+
82
+ x
83
+ end
84
+
85
+ def initialize *args
86
+ self.activity_object_type = "http://activitystrea.ms/schema/1.0/person"
87
+ super(*args)
88
+ end
89
+
90
+ # Gives an instance of an Lotus::Activity that parses the fields
91
+ # having an activity prefix.
92
+ def activity
93
+ Lotus::Activity.new(self)
94
+ end
95
+
96
+ def self.from_canonical(obj)
97
+ hash = obj.to_hash
98
+ hash.keys.each do |k|
99
+ to_k = k
100
+ if k == :display_name
101
+ to_k = :displayName
102
+ elsif k == :preferred_username
103
+ to_k = :preferredUsername
104
+ end
105
+
106
+ if k == :extended_name
107
+ if hash[:extended_name]
108
+ hash[:"poco_name"] = Lotus::Atom::Name.new(hash[:extended_name])
109
+ end
110
+ hash.delete :extended_name
111
+ elsif k == :organization
112
+ if hash[:organization]
113
+ hash[:"poco_organization"] = Lotus::Atom::Organization.new(hash[:organization])
114
+ end
115
+ hash.delete :organization
116
+ elsif k == :address
117
+ if hash[:address]
118
+ hash[:"poco_address"] = Lotus::Atom::Address.new(hash[:address])
119
+ end
120
+ hash.delete :address
121
+ elsif k == :account
122
+ if hash[:account]
123
+ hash[:"poco_account"] = Lotus::Atom::Account.new(hash[:account])
124
+ end
125
+ hash.delete :account
126
+ elsif (k != :uri) && (k != :name) && (k != :email)
127
+ hash[:"poco_#{to_k}"] = hash[k]
128
+ hash.delete k
129
+ end
130
+ end
131
+
132
+ self.new(hash)
133
+ end
134
+
135
+ def to_canonical
136
+ organization = self.poco_organization
137
+ organization = organization.to_canonical if organization
138
+
139
+ address = self.poco_address
140
+ address = address.to_canonical if address
141
+
142
+ account = self.poco_account
143
+ account = account.to_canonical if account
144
+
145
+ ext_name = self.poco_name
146
+ ext_name = ext_name.to_canonical if ext_name
147
+ Lotus::Author.new(:id => self.poco_id,
148
+ :extended_name => ext_name,
149
+ :organization => organization,
150
+ :address => address,
151
+ :account => account,
152
+ :gender => self.poco_gender,
153
+ :note => self.poco_note,
154
+ :nickname => self.poco_nickname,
155
+ :display_name => self.poco_displayName,
156
+ :preferred_username => self.poco_preferredUsername,
157
+ :updated => self.poco_updated,
158
+ :published => self.poco_published,
159
+ :birthday => self.poco_birthday,
160
+ :anniversary => self.poco_anniversary,
161
+ :uri => self.uri,
162
+ :email => self.email,
163
+ :name => self.name)
164
+ end
165
+ end
166
+ end
167
+ end
@@ -0,0 +1,41 @@
1
+ require 'lotus/category'
2
+
3
+ module Lotus
4
+ require 'atom'
5
+
6
+ module Atom
7
+ # This class represents an Lotus 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
+ Lotus::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
+