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.
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
+