cs 0.1.0beta3

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 (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