cs 0.1.0beta3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (36) hide show
  1. data/.gitignore +21 -0
  2. data/Gemfile +10 -0
  3. data/LICENSE +22 -0
  4. data/README.md +132 -0
  5. data/Rakefile +7 -0
  6. data/cs.gemspec +22 -0
  7. data/lib/commonsense-ruby-lib.rb +127 -0
  8. data/lib/commonsense-ruby-lib/auth/http.rb +117 -0
  9. data/lib/commonsense-ruby-lib/auth/oauth.rb +101 -0
  10. data/lib/commonsense-ruby-lib/end_point.rb +276 -0
  11. data/lib/commonsense-ruby-lib/end_point/group.rb +28 -0
  12. data/lib/commonsense-ruby-lib/end_point/sensor.rb +36 -0
  13. data/lib/commonsense-ruby-lib/end_point/sensor_data.rb +70 -0
  14. data/lib/commonsense-ruby-lib/end_point/user.rb +50 -0
  15. data/lib/commonsense-ruby-lib/error.rb +51 -0
  16. data/lib/commonsense-ruby-lib/relation.rb +233 -0
  17. data/lib/commonsense-ruby-lib/relation/sensor_data_relation.rb +116 -0
  18. data/lib/commonsense-ruby-lib/relation/sensor_relation.rb +162 -0
  19. data/lib/commonsense-ruby-lib/serializer.rb +20 -0
  20. data/lib/commonsense-ruby-lib/session.rb +105 -0
  21. data/lib/commonsense-ruby-lib/version.rb +3 -0
  22. data/spec/features/sensor_data_management_spec.rb +4 -0
  23. data/spec/features/sensor_management_spec.rb +105 -0
  24. data/spec/features/user_management_spec.rb +70 -0
  25. data/spec/lib/commonsense-ruby-lib/end_point/sensor_data_spec.rb +68 -0
  26. data/spec/lib/commonsense-ruby-lib/end_point/sensor_spec.rb +98 -0
  27. data/spec/lib/commonsense-ruby-lib/end_point/user_spec.rb +36 -0
  28. data/spec/lib/commonsense-ruby-lib/end_point_spec.rb +190 -0
  29. data/spec/lib/commonsense-ruby-lib/relation/sensor_data_relation_spec.rb +444 -0
  30. data/spec/lib/commonsense-ruby-lib/relation/sensor_relation_spec.rb +165 -0
  31. data/spec/lib/commonsense-ruby-lib/session_spec.rb +43 -0
  32. data/spec/lib/commonsense-ruby-lib_spec.rb +51 -0
  33. data/spec/spec_helper.rb +40 -0
  34. data/spec/support/spec_config.yml.sample +6 -0
  35. data/spec/support/vcr.rb +5 -0
  36. metadata +175 -0
