xively-rb 0.2.09
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 +13 -0
- data/.rbenv-version +1 -0
- data/.rspec +2 -0
- data/.rvmrc +1 -0
- data/.travis.yml +7 -0
- data/CHANGELOG.md +91 -0
- data/CONTRIBUTING.md +95 -0
- data/Gemfile +15 -0
- data/LICENSE.md +13 -0
- data/README.md +10 -0
- data/Rakefile +25 -0
- data/ci/build_hudson.sh +24 -0
- data/init.rb +2 -0
- data/lib/xively-rb.rb +44 -0
- data/lib/xively-rb/array_extensions.rb +6 -0
- data/lib/xively-rb/base.rb +52 -0
- data/lib/xively-rb/base/instance_methods.rb +28 -0
- data/lib/xively-rb/client.rb +43 -0
- data/lib/xively-rb/datapoint.rb +72 -0
- data/lib/xively-rb/datastream.rb +127 -0
- data/lib/xively-rb/exceptions.rb +5 -0
- data/lib/xively-rb/feed.rb +109 -0
- data/lib/xively-rb/hash_extensions.rb +16 -0
- data/lib/xively-rb/helpers.rb +41 -0
- data/lib/xively-rb/key.rb +99 -0
- data/lib/xively-rb/nil_content.rb +15 -0
- data/lib/xively-rb/object_extensions.rb +6 -0
- data/lib/xively-rb/parsers/csv/datastream_defaults.rb +50 -0
- data/lib/xively-rb/parsers/csv/feed_defaults.rb +97 -0
- data/lib/xively-rb/parsers/defaults.rb +15 -0
- data/lib/xively-rb/parsers/json/datapoint_defaults.rb +16 -0
- data/lib/xively-rb/parsers/json/datastream_defaults.rb +58 -0
- data/lib/xively-rb/parsers/json/feed_defaults.rb +114 -0
- data/lib/xively-rb/parsers/json/key_defaults.rb +20 -0
- data/lib/xively-rb/parsers/json/search_result_defaults.rb +24 -0
- data/lib/xively-rb/parsers/json/trigger_defaults.rb +16 -0
- data/lib/xively-rb/parsers/xml/datapoint_defaults.rb +27 -0
- data/lib/xively-rb/parsers/xml/datastream_defaults.rb +53 -0
- data/lib/xively-rb/parsers/xml/errors.rb +7 -0
- data/lib/xively-rb/parsers/xml/feed_defaults.rb +83 -0
- data/lib/xively-rb/parsers/xml/helpers.rb +116 -0
- data/lib/xively-rb/parsers/xml/key_defaults.rb +46 -0
- data/lib/xively-rb/parsers/xml/trigger_defaults.rb +28 -0
- data/lib/xively-rb/permission.rb +67 -0
- data/lib/xively-rb/resource.rb +43 -0
- data/lib/xively-rb/search_result.rb +68 -0
- data/lib/xively-rb/string_extensions.rb +6 -0
- data/lib/xively-rb/templates/csv/datapoint_defaults.rb +22 -0
- data/lib/xively-rb/templates/csv/datastream_defaults.rb +43 -0
- data/lib/xively-rb/templates/csv/feed_defaults.rb +47 -0
- data/lib/xively-rb/templates/defaults.rb +14 -0
- data/lib/xively-rb/templates/json/datapoint_defaults.rb +15 -0
- data/lib/xively-rb/templates/json/datastream_defaults.rb +61 -0
- data/lib/xively-rb/templates/json/feed_defaults.rb +90 -0
- data/lib/xively-rb/templates/json/key_defaults.rb +39 -0
- data/lib/xively-rb/templates/json/search_result_defaults.rb +42 -0
- data/lib/xively-rb/templates/json/trigger_defaults.rb +21 -0
- data/lib/xively-rb/templates/xml/datapoint_defaults.rb +25 -0
- data/lib/xively-rb/templates/xml/datastream_defaults.rb +66 -0
- data/lib/xively-rb/templates/xml/feed_defaults.rb +112 -0
- data/lib/xively-rb/templates/xml/search_result_defaults.rb +118 -0
- data/lib/xively-rb/templates/xml_headers.rb +17 -0
- data/lib/xively-rb/trigger.rb +66 -0
- data/lib/xively-rb/validations.rb +9 -0
- data/lib/xively-rb/version.rb +3 -0
- data/spec/fixtures/models.rb +81 -0
- data/spec/spec_helper.rb +29 -0
- data/spec/support/contain_datapoint_eeml_matcher.rb +16 -0
- data/spec/support/contain_datastream_eeml_matcher.rb +60 -0
- data/spec/support/contain_feed_eeml_matcher.rb +98 -0
- data/spec/support/datapoint_helper.rb +53 -0
- data/spec/support/datastream_helper.rb +324 -0
- data/spec/support/describe_eeml_matcher.rb +23 -0
- data/spec/support/feed_helper.rb +783 -0
- data/spec/support/fully_represent_datapoint_matcher.rb +30 -0
- data/spec/support/fully_represent_datastream_matcher.rb +96 -0
- data/spec/support/fully_represent_feed_matcher.rb +234 -0
- data/spec/support/fully_represent_key_matcher.rb +74 -0
- data/spec/support/fully_represent_search_result_matcher.rb +67 -0
- data/spec/support/fully_represent_trigger_matcher.rb +29 -0
- data/spec/support/key_helper.rb +74 -0
- data/spec/support/search_result_helper.rb +252 -0
- data/spec/support/trigger_helper.rb +51 -0
- data/spec/xively-rb/array_extensions_spec.rb +9 -0
- data/spec/xively-rb/base/instance_methods_spec.rb +109 -0
- data/spec/xively-rb/base_spec.rb +56 -0
- data/spec/xively-rb/client_spec.rb +51 -0
- data/spec/xively-rb/datapoint_spec.rb +187 -0
- data/spec/xively-rb/datastream_spec.rb +344 -0
- data/spec/xively-rb/feed_spec.rb +341 -0
- data/spec/xively-rb/hash_extensions_spec.rb +20 -0
- data/spec/xively-rb/helpers_spec.rb +56 -0
- data/spec/xively-rb/key_spec.rb +198 -0
- data/spec/xively-rb/parsers/csv/datastream_defaults_spec.rb +110 -0
- data/spec/xively-rb/parsers/csv/feed_defaults_spec.rb +234 -0
- data/spec/xively-rb/parsers/json/datapoint_defaults_spec.rb +21 -0
- data/spec/xively-rb/parsers/json/datastream_defaults_spec.rb +105 -0
- data/spec/xively-rb/parsers/json/feed_defaults_spec.rb +45 -0
- data/spec/xively-rb/parsers/json/key_defaults_spec.rb +14 -0
- data/spec/xively-rb/parsers/json/search_result_defaults_spec.rb +18 -0
- data/spec/xively-rb/parsers/json/trigger_defaults_spec.rb +22 -0
- data/spec/xively-rb/parsers/xml/datapoint_defaults_spec.rb +19 -0
- data/spec/xively-rb/parsers/xml/datastream_defaults_spec.rb +148 -0
- data/spec/xively-rb/parsers/xml/feed_defaults_spec.rb +254 -0
- data/spec/xively-rb/parsers/xml/key_defaults_spec.rb +22 -0
- data/spec/xively-rb/parsers/xml/trigger_defaults_spec.rb +22 -0
- data/spec/xively-rb/search_result_spec.rb +257 -0
- data/spec/xively-rb/string_extensions_spec.rb +12 -0
- data/spec/xively-rb/templates/csv/datapoint_defaults_spec.rb +41 -0
- data/spec/xively-rb/templates/csv/datastream_defaults_spec.rb +131 -0
- data/spec/xively-rb/templates/csv/feed_defaults_spec.rb +78 -0
- data/spec/xively-rb/templates/json/datapoint_defaults_spec.rb +14 -0
- data/spec/xively-rb/templates/json/datastream_defaults_spec.rb +170 -0
- data/spec/xively-rb/templates/json/feed_defaults_spec.rb +399 -0
- data/spec/xively-rb/templates/json/key_defaults_spec.rb +29 -0
- data/spec/xively-rb/templates/json/search_result_defaults_spec.rb +37 -0
- data/spec/xively-rb/templates/json/trigger_defaults_spec.rb +19 -0
- data/spec/xively-rb/templates/xml/datapoint_defaults_spec.rb +14 -0
- data/spec/xively-rb/templates/xml/datastream_defaults_spec.rb +113 -0
- data/spec/xively-rb/templates/xml/feed_defaults_spec.rb +131 -0
- data/spec/xively-rb/templates/xml/search_result_defaults_spec.rb +44 -0
- data/spec/xively-rb/trigger_spec.rb +157 -0
- data/xively-rb.gemspec +41 -0
- metadata +333 -0
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
module Xively
|
|
2
|
+
module Parsers
|
|
3
|
+
module CSV
|
|
4
|
+
module DatastreamDefaults
|
|
5
|
+
def from_csv(csv, csv_version = nil)
|
|
6
|
+
begin
|
|
7
|
+
rows = Xively::CSV.parse(csv.strip)
|
|
8
|
+
rescue Exception => e
|
|
9
|
+
# this might be a FasterCSV or CSV exception depending on whether
|
|
10
|
+
# we are running under 1.8.x or 1.9.x
|
|
11
|
+
raise InvalidCSVError, e.message
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
version = FeedDefaults.detect_version(rows, csv_version)
|
|
15
|
+
|
|
16
|
+
raise InvalidCSVError, "CSV is invalid. Submitted data appears to be empty" if rows.nil?
|
|
17
|
+
|
|
18
|
+
if version == :v1
|
|
19
|
+
raise InvalidCSVError, "CSV is invalid. Can only construct a Xively::Datastream object from a single row of data" if rows.size > 1
|
|
20
|
+
row = rows.first
|
|
21
|
+
raise InvalidCSVError, "CSV is invalid. Too many fields; must only be a single value" if row.size > 1
|
|
22
|
+
return { "current_value" => row[0].to_s.strip }
|
|
23
|
+
else
|
|
24
|
+
row_sizes = rows.collect { |row| row.size }.uniq
|
|
25
|
+
raise InvalidCSVError, "CSV is invalid. Too many fields; must only be a single value, or a timestamp and a value" if row_sizes.max > 2
|
|
26
|
+
|
|
27
|
+
if rows.size == 1
|
|
28
|
+
# capture single lines (normal case)
|
|
29
|
+
row = rows.first
|
|
30
|
+
|
|
31
|
+
if row.size == 2
|
|
32
|
+
return { "updated" => row[0].to_s.strip, "current_value" => row[1].to_s.strip }
|
|
33
|
+
else
|
|
34
|
+
return { "current_value" => row[0].to_s.strip }
|
|
35
|
+
end
|
|
36
|
+
else
|
|
37
|
+
# capture multiple lines
|
|
38
|
+
raise InvalidCSVError, "CSV is invalid. If multiple values are included, then a timestamp and value must be submitted for every row" if row_sizes.min < 2
|
|
39
|
+
|
|
40
|
+
return { "datapoints" => rows.collect { |row| { "at" => row[0].to_s.strip, "value" => row[1].to_s.strip } } }
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
module Xively
|
|
2
|
+
module Parsers
|
|
3
|
+
module CSV
|
|
4
|
+
class UnknownVersionError < Xively::ParserError ; end
|
|
5
|
+
class InvalidCSVError < Xively::ParserError ; end
|
|
6
|
+
|
|
7
|
+
module FeedDefaults
|
|
8
|
+
|
|
9
|
+
class << self
|
|
10
|
+
def detect_version(rows, version = nil)
|
|
11
|
+
return version if version
|
|
12
|
+
return :v2 if rows.size >= 2
|
|
13
|
+
return :v1 if rows.size == 1 && rows.first.size != 2
|
|
14
|
+
raise UnknownVersionError, "CSV Version could not be detected"
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def from_csv(csv, csv_version = nil)
|
|
19
|
+
begin
|
|
20
|
+
rows = Xively::CSV.parse(csv.strip)
|
|
21
|
+
rescue Exception => e
|
|
22
|
+
# this might be a FasterCSV or CSV exception depending on whether
|
|
23
|
+
# we are running under 1.8.x or 1.9.x
|
|
24
|
+
raise InvalidCSVError, e.message
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
version = FeedDefaults.detect_version(rows, csv_version)
|
|
28
|
+
|
|
29
|
+
hash = Hash.new
|
|
30
|
+
|
|
31
|
+
raise InvalidCSVError, "Submitted CSV is empty." if rows.empty?
|
|
32
|
+
|
|
33
|
+
if version == :v2
|
|
34
|
+
hash["datastreams"] = extract_datastreams(rows)
|
|
35
|
+
elsif version == :v1
|
|
36
|
+
raise InvalidCSVError, "CSV is invalid. Currently we can only accept CSV for your most recent set of values. You have submitted #{rows.size} rows of data." if rows.size > 1
|
|
37
|
+
hash["datastreams"] = []
|
|
38
|
+
rows.first.each_with_index do |current_value, stream_id|
|
|
39
|
+
hash["datastreams"] << { "id" => stream_id.to_s.strip, "current_value" => current_value.to_s.strip }
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
hash["csv_version"] = version
|
|
43
|
+
hash
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
private
|
|
47
|
+
|
|
48
|
+
# This is used by v2 only
|
|
49
|
+
def extract_datastreams(rows)
|
|
50
|
+
row_sizes = rows.collect { |row| row.size }.uniq
|
|
51
|
+
row_ids = rows.collect { |row| row.first.to_s.strip }.uniq
|
|
52
|
+
|
|
53
|
+
raise InvalidCSVError, "CSV is invalid. Incorrect number of fields" if row_sizes.max > 3 || row_sizes.min <= 1
|
|
54
|
+
|
|
55
|
+
datastream_buckets = {}
|
|
56
|
+
|
|
57
|
+
# iterate through each row bucketing by datastream id
|
|
58
|
+
rows.each do |row|
|
|
59
|
+
# this splits each row into the id first element, and an array containing the rest of the row
|
|
60
|
+
id, *rest = *row
|
|
61
|
+
|
|
62
|
+
# make empty array if it doesn't exist
|
|
63
|
+
datastream_buckets[id.to_s.strip] ||= []
|
|
64
|
+
# add this row to the correct bucketed array
|
|
65
|
+
datastream_buckets[id.to_s.strip] << rest
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
datastreams = []
|
|
69
|
+
|
|
70
|
+
row_ids.each do |datastream_id|
|
|
71
|
+
datastream_data = datastream_buckets[datastream_id]
|
|
72
|
+
|
|
73
|
+
if datastream_data.size == 1
|
|
74
|
+
# single value for this datastream - current normal
|
|
75
|
+
data = datastream_data[0]
|
|
76
|
+
if data.size == 2
|
|
77
|
+
datastreams << { "id" => datastream_id, "updated" => data[0].to_s.strip, "current_value" => data[1].to_s.strip }
|
|
78
|
+
else
|
|
79
|
+
datastreams << { "id" => datastream_id, "current_value" => data[0].to_s.strip }
|
|
80
|
+
end
|
|
81
|
+
else
|
|
82
|
+
# multiple values for this datastream
|
|
83
|
+
raise InvalidCSVError, "CSV is invalid. If multiple values given they must include a timestamp for all values" if datastream_data.collect { |d| d.size }.min < 2
|
|
84
|
+
|
|
85
|
+
datapoints = datastream_data.collect { |datapoint_data| { "at" => datapoint_data[0].to_s.strip, "value" => datapoint_data[1].to_s.strip } }
|
|
86
|
+
|
|
87
|
+
datastreams << { "id" => datastream_id, "datapoints" => datapoints }
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
return datastreams
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
require 'xively-rb/parsers/json/feed_defaults'
|
|
2
|
+
require 'xively-rb/parsers/json/search_result_defaults'
|
|
3
|
+
require 'xively-rb/parsers/json/datastream_defaults'
|
|
4
|
+
require 'xively-rb/parsers/json/datapoint_defaults'
|
|
5
|
+
require 'xively-rb/parsers/json/trigger_defaults'
|
|
6
|
+
require 'xively-rb/parsers/json/key_defaults'
|
|
7
|
+
require 'xively-rb/parsers/xml/errors'
|
|
8
|
+
require 'xively-rb/parsers/xml/helpers'
|
|
9
|
+
require 'xively-rb/parsers/xml/feed_defaults'
|
|
10
|
+
require 'xively-rb/parsers/xml/datastream_defaults'
|
|
11
|
+
require 'xively-rb/parsers/xml/datapoint_defaults'
|
|
12
|
+
require 'xively-rb/parsers/xml/trigger_defaults'
|
|
13
|
+
require 'xively-rb/parsers/xml/key_defaults'
|
|
14
|
+
require 'xively-rb/parsers/csv/feed_defaults'
|
|
15
|
+
require 'xively-rb/parsers/csv/datastream_defaults'
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
module Xively
|
|
2
|
+
module Parsers
|
|
3
|
+
module JSON
|
|
4
|
+
module DatastreamDefaults
|
|
5
|
+
def from_json(json)
|
|
6
|
+
begin
|
|
7
|
+
hash = MultiJson.load(json)
|
|
8
|
+
rescue MultiJson::DecodeError => e
|
|
9
|
+
raise InvalidJSONError, e.message
|
|
10
|
+
end
|
|
11
|
+
raise InvalidJSONError, "JSON doesn't appear to be a hash" unless hash.is_a?(Hash)
|
|
12
|
+
case hash['version']
|
|
13
|
+
when '0.6-alpha'
|
|
14
|
+
transform_0_6_alpha(hash)
|
|
15
|
+
when '1.0.0', nil
|
|
16
|
+
transform_1_0_0(hash)
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
private
|
|
21
|
+
|
|
22
|
+
# As produced by http://xively.com/api/v2/FEED_ID/datastreams/DATASTREAM_ID.json
|
|
23
|
+
def transform_1_0_0(hash)
|
|
24
|
+
hash["id"] = hash.delete("id")
|
|
25
|
+
hash["updated"] = hash.delete("at")
|
|
26
|
+
hash["current_value"] = hash.delete("current_value")
|
|
27
|
+
hash["tags"] = join_tags(hash["tags"])
|
|
28
|
+
if unit = hash.delete('unit')
|
|
29
|
+
hash['unit_type'] = unit['type']
|
|
30
|
+
hash['unit_symbol'] = unit['symbol']
|
|
31
|
+
hash['unit_label'] = unit['label']
|
|
32
|
+
end
|
|
33
|
+
hash
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# As produced by http://xively.com/api/v1/FEED_ID/datastreams/DATASTREAM_ID.json
|
|
37
|
+
def transform_0_6_alpha(hash)
|
|
38
|
+
hash["id"] = hash.delete("id")
|
|
39
|
+
if values = [*hash["values"]].first
|
|
40
|
+
hash["updated"] = hash["values"].first.delete("recorded_at")
|
|
41
|
+
hash["current_value"] = hash["values"].first.delete("value")
|
|
42
|
+
hash["max_value"] = hash["values"].first.delete("max_value")
|
|
43
|
+
hash["min_value"] = hash["values"].first.delete("min_value")
|
|
44
|
+
end
|
|
45
|
+
hash["tags"] = join_tags(hash["tags"])
|
|
46
|
+
if unit = hash.delete('unit')
|
|
47
|
+
hash['unit_type'] = unit['type']
|
|
48
|
+
hash['unit_symbol'] = unit['symbol']
|
|
49
|
+
hash['unit_label'] = unit['label']
|
|
50
|
+
end
|
|
51
|
+
hash
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
module Xively
|
|
2
|
+
module Parsers
|
|
3
|
+
module JSON
|
|
4
|
+
class InvalidJSONError < Xively::ParserError; end
|
|
5
|
+
module FeedDefaults
|
|
6
|
+
|
|
7
|
+
include Xively::Helpers
|
|
8
|
+
|
|
9
|
+
def from_json(json)
|
|
10
|
+
begin
|
|
11
|
+
hash = MultiJson.load(json)
|
|
12
|
+
rescue MultiJson::DecodeError => e
|
|
13
|
+
raise InvalidJSONError, e.message
|
|
14
|
+
end
|
|
15
|
+
raise InvalidJSONError, "JSON doesn't appear to be a hash" unless hash.is_a?(Hash)
|
|
16
|
+
case hash['version']
|
|
17
|
+
when '0.6-alpha', '0.6'
|
|
18
|
+
transform_0_6_alpha(hash)
|
|
19
|
+
else
|
|
20
|
+
transform_1_0_0(hash)
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
private
|
|
25
|
+
|
|
26
|
+
# As produced by http://xively.com/api/v2/FEED_ID.json
|
|
27
|
+
def transform_1_0_0(hash)
|
|
28
|
+
hash["updated"] = hash["updated"]
|
|
29
|
+
hash["created"] = hash["created"]
|
|
30
|
+
hash["status"] = hash["status"]
|
|
31
|
+
hash["tags"] = join_tags(hash["tags"])
|
|
32
|
+
hash["datastreams"] = hash["datastreams"].collect do |datastream|
|
|
33
|
+
unit_hash = {}
|
|
34
|
+
if unit = datastream.delete('unit')
|
|
35
|
+
unit_hash['unit_type'] = unit['type']
|
|
36
|
+
unit_hash['unit_symbol'] = unit['symbol']
|
|
37
|
+
unit_hash['unit_label'] = unit['label']
|
|
38
|
+
end
|
|
39
|
+
{
|
|
40
|
+
"id" => datastream["id"],
|
|
41
|
+
"current_value" => datastream["current_value"],
|
|
42
|
+
"min_value" => datastream["min_value"],
|
|
43
|
+
"max_value" => datastream["max_value"],
|
|
44
|
+
"updated" => datastream["at"],
|
|
45
|
+
"tags" => join_tags(datastream["tags"]),
|
|
46
|
+
"datapoints" => setup_datapoints(datastream["datapoints"])
|
|
47
|
+
}.merge(unit_hash)
|
|
48
|
+
end if hash["datastreams"]
|
|
49
|
+
if location = hash.delete("location")
|
|
50
|
+
hash["location_disposition"] = location["disposition"]
|
|
51
|
+
hash["location_domain"] = location["domain"]
|
|
52
|
+
hash["location_ele"] = location["ele"]
|
|
53
|
+
hash["location_exposure"] = location["exposure"]
|
|
54
|
+
hash["location_lat"] = location["lat"]
|
|
55
|
+
hash["location_lon"] = location["lon"]
|
|
56
|
+
hash["location_name"] = location["name"]
|
|
57
|
+
end
|
|
58
|
+
if owner = hash.delete("user")
|
|
59
|
+
hash["owner_login"] = owner["login"]
|
|
60
|
+
end
|
|
61
|
+
hash
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
# As produced by http://xively.com/api/v1/FEED_ID.json
|
|
65
|
+
def transform_0_6_alpha(hash)
|
|
66
|
+
hash["retrieved_at"] = hash["updated"]
|
|
67
|
+
hash["state"] = hash["status"]
|
|
68
|
+
if hash["datastreams"]
|
|
69
|
+
hash["datastreams"] = hash["datastreams"].collect do |datastream|
|
|
70
|
+
unit_hash = {}
|
|
71
|
+
if unit = datastream.delete('unit')
|
|
72
|
+
unit_hash['unit_type'] = unit['type']
|
|
73
|
+
unit_hash['unit_symbol'] = unit['symbol']
|
|
74
|
+
unit_hash['unit_label'] = unit['label']
|
|
75
|
+
end
|
|
76
|
+
value_hash = {}
|
|
77
|
+
if datastream["values"].size >= 1
|
|
78
|
+
value_hash["current_value"] = datastream["values"].first["value"]
|
|
79
|
+
value_hash["min_value"] = datastream["values"].first["min_value"]
|
|
80
|
+
value_hash["max_value"] = datastream["values"].first["max_value"]
|
|
81
|
+
value_hash["updated"] = datastream["values"].first["recorded_at"]
|
|
82
|
+
end
|
|
83
|
+
{
|
|
84
|
+
"id" => datastream["id"],
|
|
85
|
+
"tags" => join_tags(datastream["tags"]),
|
|
86
|
+
}.merge(value_hash).merge(unit_hash)
|
|
87
|
+
end
|
|
88
|
+
if location = hash.delete("location")
|
|
89
|
+
hash["location_disposition"] = location["disposition"]
|
|
90
|
+
hash["location_domain"] = location["domain"]
|
|
91
|
+
hash["location_ele"] = location["ele"]
|
|
92
|
+
hash["location_exposure"] = location["exposure"]
|
|
93
|
+
hash["location_lat"] = location["lat"]
|
|
94
|
+
hash["location_lon"] = location["lon"]
|
|
95
|
+
hash["location_name"] = location["name"]
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
hash
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
def setup_datapoints(datapoints)
|
|
102
|
+
return [] unless datapoints
|
|
103
|
+
datapoints.collect do |datapoint|
|
|
104
|
+
{
|
|
105
|
+
"at" => datapoint["at"],
|
|
106
|
+
"value" => datapoint["value"]
|
|
107
|
+
}
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
module Xively
|
|
2
|
+
module Parsers
|
|
3
|
+
module JSON
|
|
4
|
+
module KeyDefaults
|
|
5
|
+
def from_json(json)
|
|
6
|
+
begin
|
|
7
|
+
hash = MultiJson.load(json)["key"]
|
|
8
|
+
rescue MultiJson::DecodeError => e
|
|
9
|
+
raise InvalidJSONError, e.message
|
|
10
|
+
end
|
|
11
|
+
raise InvalidJSONError, "JSON doesn't appear to be a hash" unless hash.is_a?(Hash)
|
|
12
|
+
hash["id"] = hash.delete("id")
|
|
13
|
+
hash["key"] = hash.delete("api_key")
|
|
14
|
+
hash
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
module Xively
|
|
2
|
+
module Parsers
|
|
3
|
+
module JSON
|
|
4
|
+
module SearchResultDefaults
|
|
5
|
+
include FeedDefaults
|
|
6
|
+
|
|
7
|
+
def from_json(json)
|
|
8
|
+
begin
|
|
9
|
+
hash = MultiJson.load(json)
|
|
10
|
+
rescue MultiJson::DecodeError => e
|
|
11
|
+
raise InvalidJSONError, e.message
|
|
12
|
+
end
|
|
13
|
+
raise InvalidJSONError, "JSON doesn't appear to be a hash" unless hash.is_a?(Hash)
|
|
14
|
+
|
|
15
|
+
hash['results'] = hash['results'].collect do |feed|
|
|
16
|
+
transform_1_0_0(feed)
|
|
17
|
+
end
|
|
18
|
+
hash
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
module Xively
|
|
2
|
+
module Parsers
|
|
3
|
+
module XML
|
|
4
|
+
module DatapointDefaults
|
|
5
|
+
|
|
6
|
+
include Xively::Parsers::XML::Helpers
|
|
7
|
+
|
|
8
|
+
def from_xml(xml)
|
|
9
|
+
begin
|
|
10
|
+
parsed = MultiXml.parse(xml)
|
|
11
|
+
raise InvalidXMLError, "Missing 'environment' node from base node" if parsed['eeml'].nil? || !parsed['eeml'].key?('environment')
|
|
12
|
+
return {} if parsed['eeml']['environment'].nil?
|
|
13
|
+
datastream = parsed['eeml']['environment']['data']
|
|
14
|
+
raise InvalidXMLError, "Multiple 'data' nodes are not permitted for Datapoint level XML" if datastream.is_a?(Array)
|
|
15
|
+
datapoint = datastream['datapoints']
|
|
16
|
+
raise InvalidXMLError, "Multiple 'value' nodes are not permitted for Datapoint level XML" if datapoint.is_a?(Array)
|
|
17
|
+
_extract_datapoints(datapoint).first
|
|
18
|
+
rescue MultiXml::ParseError => e
|
|
19
|
+
raise InvalidXMLError, e.message
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|