yam 0.0.6 → 1.0.0

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 (88) hide show
  1. data.tar.gz.sig +0 -0
  2. data/.travis.yml +5 -0
  3. data/.yardopts +10 -0
  4. data/AUTHORS +1 -0
  5. data/CHANGELOG.md +7 -0
  6. data/CONTRIBUTING.md +0 -7
  7. data/Gemfile +27 -1
  8. data/README.md +190 -67
  9. data/Rakefile +9 -3
  10. data/certs/public.pem +20 -0
  11. data/lib/yammer.rb +47 -0
  12. data/lib/yammer/api.rb +29 -0
  13. data/lib/yammer/api/autocomplete.rb +39 -0
  14. data/lib/yammer/api/group.rb +92 -0
  15. data/lib/yammer/api/group_membership.rb +46 -0
  16. data/lib/yammer/api/invitation.rb +39 -0
  17. data/lib/yammer/api/like.rb +57 -0
  18. data/lib/yammer/api/message.rb +227 -0
  19. data/lib/yammer/api/network.rb +35 -0
  20. data/lib/yammer/api/notification.rb +32 -0
  21. data/lib/yammer/api/open_graph_object.rb +92 -0
  22. data/lib/yammer/api/pending_attachment.rb +64 -0
  23. data/lib/yammer/api/search.rb +42 -0
  24. data/lib/yammer/api/subscription.rb +32 -0
  25. data/lib/yammer/api/thread.rb +37 -0
  26. data/lib/yammer/api/topic.rb +37 -0
  27. data/lib/yammer/api/user.rb +168 -0
  28. data/lib/yammer/api_handler.rb +27 -0
  29. data/lib/yammer/api_response.rb +57 -0
  30. data/lib/yammer/base.rb +208 -0
  31. data/lib/yammer/client.rb +100 -0
  32. data/lib/yammer/configurable.rb +81 -0
  33. data/lib/yammer/error.rb +75 -0
  34. data/lib/yammer/group.rb +27 -0
  35. data/lib/yammer/group_membership.rb +25 -0
  36. data/lib/yammer/http_adapter.rb +100 -0
  37. data/lib/yammer/identity_map.rb +56 -0
  38. data/lib/yammer/message.rb +32 -0
  39. data/lib/yammer/message_body.rb +27 -0
  40. data/lib/yammer/pending_attachment.rb +19 -0
  41. data/lib/yammer/thread.rb +58 -0
  42. data/lib/yammer/user.rb +66 -0
  43. data/lib/yammer/version.rb +32 -0
  44. data/{lib/yam/configuration.rb → spec/api/autocomplete_spec.rb} +18 -23
  45. data/spec/api/group_membership_spec.rb +48 -0
  46. data/spec/api/group_spec.rb +76 -0
  47. data/spec/api/invitation_spec.rb +60 -0
  48. data/spec/api/like_spec.rb +46 -0
  49. data/spec/api/message_spec.rb +136 -0
  50. data/spec/api/network_spec.rb +41 -0
  51. data/{lib/yam/client.rb → spec/api/notification_spec.rb} +22 -4
  52. data/spec/api/open_graph_object_spec.rb +67 -0
  53. data/spec/api/pending_attachment_spec.rb +56 -0
  54. data/{lib/yam/constants.rb → spec/api/search_spec.rb} +21 -8
  55. data/spec/api/subscription_spec.rb +41 -0
  56. data/{lib/yam.rb → spec/api/thread_spec.rb} +19 -12
  57. data/{lib/yam/request.rb → spec/api/topic_spec.rb} +19 -15
  58. data/spec/api/user_spec.rb +108 -0
  59. data/spec/api_response.rb +86 -0
  60. data/spec/client_spec.rb +364 -0
  61. data/spec/error_spec.rb +88 -0
  62. data/spec/fixtures/group.json +1 -0
  63. data/spec/fixtures/message.json +1 -0
  64. data/spec/fixtures/messages_in_thread.json +1 -0
  65. data/spec/fixtures/portal_thread.json +1 -0
  66. data/spec/fixtures/private_thread.json +1 -0
  67. data/spec/fixtures/public_thread.json +1 -0
  68. data/spec/fixtures/user.json +1 -0
  69. data/spec/fixtures/users_followed.json +1 -0
  70. data/spec/fixtures/users_following.json +1 -0
  71. data/spec/http_adapter_spec.rb +109 -0
  72. data/spec/identity_map_spec.rb +127 -0
  73. data/spec/mocks/attachment.txt +1 -0
  74. data/spec/model/base_spec.rb +196 -0
  75. data/spec/model/group_membership_spec.rb +57 -0
  76. data/spec/model/group_spec.rb +73 -0
  77. data/spec/model/message_spec.rb +74 -0
  78. data/spec/model/thread_spec.rb +91 -0
  79. data/spec/model/user_spec.rb +222 -0
  80. data/spec/spec_helper.rb +39 -14
  81. data/yam.gemspec +50 -28
  82. metadata +270 -187
  83. metadata.gz.sig +0 -0
  84. data/lib/yam/api.rb +0 -53
  85. data/lib/yam/connection.rb +0 -57
  86. data/lib/yam/version.rb +0 -20
  87. data/spec/yam/client_spec.rb +0 -50
  88. data/spec/yam_spec.rb +0 -87
