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.
Files changed (95) hide show
  1. data/.gitignore +6 -0
  2. data/.travis.yml +9 -0
  3. data/Gemfile +20 -0
  4. data/README.md +242 -0
  5. data/Rakefile +7 -0
  6. data/assets/lotus_logo_purple.png +0 -0
  7. data/assets/lotus_logo_purple.svg +262 -0
  8. data/lib/nelumba.rb +47 -0
  9. data/lib/nelumba/activity.rb +250 -0
  10. data/lib/nelumba/application.rb +11 -0
  11. data/lib/nelumba/article.rb +11 -0
  12. data/lib/nelumba/atom/account.rb +50 -0
  13. data/lib/nelumba/atom/address.rb +56 -0
  14. data/lib/nelumba/atom/author.rb +176 -0
  15. data/lib/nelumba/atom/category.rb +41 -0
  16. data/lib/nelumba/atom/comment.rb +96 -0
  17. data/lib/nelumba/atom/entry.rb +216 -0
  18. data/lib/nelumba/atom/feed.rb +198 -0
  19. data/lib/nelumba/atom/generator.rb +40 -0
  20. data/lib/nelumba/atom/link.rb +79 -0
  21. data/lib/nelumba/atom/name.rb +57 -0
  22. data/lib/nelumba/atom/organization.rb +62 -0
  23. data/lib/nelumba/atom/person.rb +179 -0
  24. data/lib/nelumba/atom/portable_contacts.rb +117 -0
  25. data/lib/nelumba/atom/source.rb +179 -0
  26. data/lib/nelumba/atom/thread.rb +60 -0
  27. data/lib/nelumba/audio.rb +39 -0
  28. data/lib/nelumba/badge.rb +11 -0
  29. data/lib/nelumba/binary.rb +52 -0
  30. data/lib/nelumba/bookmark.rb +30 -0
  31. data/lib/nelumba/category.rb +49 -0
  32. data/lib/nelumba/collection.rb +34 -0
  33. data/lib/nelumba/comment.rb +47 -0
  34. data/lib/nelumba/crypto.rb +144 -0
  35. data/lib/nelumba/device.rb +11 -0
  36. data/lib/nelumba/discover.rb +362 -0
  37. data/lib/nelumba/event.rb +57 -0
  38. data/lib/nelumba/feed.rb +173 -0
  39. data/lib/nelumba/file.rb +43 -0
  40. data/lib/nelumba/generator.rb +53 -0
  41. data/lib/nelumba/group.rb +11 -0
  42. data/lib/nelumba/identity.rb +63 -0
  43. data/lib/nelumba/image.rb +30 -0
  44. data/lib/nelumba/link.rb +56 -0
  45. data/lib/nelumba/note.rb +34 -0
  46. data/lib/nelumba/notification.rb +229 -0
  47. data/lib/nelumba/object.rb +251 -0
  48. data/lib/nelumba/person.rb +306 -0
  49. data/lib/nelumba/place.rb +34 -0
  50. data/lib/nelumba/product.rb +30 -0
  51. data/lib/nelumba/publisher.rb +44 -0
  52. data/lib/nelumba/question.rb +30 -0
  53. data/lib/nelumba/review.rb +30 -0
  54. data/lib/nelumba/service.rb +11 -0
  55. data/lib/nelumba/subscription.rb +117 -0
  56. data/lib/nelumba/version.rb +3 -0
  57. data/lib/nelumba/video.rb +43 -0
  58. data/nelumba.gemspec +28 -0
  59. data/spec/activity_spec.rb +116 -0
  60. data/spec/application_spec.rb +136 -0
  61. data/spec/article_spec.rb +136 -0
  62. data/spec/atom/comment_spec.rb +455 -0
  63. data/spec/atom/feed_spec.rb +684 -0
  64. data/spec/audio_spec.rb +164 -0
  65. data/spec/badge_spec.rb +136 -0
  66. data/spec/binary_spec.rb +218 -0
  67. data/spec/bookmark.rb +150 -0
  68. data/spec/collection_spec.rb +152 -0
  69. data/spec/comment_spec.rb +128 -0
  70. data/spec/crypto_spec.rb +126 -0
  71. data/spec/device_spec.rb +136 -0
  72. data/spec/event_spec.rb +239 -0
  73. data/spec/feed_spec.rb +252 -0
  74. data/spec/file_spec.rb +190 -0
  75. data/spec/group_spec.rb +136 -0
  76. data/spec/helper.rb +10 -0
  77. data/spec/identity_spec.rb +67 -0
  78. data/spec/image_spec.rb +150 -0
  79. data/spec/link_spec.rb +30 -0
  80. data/spec/note_spec.rb +163 -0
  81. data/spec/notification_spec.rb +89 -0
  82. data/spec/person_spec.rb +244 -0
  83. data/spec/place_spec.rb +162 -0
  84. data/spec/product_spec.rb +150 -0
  85. data/spec/question_spec.rb +156 -0
  86. data/spec/review_spec.rb +149 -0
  87. data/spec/service_spec.rb +136 -0
  88. data/spec/video_spec.rb +164 -0
  89. data/test/example_feed.atom +393 -0
  90. data/test/example_feed_empty_author.atom +336 -0
  91. data/test/example_feed_false_connected.atom +359 -0
  92. data/test/example_feed_link_without_href.atom +134 -0
  93. data/test/example_page.html +4 -0
  94. data/test/mime_type_bug_feed.atom +874 -0
  95. metadata +288 -0
