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.
- data/.gitignore +21 -0
- data/Gemfile +10 -0
- data/LICENSE +22 -0
- data/README.md +132 -0
- data/Rakefile +7 -0
- data/cs.gemspec +22 -0
- data/lib/commonsense-ruby-lib.rb +127 -0
- data/lib/commonsense-ruby-lib/auth/http.rb +117 -0
- data/lib/commonsense-ruby-lib/auth/oauth.rb +101 -0
- data/lib/commonsense-ruby-lib/end_point.rb +276 -0
- data/lib/commonsense-ruby-lib/end_point/group.rb +28 -0
- data/lib/commonsense-ruby-lib/end_point/sensor.rb +36 -0
- data/lib/commonsense-ruby-lib/end_point/sensor_data.rb +70 -0
- data/lib/commonsense-ruby-lib/end_point/user.rb +50 -0
- data/lib/commonsense-ruby-lib/error.rb +51 -0
- data/lib/commonsense-ruby-lib/relation.rb +233 -0
- data/lib/commonsense-ruby-lib/relation/sensor_data_relation.rb +116 -0
- data/lib/commonsense-ruby-lib/relation/sensor_relation.rb +162 -0
- data/lib/commonsense-ruby-lib/serializer.rb +20 -0
- data/lib/commonsense-ruby-lib/session.rb +105 -0
- data/lib/commonsense-ruby-lib/version.rb +3 -0
- data/spec/features/sensor_data_management_spec.rb +4 -0
- data/spec/features/sensor_management_spec.rb +105 -0
- data/spec/features/user_management_spec.rb +70 -0
- data/spec/lib/commonsense-ruby-lib/end_point/sensor_data_spec.rb +68 -0
- data/spec/lib/commonsense-ruby-lib/end_point/sensor_spec.rb +98 -0
- data/spec/lib/commonsense-ruby-lib/end_point/user_spec.rb +36 -0
- data/spec/lib/commonsense-ruby-lib/end_point_spec.rb +190 -0
- data/spec/lib/commonsense-ruby-lib/relation/sensor_data_relation_spec.rb +444 -0
- data/spec/lib/commonsense-ruby-lib/relation/sensor_relation_spec.rb +165 -0
- data/spec/lib/commonsense-ruby-lib/session_spec.rb +43 -0
- data/spec/lib/commonsense-ruby-lib_spec.rb +51 -0
- data/spec/spec_helper.rb +40 -0
- data/spec/support/spec_config.yml.sample +6 -0
- data/spec/support/vcr.rb +5 -0
- 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
|