@@ -0,0 +1,27 @@
1
+ # Copyright (c) Microsoft Corporation
2
+ # All rights reserved.
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
6
+ #
7
+ # THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR
8
+ # CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING
9
+ # WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF TITLE,
10
+ # FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR NON-INFRINGEMENT.
11
+
12
+ # See the Apache Version 2.0 License for specific language governing
13
+ # permissions and limitations under the License.
14
+
15
+ module Yammer
16
+ module ApiHandler
17
+
18
+ def api_handler
19
+ establish_api_handler
20
+ end
21
+
22
+ def establish_api_handler(opts={})
23
+ Yammer::Client.new(opts)
24
+ end
25
+
26
+ end
27
+ end
@@ -0,0 +1,57 @@
1
+ # Copyright (c) Microsoft Corporation
2
+ # All rights reserved.
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
6
+ #
7
+ # THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR
8
+ # CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING
9
+ # WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF TITLE,
10
+ # FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR NON-INFRINGEMENT.
11
+
12
+ # See the Apache Version 2.0 License for specific language governing
13
+ # permissions and limitations under the License.
14
+
15
+ module Yammer
16
+ class ApiResponse
17
+
18
+ attr_reader :code, :headers
19
+
20
+ def initialize(headers, body, code)
21
+ @headers = headers
22
+ @body = body
23
+ @code = code.to_i
24
+ end
25
+
26
+ def raw_body
27
+ @body
28
+ end
29
+
30
+ def body
31
+ @parsed_body ||= parse(@body)
32
+ end
33
+
34
+ def empty?
35
+ @body.nil? || @body.strip.empty?
36
+ end
37
+
38
+ def success?
39
+ @code == 200
40
+ end
41
+
42
+ def created?
43
+ @code == 201
44
+ end
45
+
46
+ private
47
+
48
+ def parse(body)
49
+ case body
50
+ when /\A^\s*$\z/, nil
51
+ nil
52
+ else
53
+ MultiJson.load(body, :symbolize_keys => true)
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,208 @@
1
+ # Copyright (c) Microsoft Corporation
2
+ # All rights reserved.
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
6
+ #
7
+ # THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR
8
+ # CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING
9
+ # WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF TITLE,
10
+ # FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR NON-INFRINGEMENT.
11
+
12
+ # See the Apache Version 2.0 License for specific language governing
13
+ # permissions and limitations under the License.
14
+
15
+ module Yammer
16
+ class Base
17
+ class << self
18
+ include ApiHandler
19
+
20
+ # Returns the non-qualified class name
21
+ # @!scope class
22
+ def base_name
23
+ @base_name ||= begin
24
+ word = "#{name.split(/::/).last}"
25
+ word.gsub!(/::/, '/')
26
+ word.gsub!(/([A-Z]+)([A-Z][a-z])/,'\1_\2')
27
+ word.gsub!(/([a-z\d])([A-Z])/,'\1_\2')
28
+ word.tr!("-", "_")
29
+ word.downcase!
30
+ word
31
+ end
32
+ end
33
+
34
+ # Fetches JSON reprsentation for object model with provided `id`
35
+ # and returns a model instance with attributes
36
+ # @return [Yammer::Base]
37
+ # @param id [Integer]
38
+ # @!scope class
39
+ def get(id)
40
+ attrs = fetch(id)
41
+ attrs ? new(attrs) : nil
42
+ end
43
+
44
+
45
+ # @!scope class
46
+ def fetch(id)
47
+ return unless identity_map
48
+ attributes = identity_map.get("#{base_name}_#{id}")
49
+ unless attributes
50
+ result = api_handler.send("get_#{base_name}", id)
51
+ attributes = result.empty? ? nil : result.body
52
+ unless attributes.empty?
53
+ identity_map.put("#{base_name}_#{id}", attributes)
54
+ end
55
+ end
56
+ attributes
57
+ end
58
+
59
+ # @!scope class
60
+ def identity_map
61
+ @identity_map ||= Yammer::IdentityMap.new
62
+ end
63
+
64
+ # Returns a hash of all attributes that are meant to trigger an HTTP request
65
+ # @!scope class
66
+ def model_attributes
67
+ @model_attributes ||= {}
68
+ end
69
+
70
+ protected
71
+
72
+ def attr_accessor_deffered(*symbols)
73
+ symbols.each do |key|
74
+ # track attributes that should trigger a fetch
75
+ model_attributes[key] = false
76
+
77
+ # getter
78
+ define_method(key.to_s) do
79
+ load_deferred_attribute!(key)
80
+ instance_variable_get("@#{key}")
81
+ end
82
+
83
+ # setter
84
+ define_method("#{key}=") do |value|
85
+ load_deferred_attribute!(key)
86
+ if persisted? && loaded?
87
+ @modified_attributes[key] = value
88
+ else
89
+ @attrs[key] = value
90
+ end
91
+ instance_variable_set("@#{key}", value)
92
+ end
93
+ end
94
+ end
95
+ end
96
+
97
+ attr_reader :id, :attrs
98
+
99
+ def initialize(props={})
100
+ @klass = self.class
101
+ @modified_attributes = {}
102
+ @new_record = true
103
+ @loaded = false
104
+ @attrs = props
105
+ self.id = @attrs.delete(:id)
106
+ self.update(@attrs)
107
+
108
+ yield self if block_given?
109
+ end
110
+
111
+ def api_handler
112
+ @klass.api_handler
113
+ end
114
+
115
+ def base_name
116
+ @klass.base_name
117
+ end
118
+
119
+ def new_record?
120
+ @new_record
121
+ end
122
+
123
+ def persisted?
124
+ !new_record?
125
+ end
126
+
127
+ def changes
128
+ @modified_attributes
129
+ end
130
+
131
+ def modified?
132
+ !changes.empty?
133
+ end
134
+
135
+ def loaded?
136
+ @loaded
137
+ end
138
+
139
+ def load!
140
+ @attrs = @klass.fetch(@id)
141
+ @loaded = true
142
+ update(@attrs)
143
+ self
144
+ end
145
+
146
+ def reload!
147
+ reset!
148
+ load!
149
+ end
150
+
151
+ def save
152
+ return self if ((persisted? && @modified_attributes.empty?) || @attrs.empty?)
153
+
154
+ result = if new_record?
155
+ api_handler.send("create_#{base_name}", @attrs)
156
+ else
157
+ api_handler.send("update_#{base_name}", @id, @modified_attributes)
158
+ end
159
+ @modified_attributes = {}
160
+ self
161
+ end
162
+
163
+ def delete!
164
+ return if new_record?
165
+ result = api_handler.send("delete_#{base_name}", @id)
166
+ result.success?
167
+ end
168
+
169
+ private
170
+
171
+ def id=(model_id)
172
+ return if model_id.nil?
173
+ @id = model_id.to_i
174
+ @new_record = false
175
+ end
176
+
177
+ # clear the entire class
178
+ def reset!
179
+ @modified_attributes = {}
180
+ @attrs = {}
181
+ @new_record = true
182
+ @loaded = false
183
+ end
184
+
185
+ protected
186
+ # loads model
187
+ def load_deferred_attribute!(key)
188
+ if @attrs.empty? && persisted? && !loaded?
189
+ load!
190
+ if !@attrs.has_key?(key)
191
+ raise "The key: #{key} appears not to be supported for model: #{self.base_name} \n #{@attrs.keys.inspect}"
192
+ end
193
+ end
194
+ end
195
+
196
+ # set all fetchable attributes
197
+ def update(attrs={})
198
+ attrs.each do |key, value|
199
+ send("#{key}=", value)
200
+ end
201
+ if persisted? && !loaded?
202
+ @loaded = @klass.model_attributes.keys.inject(true) do |result, key|
203
+ result && @attrs.has_key?(key)
204
+ end
205
+ end
206
+ end
207
+ end
208
+ end
@@ -0,0 +1,100 @@
1
+ # Copyright (c) Microsoft Corporation
2
+ # All rights reserved.
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
6
+ #
7
+ # THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR
8
+ # CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING
9
+ # WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF TITLE,
10
+ # FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR NON-INFRINGEMENT.
11
+
12
+ # See the Apache Version 2.0 License for specific language governing
13
+ # permissions and limitations under the License.
14
+
15
+ require 'yammer/api'
16
+ require 'yammer/configurable'
17
+ require 'yammer/http_adapter'
18
+
19
+ module Yammer
20
+ class Client
21
+
22
+ include Yammer::Configurable
23
+ include Yammer::Api::User
24
+ include Yammer::Api::Group
25
+ include Yammer::Api::GroupMembership
26
+ include Yammer::Api::Message
27
+ include Yammer::Api::Thread
28
+ include Yammer::Api::Topic
29
+ include Yammer::Api::Network
30
+ include Yammer::Api::Search
31
+ include Yammer::Api::Like
32
+ include Yammer::Api::Notification
33
+ include Yammer::Api::Autocomplete
34
+ include Yammer::Api::Invitation
35
+ include Yammer::Api::PendingAttachment
36
+ include Yammer::Api::Subscription
37
+ include Yammer::Api::OpenGraphObject
38
+
39
+ attr_reader :site_url, :default_headers, :connection_options
40
+
41
+ attr_accessor :client_id, :client_secret, :access_token
42
+
43
+ def initialize(opts={})
44
+ Yammer::Configurable.keys.each do |key|
45
+ case key
46
+ when :headers, :connection_options
47
+ value = Yammer.instance_variable_get(:"@#{key}").merge(opts.fetch(key, {}))
48
+ else
49
+ value = opts.fetch(key, Yammer.instance_variable_get(:"@#{key}"))
50
+ end
51
+ instance_variable_set(:"@#{key}", value)
52
+ end
53
+ end
54
+
55
+ # makes a GET request
56
+ def get(path, params={})
57
+ request(:get, path, params)
58
+ end
59
+
60
+ # makes a PUT request
61
+ def put(path, params={})
62
+ request(:put, path, params)
63
+ end
64
+
65
+ # makes a POST request
66
+ def post(path, params={})
67
+ request(:post, path, params)
68
+ end
69
+
70
+ # makes a DELETE request
71
+ def delete(path, params={})
72
+ request(:delete, path, params)
73
+ end
74
+
75
+ private
76
+
77
+ # returns an instance of the http adapter
78
+ # if none is specified, the default is Yammer::HttpConnection
79
+ # @!visibility private
80
+ def http_client
81
+ @http_client ||= @http_adapter.new(@site_url, @connection_options)
82
+ end
83
+
84
+ # Makes an HTTP request using the provided parameters
85
+ # @raise [Yammer::Error::Unauthorized]
86
+ # @param method [string]
87
+ # @param path [string]
88
+ # @param params [Hash]
89
+ # @return [Yammer::ApiResponse]
90
+ # @!visibility private
91
+ def request(method, path, params={})
92
+ headers = @default_headers.merge({'Authorization' => "Bearer #{@access_token}"})
93
+ result = http_client.send_request(method, path, {
94
+ :params => params,
95
+ :headers => headers
96
+ })
97
+ result
98
+ end
99
+ end
100
+ end
@@ -0,0 +1,81 @@
1
+ # Copyright (c) Microsoft Corporation
2
+ # All rights reserved.
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
6
+ #
7
+ # THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR
8
+ # CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING
9
+ # WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF TITLE,
10
+ # FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR NON-INFRINGEMENT.
11
+
12
+ # See the Apache Version 2.0 License for specific language governing
13
+ # permissions and limitations under the License.
14
+
15
+ require 'yammer/http_adapter'
16
+
17
+ module Yammer
18
+ module Configurable
19
+
20
+ ENDPOINT = 'https://www.yammer.com' unless defined? ENDPOINT
21
+ HTTP_ADAPTER = Yammer::HttpAdapter unless defined? HTTP_CONNECTION
22
+
23
+ attr_accessor :client_id, :client_secret, :access_token, :site_url,
24
+ :connection_options, :default_headers, :http_adapter
25
+
26
+ # Return a hash with the default options
27
+ # @return [Hash]
28
+ def self.default_options
29
+ {
30
+ :site_url => ENDPOINT,
31
+ :client_id => ENV['YAMMER_CLIENT_ID'],
32
+ :client_secret => ENV['YAMMER_CLIENT_SECRET'],
33
+ :access_token => ENV['YAMMER_ACCESS_TOKEN'],
34
+ :http_adapter => HTTP_ADAPTER,
35
+ :connection_options => { :max_redirects => 5, :verify_ssl => true },
36
+ :default_headers => {
37
+ 'Accept' => 'application/json',
38
+ 'User-Agent' => "Yammer Ruby Gem #{Yammer::Version}"
39
+ }
40
+ }
41
+ end
42
+
43
+ # @return [Array<String>]
44
+ def self.keys
45
+ self.default_options.keys
46
+ end
47
+
48
+ # @return [Hash]
49
+ def options
50
+ Hash[Yammer::Configurable.keys.map{|key| [key, instance_variable_get(:"@#{key}")]}]
51
+ end
52
+
53
+ def reset!
54
+ Yammer::Configurable.keys.each do |key|
55
+ instance_variable_set(:"@#{key}", Yammer::Configurable.default_options[key.to_sym])
56
+ end
57
+ self
58
+ end
59
+
60
+ # Convenience method to allow configuration options to be set in a block
61
+ def configure
62
+ yield self if block_given?
63
+ self
64
+ end
65
+
66
+ def enable_logging(output='stdout')
67
+ self.http_adapter.log = output
68
+ end
69
+
70
+ def disable_logging
71
+ self.http_adapter.log = nil
72
+ end
73
+
74
+ def with_logging(output)
75
+ cached_output = self.http_adapter.log
76
+ enable_logging(output)
77
+ yield self if block_given?
78
+ self.http_adapter.log = cached_output
79
+ end
80
+ end
81
+ end