@@ -0,0 +1,179 @@
1
+ require 'nelumba/person'
2
+ require 'nelumba/category'
3
+ require 'nelumba/generator'
4
+
5
+ require 'nelumba/atom/generator'
6
+ require 'nelumba/atom/category'
7
+ require 'nelumba/atom/person'
8
+ require 'nelumba/atom/link'
9
+
10
+ module Nelumba
11
+ require 'atom'
12
+
13
+ module Atom
14
+ # This class represents an OStatus Feed object.
15
+ class Source < ::Atom::Source
16
+ require 'open-uri'
17
+
18
+ include ::Atom::SimpleExtensions
19
+
20
+ # The XML namespace that identifies the conforming specification.
21
+ ACTIVITY_NAMESPACE = 'http://activitystrea.ms/spec/1.0/'
22
+
23
+ # The XML namespace the specifies this content.
24
+ POCO_NAMESPACE = 'http://portablecontacts.net/spec/1.0'
25
+
26
+ namespace ::Atom::NAMESPACE
27
+
28
+ add_extension_namespace :poco, POCO_NAMESPACE
29
+ add_extension_namespace :activity, ACTIVITY_NAMESPACE
30
+ element :id, :rights, :icon, :logo
31
+ element :generator, :class => Nelumba::Atom::Generator
32
+ element :title, :class => ::Atom::Content
33
+ element :subtitle, :class => ::Atom::Content
34
+ element :published, :class => Time, :content_only => true
35
+ element :updated, :class => Time, :content_only => true
36
+ elements :links, :class => ::Atom::Link
37
+ elements :authors, :class => Nelumba::Atom::Author
38
+ elements :contributors, :class => Nelumba::Atom::Person
39
+ elements :categories, :class => Nelumba::Atom::Category
40
+
41
+ # Creates an Atom generator for the given Nelumba::Feed.
42
+ def self.from_canonical(obj)
43
+ hash = obj.to_hash
44
+ hash.delete :items
45
+ hash.delete :author
46
+ hash.delete :total_items
47
+ hash.delete :display_name
48
+ hash.delete :content
49
+ hash.delete :summary
50
+
51
+ hash.delete :text
52
+ hash.delete :html
53
+
54
+ # Ensure that the generator is encoded.
55
+ if hash[:generator]
56
+ hash[:generator] = Nelumba::Atom::Generator.from_canonical(hash[:generator])
57
+ end
58
+
59
+ hash[:links] ||= []
60
+
61
+ if hash[:salmon_url]
62
+ hash[:links] << ::Atom::Link.new(:rel => "salmon", :href => hash[:salmon_url])
63
+ end
64
+ hash.delete :salmon_url
65
+
66
+ if hash[:url]
67
+ hash[:links] << ::Atom::Link.new(:rel => "self", :href => hash[:url])
68
+ end
69
+ hash.delete :url
70
+
71
+ hash[:hubs].each {|h|
72
+ hash[:links] << ::Atom::Link.new(:rel => "hub", :href => h)
73
+ }
74
+ hash.delete :hubs
75
+
76
+ hash[:authors].map! {|a|
77
+ Nelumba::Atom::Author.from_canonical(a)
78
+ }
79
+
80
+ hash[:contributors].map! {|a|
81
+ Nelumba::Atom::Person.from_canonical(a)
82
+ }
83
+
84
+ hash[:categories].map! {|c|
85
+ Nelumba::Atom::Category.from_canonical(c)
86
+ }
87
+
88
+ # title/subtitle content type
89
+ node = XML::Node.new("title")
90
+ node['type'] = hash[:title_type] if hash[:title_type]
91
+ node << hash[:title]
92
+
93
+ xml = XML::Reader.string(node.to_s)
94
+ xml.read
95
+ hash[:title] = ::Atom::Content.parse(xml)
96
+ hash.delete :title_type
97
+
98
+ hash[:id] = hash[:uid]
99
+ hash.delete :uid
100
+
101
+ if hash[:subtitle]
102
+ node = XML::Node.new("subtitle")
103
+ node['type'] = hash[:subtitle_type] if hash[:subtitle_type]
104
+ node << hash[:subtitle]
105
+
106
+ xml = XML::Reader.string(node.to_s)
107
+ xml.read
108
+ hash[:subtitle] = ::Atom::Content.parse(xml)
109
+ else
110
+ hash.delete :subtitle
111
+ end
112
+ hash.delete :subtitle_type
113
+
114
+ self.new(hash)
115
+ end
116
+
117
+ def to_canonical
118
+ generator = nil
119
+ generator = self.generator.to_canonical if self.generator
120
+
121
+ salmon_url = nil
122
+ if self.link('salmon').any?
123
+ salmon_url = self.link('salmon').first.href
124
+ end
125
+
126
+ url = self.url
127
+
128
+ categories = self.categories.map(&:to_canonical)
129
+
130
+ Nelumba::Feed.new(:title => self.title,
131
+ :title_type => self.title ? self.title.type : nil,
132
+ :subtitle => self.subtitle,
133
+ :subtitle_type => self.subtitle ? self.subtitle.type : nil,
134
+ :id => self.id,
135
+ :url => url,
136
+ :categories => categories,
137
+ :icon => self.icon,
138
+ :logo => self.logo,
139
+ :rights => self.rights,
140
+ :published => self.published,
141
+ :updated => self.updated,
142
+ :authors => self.authors.map(&:to_canonical),
143
+ :contributors => self.contributors.map(&:to_canonical),
144
+ :hubs => self.hubs,
145
+ :salmon_url => salmon_url,
146
+ :generator => generator)
147
+ end
148
+
149
+ # Returns an array of ::Atom::Link instances for all link tags
150
+ # that have a rel equal to that given by attribute.
151
+ #
152
+ # For example:
153
+ # link(:hub).first.href -- Gets the first link tag with rel="hub" and
154
+ # returns the contents of the href attribute.
155
+ #
156
+ def link(attribute)
157
+ links.find_all { |l| l.rel == attribute.to_s }
158
+ end
159
+
160
+ # Returns an array of URLs for each hub link tag.
161
+ def hubs
162
+ link('hub').map { |link| link.href }
163
+ end
164
+
165
+ # Returns a string of the url for this feed.
166
+ def url
167
+ if links.alternate
168
+ links.alternate.href
169
+ elsif links.self
170
+ links.self.href
171
+ else
172
+ links.map.each do |l|
173
+ l.href
174
+ end.compact.first
175
+ end
176
+ end
177
+ end
178
+ end
179
+ end
@@ -0,0 +1,60 @@
1
+ module Nelumba
2
+ module Atom
3
+ # This will parse the Thread Atom extension
4
+ class Thread
5
+ require 'xml/libxml'
6
+ require 'atom/xml/parser.rb'
7
+
8
+ include ::Atom::Xml::Parseable
9
+ attribute :ref, :type, :source
10
+ uri_attribute :href
11
+
12
+ def initialize(o)
13
+ case o
14
+ when XML::Reader
15
+ if current_node_is?(o, 'in-reply-to')
16
+ parse(o, :once => true)
17
+ else
18
+ raise ArgumentError, "Thread created with node other than thr:in-reply-to: #{o.name}"
19
+ end
20
+ when Hash
21
+ [:href, :ref, :type, :source].each do |attr|
22
+ self.send("#{attr}=", o[attr])
23
+ end
24
+ else
25
+ raise ArgumentError, "Don't know how to handle #{o}"
26
+ end
27
+ end
28
+
29
+ def length=(v)
30
+ @length = v.to_i
31
+ end
32
+
33
+ def to_s
34
+ self.href
35
+ end
36
+
37
+ def ==(o)
38
+ o.respond_to?(:href) && o.href == self.href
39
+ end
40
+
41
+ def self.from_canonical(obj)
42
+ self.new(obj.to_hash)
43
+ end
44
+
45
+ def to_canonical
46
+ Nelumba::Activity.new(:url => self.href,
47
+ :id => self.ref)
48
+ end
49
+
50
+ def info
51
+ {
52
+ :ref => self.ref,
53
+ :type => self.type,
54
+ :source => self.source,
55
+ :href => self.href
56
+ }
57
+ end
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,39 @@
1
+ module Nelumba
2
+ class Audio
3
+ include Nelumba::Object
4
+
5
+ # A fragment of HTML markup that, when embedded within another HTML page,
6
+ # provides an interactive user-interface for viewing or listening to the
7
+ # audio stream.
8
+ attr_reader :embed_code
9
+
10
+ # A MediaLink to the audio content itself.
11
+ attr_reader :stream
12
+
13
+ # Creates a new Audio activity object.
14
+ def initialize(options = {})
15
+ super options
16
+
17
+ @embed_code = options[:embed_code]
18
+ @stream = options[:stream]
19
+ end
20
+
21
+ # Returns a hash of all relevant fields.
22
+ def to_hash
23
+ {
24
+ :embed_code => @embed_code,
25
+ :stream => @stream
26
+ }.merge(super)
27
+ end
28
+
29
+ # Returns a hash of all relevant fields with JSON activity streams
30
+ # conventions.
31
+ def to_json_hash
32
+ {
33
+ :objectType => "audio",
34
+ :embedCode => @embed_code,
35
+ :stream => @stream
36
+ }.merge(super)
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,11 @@
1
+ module Nelumba
2
+ class Badge
3
+ include Nelumba::Object
4
+
5
+ def to_json_hash
6
+ {
7
+ :objectType => "badge"
8
+ }.merge(super)
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,52 @@
1
+ module Nelumba
2
+ class Binary
3
+ include Nelumba::Object
4
+
5
+ attr_reader :data
6
+ attr_reader :length
7
+
8
+ attr_reader :md5
9
+ attr_reader :compression
10
+
11
+ attr_reader :file_url
12
+ attr_reader :mime_type
13
+
14
+ def initialize(options = {}, &blk)
15
+ init(options, &blk)
16
+ end
17
+
18
+ def init(options = {}, &blk)
19
+ super(options, &blk)
20
+
21
+ @data = options[:data]
22
+ @compression = options[:compression]
23
+ @md5 = options[:md5]
24
+ @file_url = options[:file_url]
25
+ @mime_type = options[:mime_type]
26
+ @length = options[:length]
27
+ end
28
+
29
+ def to_hash
30
+ {
31
+ :data => @data,
32
+ :compression => @compression,
33
+ :md5 => @md5,
34
+ :file_url => @file_url,
35
+ :mime_type => @mime_type,
36
+ :length => @length
37
+ }.merge(super)
38
+ end
39
+
40
+ def to_json_hash
41
+ {
42
+ :objectType => "binary",
43
+ :data => @data,
44
+ :compression => @compression,
45
+ :md5 => @md5,
46
+ :fileUrl => @file_url,
47
+ :mimeType => @mime_type,
48
+ :length => @length
49
+ }.merge(super)
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,30 @@
1
+ module Nelumba
2
+ class Bookmark
3
+ include Nelumba::Object
4
+
5
+ attr_reader :target_url
6
+
7
+ def initialize(options = {}, &blk)
8
+ init(options, &blk)
9
+ end
10
+
11
+ def init(options = {}, &blk)
12
+ super(options, &blk)
13
+
14
+ @target_url = options[:target_url]
15
+ end
16
+
17
+ def to_hash
18
+ {
19
+ :target_url => @target_url
20
+ }.merge(super)
21
+ end
22
+
23
+ def to_json_hash
24
+ {
25
+ :objectType => "bookmark",
26
+ :targetUrl => @target_url
27
+ }.merge(super)
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,49 @@
1
+ module Nelumba
2
+ # This element conveys information about a category associated with an entry
3
+ # or feed. There is no defined meaning to the content according to the Atom
4
+ # specification.
5
+ class Category
6
+ # Holds the base URI for relative URIs contained in scheme.
7
+ attr_reader :base
8
+
9
+ # Holds the language of term and label, when it exists. The language
10
+ # should be specified as RFC 3066 as either 2 or 3 letter codes.
11
+ # For example: 'en' for English or more specifically 'en-us'
12
+ attr_reader :lang
13
+
14
+ # Holds the optional scheme used for categorization.
15
+ attr_reader :scheme
16
+
17
+ # Holds the string identifying the category to which the entry or
18
+ # feed belongs.
19
+ attr_reader :term
20
+
21
+ # Holds the string that provides a human-readable label for display in
22
+ # end-user applications. The content of this field is language sensitive.
23
+ attr_reader :label
24
+
25
+ # Create a Category to apply to a feed or entry.
26
+ def initialize(options = {})
27
+ init(options)
28
+ end
29
+
30
+ def init(options = {})
31
+ @base = options[:base]
32
+ @lang = options[:lang]
33
+ @scheme = options[:scheme]
34
+ @term = options[:term]
35
+ @label = options[:label]
36
+ end
37
+
38
+ # Yields a Hash that represents this category.
39
+ def to_hash
40
+ {
41
+ :base => @base,
42
+ :lang => @lang,
43
+ :scheme => @scheme,
44
+ :term => @term,
45
+ :label => @label
46
+ }
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,34 @@
1
+ module Nelumba
2
+ class Collection
3
+ include Nelumba::Object
4
+
5
+ attr_reader :items
6
+ attr_reader :total_items
7
+
8
+ def initialize(options = {}, &blk)
9
+ init(options, &blk)
10
+ end
11
+
12
+ def init(options = {}, &blk)
13
+ super(options, &blk)
14
+
15
+ @items = options[:items] || []
16
+ @total_items = options[:total_items] || @items.count
17
+ end
18
+
19
+ def to_hash
20
+ {
21
+ :items => (self.items || []).dup,
22
+ :total_items => self.total_items || self.items.count
23
+ }.merge(super)
24
+ end
25
+
26
+ def to_json_hash
27
+ {
28
+ :objectType => "collection",
29
+ :items => (self.items || []).dup,
30
+ :totalItems => self.total_items || self.items.count
31
+ }.merge(super)
32
+ end
33
+ end
34
+ end