@@ -0,0 +1,101 @@
1
+ require "oauth"
2
+
3
+ module CommonSense
4
+ module Auth
5
+ class OAuth
6
+
7
+ attr_accessor :response_body, :response_code, :response_headers, :errors, :consumer_key,
8
+ :consumer_secret, :access_token, :access_token_secret
9
+
10
+ def initialize(consumer_key, consumer_secret, access_token, access_token_secret, uri=nil)
11
+ @consumer_key = consumer_key
12
+ @consumer_secret = consumer_secret
13
+ @access_token = access_token
14
+ @access_token_secret = access_token_secret
15
+ oauth_base = ::OAuth::Consumer.new(consumer_key, consumer_secret, :site => uri)
16
+ @oauth = ::OAuth::AccessToken.new(oauth_base, access_token, access_token_secret)
17
+ reset
18
+ end
19
+
20
+ def oauth
21
+ @oauth
22
+ end
23
+
24
+ def get(path, query={}, headers = {})
25
+ reset
26
+ headers = default_headers.merge(headers)
27
+ response = oauth.get(path, headers)
28
+ parse_response(response)
29
+ @response_body
30
+ end
31
+
32
+ def post(path, body = '', headers = {})
33
+ reset
34
+ headers = default_headers.merge(headers)
35
+ response = oauth.post(path, body.to_json, headers)
36
+ parse_response(response)
37
+
38
+ @response_body
39
+ end
40
+
41
+ def put(path, body = '', headers = {})
42
+ reset
43
+ headers = default_headers.merge(headers)
44
+ response = oauth.put(path, body.to_json, headers)
45
+ parse_response(response)
46
+
47
+ @response_body
48
+ end
49
+
50
+ def delete(path, query={}, headers = {})
51
+ reset
52
+ headers = default_headers.merge(headers)
53
+ response = oauth.delete(path, headers)
54
+ parse_response(response)
55
+
56
+ @response_body
57
+ end
58
+
59
+ def head(path, headers = {})
60
+ reset
61
+ headers = default_headers.merge(headers)
62
+ response = oauth.head(path, headers)
63
+ parse_response(response)
64
+
65
+ @response_body
66
+ end
67
+
68
+ def base_uri=(uri = nil)
69
+ self.class.base_uri uri
70
+ end
71
+
72
+
73
+ private
74
+ def default_headers
75
+ {"Content-Type" => "application/json"}
76
+ end
77
+
78
+ def reset
79
+ @errors = nil
80
+ @response_code = nil
81
+ @response_body = nil
82
+ end
83
+
84
+ # convert the body to hash if response is "application/json"
85
+ def parse_response(response)
86
+ @response_body = response.content_type == "application/json" ? (JSON(response.body) rescue nil) : response.body
87
+ @response_code = response.code.to_i
88
+
89
+ @response_headers = response.to_hash
90
+ @response_headers.each do |k,v|
91
+ @response_headers[k] = v[0] rescue nil
92
+ end
93
+
94
+
95
+ if @response_code >= 400
96
+ @errors = [response_body['error']]
97
+ end
98
+ end
99
+ end
100
+ end
101
+ end
@@ -0,0 +1,276 @@
1
+ require 'commonsense-ruby-lib/serializer'
2
+ module CommonSense
3
+ module EndPoint
4
+ include CommonSense::Serializer
5
+
6
+ attr_accessor :session
7
+
8
+ def initialize(hash={})
9
+ from_hash(hash)
10
+ end
11
+
12
+ # generate a hash representation of this end point
13
+ def to_parameters
14
+ r = self.resource rescue nil
15
+ r.nil? ? self.to_h(false) : { self.resource => self.to_h(false) }
16
+ end
17
+
18
+ def inspect
19
+ inspection = self.to_h.collect {|k,v| "#{k}: #{v.inspect}"}.compact.join(", ")
20
+ "#<#{self.class} #{inspection}>"
21
+ end
22
+
23
+ # get value of property name
24
+ def parameter(name)
25
+ self.instance_variable_get(name)
26
+ end
27
+
28
+ # Persist end point object to CS. It will create a new record on CS
29
+ # if it's a new object or it will update the object. It will throw an exception
30
+ # if it could not persist object to CS
31
+ #
32
+ # example for {Sensor} object:
33
+ #
34
+ # sensor = client.sensors.build
35
+ # sensor.name = "accelerometer"
36
+ # sensor.display_name = "Accelerometer"
37
+ # sensor.device_type = "BMA123"
38
+ # sensor.pager_type = "email"
39
+ # sensor.data_type = "json"
40
+ # sensor.data_structure = {"x-axis" => "Float", "y-axis" => "Float", "z-axis" => "Float"}
41
+ #
42
+ # sensor.save! # this will create new sensor on CS
43
+ # sensor.id # should give you the id of the sensor
44
+ #
45
+ # sensor.name = "accelerometer edit"
46
+ # sensor.save! # this will update the sensor
47
+ def save!
48
+ check_session!
49
+
50
+ if @id
51
+ self.update!
52
+ else
53
+ self.create!
54
+ end
55
+ end
56
+
57
+ # it will persist data to CS just like {#save!} but it will return nil instead of exception
58
+ # if it encouter error while persiting data
59
+ def save
60
+ save! rescue nil
61
+ end
62
+
63
+ # Create a new end point object to CS. It will raise an exception if there is an error
64
+ #
65
+ # example for {Sensor} object:
66
+ #
67
+ # sensor = client.sensors.build
68
+ # sensor.name = "accelerometer"
69
+ # sensor.display_name = "Accelerometer"
70
+ # sensor.device_type = "BMA123"
71
+ # sensor.pager_type = "email"
72
+ # sensor.data_type = "json"
73
+ # sensor.data_structure = {"x-axis" => "Float", "y-axis" => "Float", "z-axis" => "Float"}
74
+ #
75
+ # sensor.create! # this will create new sensor on CS
76
+ # sensor.id # should give you the id of the sensor
77
+ def create!
78
+ parameter = self.to_parameters
79
+ res = session.post(post_url, parameter)
80
+
81
+ if session.response_code != 201
82
+ errors = session.errors rescue nil
83
+ raise Error::ResponseError, errors
84
+ end
85
+
86
+ location_header = session.response_headers["location"]
87
+ id = scan_header_for_id(location_header)
88
+ self.id = id[0] if id
89
+
90
+ true
91
+ end
92
+
93
+ # Create a new endpoint object to CS, just like {#create!} but it will return nil
94
+ # if there is an error.
95
+ def create
96
+ result = create! rescue nil
97
+ not result.nil?
98
+ end
99
+
100
+ # Retrieve Data from CS of the current object based on the id of the object.
101
+ # It will return an exception if there is an error
102
+ #
103
+ # example for {Sensor} object:
104
+ #
105
+ # sensor = client.sensors.build
106
+ # sensor.id = "1"
107
+ # sensor.retrieve!
108
+ def retrieve!
109
+ check_session!
110
+ raise Error::ResourceIdError unless @id
111
+
112
+ res = session.get(get_url)
113
+ if session.response_code != 200
114
+ errors = session.errors rescue nil
115
+ raise Error::ResponseError, errors
116
+ end
117
+
118
+ from_hash(res[resource.to_s]) if res
119
+ true
120
+ end
121
+
122
+ # alias for {#retrieve!}
123
+ def reload!
124
+ retieve!
125
+ end
126
+
127
+ # it will retrieve / reload current object form CS, just like {#retrieve!} but it
128
+ # will return nil instead of raise an exception if there is an error.
129
+ def retrieve
130
+ result = retrieve! rescue nil
131
+ not result.nil?
132
+ end
133
+
134
+ # alias for {#retrieve}
135
+ def reload
136
+ retrieve
137
+ end
138
+
139
+ # Update current end point object to CS. It will throw an exception if there is an error
140
+ #
141
+ # example for {Sensor} object:
142
+ #
143
+ # sensor = client.sensors.find(1)
144
+ # sensor.name = "new name"
145
+ # sensor.update!
146
+ def update!
147
+ check_session!
148
+ raise Error::ResourceIdError unless @id
149
+
150
+ parameter = self.to_parameters
151
+ res = session.put(put_url, parameter)
152
+
153
+ if session.response_code != 200
154
+ errors = session.errors rescue nil
155
+ raise Error::ResponseError, errors
156
+ end
157
+
158
+ true
159
+ end
160
+
161
+ # Update current end point object to CS, just like {#update!} but it will return nil
162
+ # if there is an error
163
+ def update
164
+ result = update! rescue nil
165
+ not result.nil?
166
+ end
167
+
168
+
169
+ # Delete the current end point object from CS. It will throw an exception if there is an error
170
+ #
171
+ # example for {Sensor} object:
172
+ #
173
+ # sensor = client.sensors.find(1)
174
+ # sensor.name = "new name"
175
+ # sensor.delete!
176
+ def delete!
177
+ check_session!
178
+ raise Error::ResourceIdError unless @id
179
+
180
+ res = session.delete(delete_url)
181
+
182
+ if session.response_code != 200
183
+ errors = session.errors rescue nil
184
+ raise Error::ResponseError, errors
185
+ end
186
+
187
+ self.id = nil
188
+
189
+ true
190
+ end
191
+
192
+ # Delete the current end point object from CS, just like {#delete!} but it will return nil
193
+ # if there is an error
194
+ def delete
195
+ result = delete! rescue nil
196
+ not result.nil?
197
+ end
198
+
199
+ # return the commonsense URL for method
200
+ # vaild value for method is `:get`, `:post`, `:put`, or `:delete`
201
+ def url_for(method, id=nil)
202
+ raise Error::ResourcesError if resources.nil?
203
+ url = self.class.class_variable_get("@@#{method}_url".to_sym)
204
+ url = url.sub(":id", "#{@id}") if id
205
+ url
206
+ end
207
+
208
+ protected
209
+ def scan_header_for_id(location_header)
210
+ location_header.scan(/.*\/#{resources}\/(.*)/)[0] if location_header
211
+ end
212
+
213
+ def post_url
214
+ url_for(:post)
215
+ end
216
+
217
+ def get_url
218
+ url_for(:get, self.id)
219
+ end
220
+
221
+ def put_url
222
+ url_for(:put, self.id)
223
+ end
224
+
225
+ def delete_url
226
+ url_for(:delete, self.id)
227
+ end
228
+
229
+ def self.included(base)
230
+ base.extend(ClassMethod)
231
+ end
232
+
233
+ def resource
234
+ self.class.class_variable_get(:@@resource)
235
+ rescue
236
+ raise Error::ResourceError, "'resource' is not set up for class : #{self.class}"
237
+ end
238
+
239
+ def resources
240
+ self.class.class_variable_get(:@@resources)
241
+ end
242
+
243
+ private
244
+ def check_session!
245
+ raise Error::SessionEmptyError unless @session
246
+ end
247
+
248
+ module ClassMethod
249
+ def attribute(*args)
250
+ attr_accessor *args
251
+
252
+ unless @attribute_set
253
+ @attribute_set = Set.new([:id])
254
+ attr_accessor :id
255
+ end
256
+ @attribute_set.merge(args)
257
+ end
258
+
259
+ def attribute_set
260
+ @attribute_set
261
+ end
262
+
263
+ def resources(resources)
264
+ class_variable_set(:@@resources, resources)
265
+ class_variable_set(:@@post_url, "/#{resources}.json")
266
+ class_variable_set(:@@get_url, "/#{resources}/:id.json")
267
+ class_variable_set(:@@put_url, "/#{resources}/:id.json")
268
+ class_variable_set(:@@delete_url, "/#{resources}/:id.json")
269
+ end
270
+
271
+ def resource(resource)
272
+ class_variable_set(:@@resource, resource)
273
+ end
274
+ end
275
+ end
276
+ end
@@ -0,0 +1,28 @@
1
+ module CommonSense
2
+ module EndPoint
3
+ class Group
4
+ include EndPoint
5
+
6
+ attr_accessor :id, :name, :description, :public
7
+ # get groups that user belongs to
8
+ def current_groups(options={})
9
+ res = session.get("/groups.json", options)
10
+ return nil unless res
11
+
12
+ group_list = res['groups']
13
+
14
+
15
+ groups =[]
16
+ if group_list
17
+ group_list.each do |group|
18
+ g = Group.new(group)
19
+ g.session = session
20
+ groups << g
21
+ end
22
+ end
23
+
24
+ groups
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,36 @@
1
+ module CommonSense
2
+ module EndPoint
3
+ class Sensor
4
+ include EndPoint
5
+
6
+ attribute :name, :display_name, :device_type, :pager_type, :data_type, :data_structure
7
+ resources :sensors
8
+ resource :sensor
9
+
10
+ def initialize(hash={})
11
+ from_hash(hash)
12
+ if self.data_type == "json"
13
+ if self.data_structure && self.data_structure.kind_of?(String)
14
+ self.data_structure = JSON.parse(self.data_structure) rescue nil
15
+ end
16
+ end
17
+ end
18
+
19
+ # overide Endpoint#to_parameters
20
+ def to_parameters
21
+ param = self.to_h(false)
22
+ if param[:data_type] == "json"
23
+ if param[:data_structure] && !param[:data_structure].kind_of?(String)
24
+ param[:data_structure] = param[:data_structure].to_json
25
+ end
26
+ end
27
+
28
+ {sensor: param}
29
+ end
30
+
31
+ def data
32
+ Relation::SensorDataRelation.new(self.id, self.session)
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,70 @@
1
+ module CommonSense
2
+ module EndPoint
3
+ # This object represent a sensor data point
4
+ # usage example:
5
+ #
6
+ # client = CommonSense::Client.new
7
+ # client.login('username', 'password')
8
+ #
9
+ # # Find the first position sensor
10
+ # sensor = client.sensors.find_by_name(/position/).first
11
+ #
12
+ # # save data point
13
+ # data = sensor.data.build
14
+ # data.date = Time.now
15
+ # data.value = {"lux": 1}
16
+ # data.save!
17
+ #
18
+ # # more compact version
19
+ # sensor.data.build(date: Time.now, value: {"lux => 1}).save!
20
+ #
21
+ class SensorData
22
+ include CommonSense::EndPoint
23
+
24
+ attr_accessor :month, :week, :year
25
+ attribute :date, :value, :sensor_id
26
+ resource :data
27
+
28
+ def to_parameters
29
+ param = self.to_h(false)
30
+ param.delete(:sensor_id)
31
+ value = param[:value]
32
+ if value
33
+ param[:value] = value.to_json unless value.kind_of?(String) || value.kind_of?(Numeric)
34
+ end
35
+
36
+ {data: [param]}
37
+ end
38
+
39
+ # there is no currently end point for geting data by id
40
+ def retrieve!
41
+ raise Error::NotImplementedError, "There is no current end point to get sensor data by id"
42
+ end
43
+
44
+ # there is no currently end point for updating data
45
+ def update!
46
+ raise Error::NotImplementedError, "There is no current end point to update sensor data by id"
47
+ end
48
+
49
+ def scan_header_for_id(location_header)
50
+ location_header.scan(/.*\/sensors\/(.*)\/(.*)/)[1] if location_header
51
+ end
52
+
53
+ def post_url
54
+ "/sensors/#{sensor_id}/data.json"
55
+ end
56
+
57
+ def get_url
58
+ "/sensors/#{sensor_id}/data/#{id}.json"
59
+ end
60
+
61
+ def put_url
62
+ "/sensors/#{sensor_id}/data/#{id}.json"
63
+ end
64
+
65
+ def delete_url
66
+ "/sensors/#{sensor_id}/data/#{id}.json"
67
+ end
68
+ end
69
+ end
70
+ end