cosm-rb 0.2.00 → 0.2.01
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/cosm-rb/datastream.rb +2 -2
- data/lib/cosm-rb/parsers/csv/datastream_defaults.rb +30 -6
- data/lib/cosm-rb/parsers/csv/feed_defaults.rb +58 -14
- data/lib/cosm-rb/parsers/xml/datapoint_defaults.rb +3 -1
- data/lib/cosm-rb/parsers/xml/datastream_defaults.rb +6 -0
- data/lib/cosm-rb/parsers/xml/helpers.rb +2 -3
- data/lib/cosm-rb/version.rb +1 -1
- data/spec/cosm-rb/datastream_spec.rb +7 -7
- data/spec/cosm-rb/parsers/csv/datastream_defaults_spec.rb +73 -2
- data/spec/cosm-rb/parsers/csv/feed_defaults_spec.rb +121 -0
- data/spec/cosm-rb/parsers/json/datastream_defaults_spec.rb +1 -1
- data/spec/cosm-rb/parsers/xml/datastream_defaults_spec.rb +71 -23
- data/spec/cosm-rb/parsers/xml/feed_defaults_spec.rb +34 -0
- data/spec/spec_helper.rb +1 -0
- data/spec/support/fully_represent_datastream_matcher.rb +6 -2
- metadata +47 -47
data/lib/cosm-rb/datastream.rb
CHANGED
@@ -59,7 +59,7 @@ module Cosm
|
|
59
59
|
return pass
|
60
60
|
end
|
61
61
|
|
62
|
-
def initialize(input = {}, format = nil)
|
62
|
+
def initialize(input = {}, csv_version = nil, format = nil)
|
63
63
|
raise InvalidFormatError, "Unknown format specified, currently we can only parse JSON, XML or CSV." unless [nil,:json,:xml,:csv].include?(format)
|
64
64
|
if input.is_a? Hash
|
65
65
|
self.attributes = input
|
@@ -68,7 +68,7 @@ module Cosm
|
|
68
68
|
elsif format == :xml || (format.nil? && input.strip[0...1].to_s == "<")
|
69
69
|
self.attributes = from_xml(input)
|
70
70
|
else
|
71
|
-
self.attributes = from_csv(input)
|
71
|
+
self.attributes = from_csv(input, csv_version)
|
72
72
|
end
|
73
73
|
end
|
74
74
|
|
@@ -10,15 +10,39 @@ module Cosm
|
|
10
10
|
# we are running under 1.8.x or 1.9.x
|
11
11
|
raise InvalidCSVError, e.message
|
12
12
|
end
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
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 Cosm::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
|
19
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
|
20
42
|
end
|
43
|
+
|
21
44
|
end
|
45
|
+
|
22
46
|
end
|
23
47
|
end
|
24
48
|
end
|
@@ -5,6 +5,16 @@ module Cosm
|
|
5
5
|
class InvalidCSVError < Cosm::ParserError ; end
|
6
6
|
|
7
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
|
+
|
8
18
|
def from_csv(csv, csv_version = nil)
|
9
19
|
begin
|
10
20
|
rows = Cosm::CSV.parse(csv.strip)
|
@@ -13,17 +23,13 @@ module Cosm
|
|
13
23
|
# we are running under 1.8.x or 1.9.x
|
14
24
|
raise InvalidCSVError, e.message
|
15
25
|
end
|
16
|
-
|
26
|
+
|
27
|
+
version = FeedDefaults.detect_version(rows, csv_version)
|
28
|
+
|
17
29
|
hash = Hash.new
|
30
|
+
|
18
31
|
if version == :v2
|
19
|
-
|
20
|
-
hash["datastreams"] = rows.collect {|row|
|
21
|
-
timestamp = {}
|
22
|
-
if row.size == 3
|
23
|
-
timestamp["updated"] = row[1].strip
|
24
|
-
end
|
25
|
-
{ "id" => row.first.to_s.strip, "current_value" => row.last.to_s.strip }.merge(timestamp)
|
26
|
-
}
|
32
|
+
hash["datastreams"] = extract_datastreams(rows)
|
27
33
|
elsif version == :v1
|
28
34
|
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
|
29
35
|
hash["datastreams"] = []
|
@@ -37,11 +43,49 @@ module Cosm
|
|
37
43
|
|
38
44
|
private
|
39
45
|
|
40
|
-
def
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
raise
|
46
|
+
def extract_datastreams(rows)
|
47
|
+
row_sizes = rows.collect { |row| row.size }.uniq
|
48
|
+
row_ids = rows.collect { |row| row.first.to_s.strip }.uniq
|
49
|
+
|
50
|
+
raise InvalidCSVError, "CSV is invalid. Incorrect number of fields" if row_sizes.max > 3
|
51
|
+
|
52
|
+
datastream_buckets = {}
|
53
|
+
|
54
|
+
# iterate through each row bucketing by datastream id
|
55
|
+
rows.each do |row|
|
56
|
+
# this splits each row into the id first element, and an array containing the rest of the row
|
57
|
+
id, *rest = *row
|
58
|
+
|
59
|
+
# make empty array if it doesn't exist
|
60
|
+
datastream_buckets[id.to_s.strip] ||= []
|
61
|
+
# add this row to the correct bucketed array
|
62
|
+
datastream_buckets[id.to_s.strip] << rest
|
63
|
+
end
|
64
|
+
|
65
|
+
datastreams = []
|
66
|
+
|
67
|
+
row_ids.each do |datastream_id|
|
68
|
+
datastream_data = datastream_buckets[datastream_id]
|
69
|
+
|
70
|
+
if datastream_data.size == 1
|
71
|
+
# single value for this datastream - current normal
|
72
|
+
data = datastream_data[0]
|
73
|
+
if data.size == 2
|
74
|
+
datastreams << { "id" => datastream_id, "updated" => data[0].to_s.strip, "current_value" => data[1].to_s.strip }
|
75
|
+
else
|
76
|
+
datastreams << { "id" => datastream_id, "current_value" => data[0].to_s.strip }
|
77
|
+
end
|
78
|
+
else
|
79
|
+
# multiple values for this datastream
|
80
|
+
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
|
81
|
+
|
82
|
+
datapoints = datastream_data.collect { |datapoint_data| { "at" => datapoint_data[0].to_s.strip, "value" => datapoint_data[1].to_s.strip } }
|
83
|
+
|
84
|
+
datastreams << { "id" => datastream_id, "datapoints" => datapoints }
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
return datastreams
|
45
89
|
end
|
46
90
|
end
|
47
91
|
end
|
@@ -11,8 +11,10 @@ module Cosm
|
|
11
11
|
raise InvalidXMLError, "Missing 'environment' node from base node" if parsed['eeml'].nil? || !parsed['eeml'].key?('environment')
|
12
12
|
return {} if parsed['eeml']['environment'].nil?
|
13
13
|
datastream = parsed['eeml']['environment']['data']
|
14
|
+
raise InvalidXMLError, "Multiple 'data' nodes are not permitted for Datapoint level XML" if datastream.is_a?(Array)
|
14
15
|
datapoint = datastream['datapoints']
|
15
|
-
|
16
|
+
raise InvalidXMLError, "Multiple 'value' nodes are not permitted for Datapoint level XML" if datapoint.is_a?(Array)
|
17
|
+
_extract_datapoints(datapoint).first
|
16
18
|
rescue MultiXml::ParseError => e
|
17
19
|
raise InvalidXMLError, e.message
|
18
20
|
end
|
@@ -23,6 +23,7 @@ module Cosm
|
|
23
23
|
|
24
24
|
# As produced by http://cosm.com/api/v2/FEED_ID/datastreams/DATASTREAM_ID.xml
|
25
25
|
def transform_v2(xml)
|
26
|
+
validate_xml(xml)
|
26
27
|
datastream = convert_to_hash(xml['data'])
|
27
28
|
_extract_datastream(datastream).merge({
|
28
29
|
:feed_id => strip(xml,'id'),
|
@@ -32,6 +33,7 @@ module Cosm
|
|
32
33
|
|
33
34
|
# As produced by http://cosm.com/api/v1/FEED_ID/datastreams/DATASTREAM_ID.xml
|
34
35
|
def transform_v1(xml)
|
36
|
+
validate_xml(xml)
|
35
37
|
datastream = convert_to_hash(xml['data'])
|
36
38
|
_extract_datastream_v1(datastream).merge({
|
37
39
|
:feed_id => strip(xml,'id'),
|
@@ -40,6 +42,10 @@ module Cosm
|
|
40
42
|
})
|
41
43
|
end
|
42
44
|
|
45
|
+
def validate_xml(xml)
|
46
|
+
raise InvalidXMLError, "Multiple 'data' nodes are not permitted for Datastream level XML" if xml['data'].is_a?(Array)
|
47
|
+
raise InvalidXMLError, "Missing 'data' node from source document" if xml['data'].nil?
|
48
|
+
end
|
43
49
|
end
|
44
50
|
end
|
45
51
|
end
|
data/lib/cosm-rb/version.rb
CHANGED
@@ -120,43 +120,43 @@ describe Cosm::Datastream do
|
|
120
120
|
|
121
121
|
it "should raise known exception if passed json but told xml" do
|
122
122
|
expect {
|
123
|
-
Cosm::Datastream.new(datastream_as_(:json), :xml)
|
123
|
+
Cosm::Datastream.new(datastream_as_(:json), :v2, :xml)
|
124
124
|
}.to raise_error(Cosm::Parsers::XML::InvalidXMLError)
|
125
125
|
end
|
126
126
|
|
127
127
|
it "should raise known exception if passed csv but told xml" do
|
128
128
|
expect {
|
129
|
-
Cosm::Datastream.new(datastream_as_(:csv), :xml)
|
129
|
+
Cosm::Datastream.new(datastream_as_(:csv), :v2, :xml)
|
130
130
|
}.to raise_error(Cosm::Parsers::XML::InvalidXMLError)
|
131
131
|
end
|
132
132
|
|
133
133
|
it "should raise known exception if passed xml but told json" do
|
134
134
|
expect {
|
135
|
-
Cosm::Datastream.new(datastream_as_(:xml), :json)
|
135
|
+
Cosm::Datastream.new(datastream_as_(:xml), :v2, :json)
|
136
136
|
}.to raise_error(Cosm::Parsers::JSON::InvalidJSONError)
|
137
137
|
end
|
138
138
|
|
139
139
|
it "should raise known exception if passed csv but told json" do
|
140
140
|
expect {
|
141
|
-
Cosm::Datastream.new(datastream_as_(:csv), :json)
|
141
|
+
Cosm::Datastream.new(datastream_as_(:csv), :v2, :json)
|
142
142
|
}.to raise_error(Cosm::Parsers::JSON::InvalidJSONError)
|
143
143
|
end
|
144
144
|
|
145
145
|
it "should raise known exception if passed json but told csv" do
|
146
146
|
expect {
|
147
|
-
Cosm::Datastream.new(datastream_as_(:json), :csv)
|
147
|
+
Cosm::Datastream.new(datastream_as_(:json), :v2, :csv)
|
148
148
|
}.to raise_error(Cosm::Parsers::CSV::InvalidCSVError)
|
149
149
|
end
|
150
150
|
|
151
151
|
it "should raise known exception if passed xml but told csv" do
|
152
152
|
expect {
|
153
|
-
Cosm::Datastream.new(datastream_as_(:xml), :csv)
|
153
|
+
Cosm::Datastream.new(datastream_as_(:xml), :v2, :csv)
|
154
154
|
}.to raise_error(Cosm::Parsers::CSV::InvalidCSVError)
|
155
155
|
end
|
156
156
|
|
157
157
|
it "should raise known exception if told some format we don't accept" do
|
158
158
|
expect {
|
159
|
-
Cosm::Datastream.new(datastream_as_(:xml), :html)
|
159
|
+
Cosm::Datastream.new(datastream_as_(:xml), :v2, :html)
|
160
160
|
}.to raise_error(Cosm::InvalidFormatError)
|
161
161
|
end
|
162
162
|
|
@@ -4,13 +4,13 @@ describe "default datastream csv parser" do
|
|
4
4
|
describe "csv" do
|
5
5
|
it "should convert Pachube CSV into attributes hash" do
|
6
6
|
csv = datastream_as_(:csv)
|
7
|
-
datastream = Cosm::Datastream.new(csv)
|
7
|
+
datastream = Cosm::Datastream.new(csv, :v2)
|
8
8
|
datastream.should fully_represent_datastream(:csv, csv)
|
9
9
|
end
|
10
10
|
|
11
11
|
it "should capture timestamp if present" do
|
12
12
|
csv = datastream_as_(:csv, :version => "timestamped")
|
13
|
-
datastream = Cosm::Datastream.new(csv)
|
13
|
+
datastream = Cosm::Datastream.new(csv, :v2, :csv)
|
14
14
|
datastream.updated.should == "2011-02-16T16:21:01.834174Z"
|
15
15
|
datastream.current_value.should == "14"
|
16
16
|
end
|
@@ -29,11 +29,82 @@ describe "default datastream csv parser" do
|
|
29
29
|
}.to raise_error(Cosm::Parsers::CSV::InvalidCSVError)
|
30
30
|
end
|
31
31
|
|
32
|
+
it "should raise error if passed more than a single value as v1" do
|
33
|
+
csv = "192,2"
|
34
|
+
expect {
|
35
|
+
Cosm::Datastream.new(csv, :v1)
|
36
|
+
}.to raise_error(Cosm::Parsers::CSV::InvalidCSVError)
|
37
|
+
end
|
38
|
+
|
32
39
|
it "should raise exception if passed garbage csv" do
|
33
40
|
expect {
|
34
41
|
Cosm::Datastream.new("badly, \"quoted", :csv)
|
35
42
|
}.to raise_error(Cosm::Parsers::CSV::InvalidCSVError)
|
36
43
|
end
|
44
|
+
|
45
|
+
it "should not raise exception if passed data with nil value" do
|
46
|
+
expect {
|
47
|
+
datastream = Cosm::Datastream.new("2012-08-12T00:00:00Z,", :v2)
|
48
|
+
datastream.current_value.should be_empty
|
49
|
+
}.to_not raise_error
|
50
|
+
end
|
51
|
+
|
52
|
+
it "should parse multiline csv" do
|
53
|
+
csv = <<-CSV
|
54
|
+
2012-02-08T00:00:00Z,123
|
55
|
+
2012-02-08T00:00:10Z,124
|
56
|
+
2012-02-08T00:00:20Z,125
|
57
|
+
2012-02-08T00:00:30Z,126
|
58
|
+
CSV
|
59
|
+
datastream = Cosm::Datastream.new(csv, :v2)
|
60
|
+
datastream.updated.should be_nil
|
61
|
+
datastream.current_value.should be_nil
|
62
|
+
datastream.datapoints.size.should == 4
|
63
|
+
datastream.datapoints.collect { |d| [d.at, d.value].join(",") }.join("\n").should == csv.strip
|
64
|
+
end
|
65
|
+
|
66
|
+
it "should not parse multiline csv passed to the v1 api" do
|
67
|
+
csv = <<-CSV
|
68
|
+
2012-02-08T00:00:00Z,123
|
69
|
+
2012-02-08T00:00:10Z,124
|
70
|
+
2012-02-08T00:00:20Z,125
|
71
|
+
2012-02-08T00:00:30Z,126
|
72
|
+
CSV
|
73
|
+
expect {
|
74
|
+
datastream = Cosm::Datastream.new(csv, :v1)
|
75
|
+
}.to raise_error(Cosm::Parsers::CSV::InvalidCSVError)
|
76
|
+
end
|
77
|
+
|
78
|
+
it "should not accept multiline csv with just single values" do
|
79
|
+
csv = <<-CSV
|
80
|
+
123
|
81
|
+
124
|
82
|
+
125
|
83
|
+
126
|
84
|
+
CSV
|
85
|
+
|
86
|
+
expect {
|
87
|
+
datastream = Cosm::Datastream.new(csv, :v2)
|
88
|
+
}.to raise_error(Cosm::Parsers::CSV::InvalidCSVError)
|
89
|
+
end
|
90
|
+
|
91
|
+
it "should strip whitespace from multiline values" do
|
92
|
+
csv = <<-CSV
|
93
|
+
2012-02-08T00:00:00Z , 123
|
94
|
+
2012-02-08T00:00:10Z , 124
|
95
|
+
2012-02-08T00:00:20Z , 125
|
96
|
+
2012-02-08T00:00:30Z , 126
|
97
|
+
CSV
|
98
|
+
|
99
|
+
datastream = Cosm::Datastream.new(csv, :v2)
|
100
|
+
datastream.updated.should be_nil
|
101
|
+
datastream.current_value.should be_nil
|
102
|
+
datastream.datapoints.size.should == 4
|
103
|
+
datastream.datapoints.sort { |a, b| a.at <=> b.at }.collect { |d| [d.at, d.value] }.should == [["2012-02-08T00:00:00Z","123"],
|
104
|
+
["2012-02-08T00:00:10Z","124"],
|
105
|
+
["2012-02-08T00:00:20Z","125"],
|
106
|
+
["2012-02-08T00:00:30Z","126"]]
|
107
|
+
end
|
37
108
|
end
|
38
109
|
end
|
39
110
|
|
@@ -61,6 +61,26 @@ CSV
|
|
61
61
|
}.to raise_error(Cosm::Parsers::CSV::InvalidCSVError, /3 rows/)
|
62
62
|
end
|
63
63
|
|
64
|
+
context "nil attribute csv" do
|
65
|
+
before(:each) do
|
66
|
+
@csv = "0,,"
|
67
|
+
end
|
68
|
+
|
69
|
+
it "should not raise exception if csv has nil values as v1" do
|
70
|
+
expect {
|
71
|
+
feed = Cosm::Feed.new(@csv, :v1)
|
72
|
+
feed.datastreams.size.should == 3
|
73
|
+
}.to_not raise_error
|
74
|
+
end
|
75
|
+
|
76
|
+
it "should not raise exception if csv has nil attributes as v2" do
|
77
|
+
expect {
|
78
|
+
feed = Cosm::Feed.new(@csv, :v2)
|
79
|
+
feed.datastreams.size.should == 1
|
80
|
+
}.to_not raise_error
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
64
84
|
context "unwanted whitespace" do
|
65
85
|
it "should strip whitespace from v2" do
|
66
86
|
dodgy_csv = <<-CSV
|
@@ -84,6 +104,107 @@ CSV
|
|
84
104
|
feed.should fully_represent_feed(:csv_v1, good_csv)
|
85
105
|
end
|
86
106
|
end
|
107
|
+
|
108
|
+
context "multivalue csv" do
|
109
|
+
def check_multiline_csv(csv)
|
110
|
+
feed = Cosm::Feed.new(csv)
|
111
|
+
|
112
|
+
feed.datastreams.size.should == 2
|
113
|
+
feed.datastreams.each do |datastream|
|
114
|
+
datastream.updated.should be_nil
|
115
|
+
datastream.current_value.should be_nil
|
116
|
+
datastream.datapoints.size.should == 3
|
117
|
+
datastream.datapoints.sort { |a,b| a.at <=> b.at }.collect { |d| [d.at, d.value] }.should == [["2012-08-12T00:00:00Z", "1"],
|
118
|
+
["2012-08-12T00:00:05Z", "2"],
|
119
|
+
["2012-08-12T00:00:10Z", "3"]]
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
it "should capture multivalue csv with timestamps" do
|
124
|
+
csv = <<-CSV
|
125
|
+
stream0,2012-08-12T00:00:00Z,1
|
126
|
+
stream1,2012-08-12T00:00:00Z,1
|
127
|
+
stream0,2012-08-12T00:00:05Z,2
|
128
|
+
stream1,2012-08-12T00:00:05Z,2
|
129
|
+
stream0,2012-08-12T00:00:10Z,3
|
130
|
+
stream1,2012-08-12T00:00:10Z,3
|
131
|
+
CSV
|
132
|
+
|
133
|
+
check_multiline_csv(csv)
|
134
|
+
end
|
135
|
+
|
136
|
+
it "should capture multivalue csv with timestamps no matter the grouping" do
|
137
|
+
csv = <<-CSV
|
138
|
+
stream0,2012-08-12T00:00:00Z,1
|
139
|
+
stream0,2012-08-12T00:00:05Z,2
|
140
|
+
stream0,2012-08-12T00:00:10Z,3
|
141
|
+
stream1,2012-08-12T00:00:00Z,1
|
142
|
+
stream1,2012-08-12T00:00:05Z,2
|
143
|
+
stream1,2012-08-12T00:00:10Z,3
|
144
|
+
CSV
|
145
|
+
|
146
|
+
check_multiline_csv(csv)
|
147
|
+
end
|
148
|
+
|
149
|
+
it "should strip whitespace from multiline csv" do
|
150
|
+
csv = <<-CSV
|
151
|
+
stream0, 2012-08-12T00:00:00Z, 1
|
152
|
+
stream0, 2012-08-12T00:00:05Z, 2
|
153
|
+
stream0, 2012-08-12T00:00:10Z, 3
|
154
|
+
stream1, 2012-08-12T00:00:00Z, 1
|
155
|
+
stream1, 2012-08-12T00:00:05Z, 2
|
156
|
+
stream1, 2012-08-12T00:00:10Z, 3
|
157
|
+
CSV
|
158
|
+
|
159
|
+
check_multiline_csv(csv)
|
160
|
+
end
|
161
|
+
|
162
|
+
it "should reject multivalue csv without timestamps" do
|
163
|
+
csv = <<-CSV
|
164
|
+
stream0,1
|
165
|
+
stream1,1
|
166
|
+
stream0,2
|
167
|
+
stream1,2
|
168
|
+
stream0,3
|
169
|
+
stream1,3
|
170
|
+
CSV
|
171
|
+
expect {
|
172
|
+
Cosm::Feed.new(csv)
|
173
|
+
}.to raise_error(Cosm::Parsers::CSV::InvalidCSVError)
|
174
|
+
end
|
175
|
+
|
176
|
+
it "should reject multivalue csv if we tell it its v1" do
|
177
|
+
csv = <<-CSV
|
178
|
+
stream0,2012-08-12T00:00:00Z,1
|
179
|
+
stream1,2012-08-12T00:00:00Z,1
|
180
|
+
CSV
|
181
|
+
|
182
|
+
expect {
|
183
|
+
Cosm::Feed.new(csv, :v1)
|
184
|
+
}.to raise_error(Cosm::Parsers::CSV::InvalidCSVError)
|
185
|
+
end
|
186
|
+
|
187
|
+
it "should permit an individual value within a larger update to not have a timestamp" do
|
188
|
+
csv = <<-CSV
|
189
|
+
stream0,2012-08-12T00:00:00Z,1
|
190
|
+
stream1,2012-08-12T00:00:00Z,1
|
191
|
+
stream0,2012-08-12T00:00:05Z,2
|
192
|
+
stream1,2012-08-12T00:00:05Z,2
|
193
|
+
stream0,2012-08-12T00:00:10Z,3
|
194
|
+
stream1,2012-08-12T00:00:10Z,3
|
195
|
+
stream2,4
|
196
|
+
CSV
|
197
|
+
feed = Cosm::Feed.new(csv)
|
198
|
+
feed.datastreams.size.should == 3
|
199
|
+
sorted_datastreams = feed.datastreams.sort { |a, b| a.id <=> b.id }
|
200
|
+
[0,1].each do |i|
|
201
|
+
sorted_datastreams[i].current_value.should be_nil
|
202
|
+
sorted_datastreams[i].updated.should be_nil
|
203
|
+
sorted_datastreams[i].datapoints.size.should == 3
|
204
|
+
end
|
205
|
+
sorted_datastreams[2].current_value.should == "4"
|
206
|
+
end
|
207
|
+
end
|
87
208
|
end
|
88
209
|
end
|
89
210
|
|
@@ -32,7 +32,7 @@ describe "default datastream json parser" do
|
|
32
32
|
|
33
33
|
it "should raise known exception if passed garbage as JSON" do
|
34
34
|
expect {
|
35
|
-
Cosm::Datastream.new("This is not json", :json)
|
35
|
+
Cosm::Datastream.new("This is not json", :v2, :json)
|
36
36
|
}.to raise_error(Cosm::Parsers::JSON::InvalidJSONError)
|
37
37
|
end
|
38
38
|
|
@@ -3,8 +3,8 @@ require 'spec_helper'
|
|
3
3
|
describe "default datastream xml parser" do
|
4
4
|
context "0.5.1 (used by API v2)" do
|
5
5
|
it "should convert into attributes hash" do
|
6
|
-
|
7
|
-
Cosm::Datastream.new(
|
6
|
+
xml = datastream_as_(:xml)
|
7
|
+
Cosm::Datastream.new(xml).should fully_represent_datastream(:xml, xml)
|
8
8
|
end
|
9
9
|
|
10
10
|
it "should convert into attributes hash when no version string but correct xmlns" do
|
@@ -13,30 +13,57 @@ describe "default datastream xml parser" do
|
|
13
13
|
end
|
14
14
|
|
15
15
|
it "should handle blank tags" do
|
16
|
-
|
17
|
-
Cosm::Datastream.new(
|
16
|
+
xml = datastream_as_(:xml, :except_node => :tag)
|
17
|
+
Cosm::Datastream.new(xml).should fully_represent_datastream(:xml, xml)
|
18
18
|
end
|
19
19
|
|
20
20
|
it "should handle blank units" do
|
21
|
-
|
22
|
-
Cosm::Datastream.new(
|
21
|
+
xml = datastream_as_(:xml, :except_node => :unit)
|
22
|
+
Cosm::Datastream.new(xml).should fully_represent_datastream(:xml, xml)
|
23
23
|
end
|
24
24
|
|
25
25
|
it "should handle missing unit attributes" do
|
26
|
-
|
27
|
-
Cosm::Datastream.new(
|
26
|
+
xml = datastream_as_(:xml, :except_node => :unit_attributes)
|
27
|
+
Cosm::Datastream.new(xml).should fully_represent_datastream(:xml, xml)
|
28
28
|
end
|
29
29
|
|
30
30
|
it "should handle missing timestamps" do
|
31
|
-
|
32
|
-
Cosm::Datastream.new(
|
31
|
+
xml = datastream_as_(:xml, :except_node => :timestamps)
|
32
|
+
Cosm::Datastream.new(xml).should fully_represent_datastream(:xml, xml)
|
33
|
+
end
|
34
|
+
|
35
|
+
it "should capture all datapoints" do
|
36
|
+
xml = datastream_as_(:xml)
|
37
|
+
datastream = Cosm::Datastream.new(xml)
|
38
|
+
datastream.datapoints.size.should == 3
|
39
|
+
end
|
40
|
+
|
41
|
+
it "should raise exception if passed xml containing more than one datastream" do
|
42
|
+
xml = feed_as_(:xml)
|
43
|
+
expect {
|
44
|
+
Cosm::Datastream.new(xml)
|
45
|
+
}.to raise_error(Cosm::Parsers::XML::InvalidXMLError)
|
46
|
+
end
|
47
|
+
|
48
|
+
it "should raise exception if passed xml without any datastreams" do
|
49
|
+
xml = <<-XML
|
50
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
51
|
+
<eeml xmlns="http://www.eeml.org/xsd/0.5.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="0.5.1" xsi:schemaLocation="http://www.eeml.org/xsd/0.5.1 http://www.eeml.org/xsd/0.5.1/0.5.1.xsd">
|
52
|
+
<environment id="504" creator="http://appdev.loc:3000/users/occaecati">
|
53
|
+
</environment>
|
54
|
+
</eeml>
|
55
|
+
XML
|
56
|
+
|
57
|
+
expect {
|
58
|
+
Cosm::Datastream.new(xml)
|
59
|
+
}.to raise_error(Cosm::Parsers::XML::InvalidXMLError)
|
33
60
|
end
|
34
61
|
end
|
35
62
|
|
36
63
|
context "5 (used by API v1)" do
|
37
64
|
it "should convert into attributes hash" do
|
38
|
-
|
39
|
-
Cosm::Datastream.new(
|
65
|
+
xml = datastream_as_(:xml, :version => "5")
|
66
|
+
Cosm::Datastream.new(xml).should fully_represent_datastream(:xml, xml)
|
40
67
|
end
|
41
68
|
|
42
69
|
it "should convert into attributes hash even when no version attribute if correct xmlns" do
|
@@ -45,34 +72,55 @@ describe "default datastream xml parser" do
|
|
45
72
|
end
|
46
73
|
|
47
74
|
it "should handle blank tags" do
|
48
|
-
|
49
|
-
Cosm::Datastream.new(
|
75
|
+
xml = datastream_as_(:xml, :version => "5", :except_node => :tag)
|
76
|
+
Cosm::Datastream.new(xml).should fully_represent_datastream(:xml, xml)
|
50
77
|
end
|
51
78
|
|
52
79
|
it "should handle blank units" do
|
53
|
-
|
54
|
-
Cosm::Datastream.new(
|
80
|
+
xml = datastream_as_(:xml, :version => "5", :except_node => :unit)
|
81
|
+
Cosm::Datastream.new(xml).should fully_represent_datastream(:xml, xml)
|
55
82
|
end
|
56
83
|
|
57
84
|
it "should handle missing unit attributes" do
|
58
|
-
|
59
|
-
Cosm::Datastream.new(
|
85
|
+
xml = datastream_as_(:xml, :version => "5", :except_node => :unit_attributes)
|
86
|
+
Cosm::Datastream.new(xml).should fully_represent_datastream(:xml, xml)
|
60
87
|
end
|
61
88
|
|
62
89
|
it "should handle missing value attributes" do
|
63
|
-
|
64
|
-
Cosm::Datastream.new(
|
90
|
+
xml = datastream_as_(:xml, :version => "5", :except_node => :value_attributes)
|
91
|
+
Cosm::Datastream.new(xml).should fully_represent_datastream(:xml, xml)
|
65
92
|
end
|
66
93
|
|
67
94
|
it "should handle missing timestamps" do
|
68
|
-
|
69
|
-
Cosm::Datastream.new(
|
95
|
+
xml = datastream_as_(:xml, :version => "5", :except_node => :timestamps)
|
96
|
+
Cosm::Datastream.new(xml).should fully_represent_datastream(:xml, xml)
|
97
|
+
end
|
98
|
+
|
99
|
+
it "should raise exception if passed xml containing more than one datastream" do
|
100
|
+
xml = feed_as_(:xml, :version => "5")
|
101
|
+
expect {
|
102
|
+
Cosm::Datastream.new(xml)
|
103
|
+
}.to raise_error(Cosm::Parsers::XML::InvalidXMLError)
|
104
|
+
end
|
105
|
+
|
106
|
+
it "should raise exception if passed xml without any datastreams" do
|
107
|
+
xml = <<-XML
|
108
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
109
|
+
<eeml xmlns="http://www.eeml.org/xsd/005" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="5" xsi:schemaLocation="http://www.eeml.org/xsd/005 http://www.eeml.org/xsd/005/005.xsd">
|
110
|
+
<environment updated="2011-02-16T16:21:01.834174Z" id="504" creator="http://appdev.loc:3000/users/occaecati">
|
111
|
+
</environment>
|
112
|
+
</eeml>
|
113
|
+
XML
|
114
|
+
|
115
|
+
expect {
|
116
|
+
Cosm::Datastream.new(xml)
|
117
|
+
}.to raise_error(Cosm::Parsers::XML::InvalidXMLError)
|
70
118
|
end
|
71
119
|
end
|
72
120
|
|
73
121
|
it "should raise exception if passed garbage as XML" do
|
74
122
|
expect {
|
75
|
-
Cosm::Datastream.new("This is not xml", :xml)
|
123
|
+
Cosm::Datastream.new("This is not xml", :v2, :xml)
|
76
124
|
}.to raise_error(Cosm::Parsers::XML::InvalidXMLError)
|
77
125
|
end
|
78
126
|
end
|
@@ -216,5 +216,39 @@ EOXML
|
|
216
216
|
}.to raise_error(Cosm::Parsers::XML::InvalidXMLError)
|
217
217
|
end
|
218
218
|
end
|
219
|
+
|
220
|
+
context "feeds with datapoints" do
|
221
|
+
it "should grab all datapoints present in valid xml" do
|
222
|
+
xml = <<-XML
|
223
|
+
<eeml xmlns="http://www.eeml.org/xsd/0.5.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="0.5.1" xsi:schemaLocation="http://www.eeml.org/xsd/0.5.1 http://www.eeml.org/xsd/0.5.1/0.5.1.xsd">
|
224
|
+
<environment>
|
225
|
+
<data id="0">
|
226
|
+
<datapoints>
|
227
|
+
<value at="2010-05-20T11:01:43Z">294</value>
|
228
|
+
<value at="2010-05-20T11:01:44Z">295</value>
|
229
|
+
<value at="2010-05-20T11:01:45Z">296</value>
|
230
|
+
<value at="2010-05-20T11:01:46Z">297</value>
|
231
|
+
</datapoints>
|
232
|
+
</data>
|
233
|
+
<data id="1">
|
234
|
+
<current_value at="2010-05-20T11:01:47Z">23</current_value>
|
235
|
+
<datapoints>
|
236
|
+
<value at="2010-05-20T11:01:43Z">24</value>
|
237
|
+
<value at="2010-05-20T11:01:44Z">25</value>
|
238
|
+
</datapoints>
|
239
|
+
</data>
|
240
|
+
</environment>
|
241
|
+
</eeml>
|
242
|
+
XML
|
243
|
+
feed = Cosm::Feed.new(xml)
|
244
|
+
feed.datastreams.size.should == 2
|
245
|
+
feed.datastreams[0].current_value.should == nil
|
246
|
+
feed.datastreams[0].datapoints.size.should == 4
|
247
|
+
feed.datastreams[0].datapoints.collect { |d| d.value }.should == ["294", "295", "296", "297"]
|
248
|
+
feed.datastreams[1].current_value.should == "23"
|
249
|
+
feed.datastreams[1].datapoints.size.should == 2
|
250
|
+
feed.datastreams[1].datapoints.collect { |d| d.value }.should == ["24", "25"]
|
251
|
+
end
|
252
|
+
end
|
219
253
|
end
|
220
254
|
|
data/spec/spec_helper.rb
CHANGED
@@ -77,10 +77,14 @@ RSpec::Matchers.define :fully_represent_datastream do |format, formatted_datastr
|
|
77
77
|
def match_json_datastream(datastream, formatted_datastream)
|
78
78
|
json = MultiJson.load(formatted_datastream)
|
79
79
|
case json['version']
|
80
|
-
when '
|
80
|
+
when '0.6-alpha'
|
81
81
|
raise "Not implemented"
|
82
82
|
else
|
83
|
-
|
83
|
+
datastream.current_value.should == json["current_value"]
|
84
|
+
datastream.id.should == json["id"]
|
85
|
+
datastream.updated.should == json["at"]
|
86
|
+
datastream.min_value.should == json["min_value"]
|
87
|
+
datastream.max_value.should == json["max_value"]
|
84
88
|
end
|
85
89
|
end
|
86
90
|
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: cosm-rb
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 21
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 2
|
9
|
-
-
|
10
|
-
version: 0.2.
|
9
|
+
- 1
|
10
|
+
version: 0.2.01
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Paul Bellamy
|
@@ -21,9 +21,7 @@ date: 2012-09-11 00:00:00 +00:00
|
|
21
21
|
default_executable:
|
22
22
|
dependencies:
|
23
23
|
- !ruby/object:Gem::Dependency
|
24
|
-
|
25
|
-
prerelease: false
|
26
|
-
requirement: &id001 !ruby/object:Gem::Requirement
|
24
|
+
version_requirements: &id001 !ruby/object:Gem::Requirement
|
27
25
|
none: false
|
28
26
|
requirements:
|
29
27
|
- - ">="
|
@@ -34,12 +32,12 @@ dependencies:
|
|
34
32
|
- 3
|
35
33
|
- 6
|
36
34
|
version: 1.3.6
|
35
|
+
requirement: *id001
|
37
36
|
type: :runtime
|
38
|
-
|
39
|
-
- !ruby/object:Gem::Dependency
|
40
|
-
name: multi_xml
|
37
|
+
name: multi_json
|
41
38
|
prerelease: false
|
42
|
-
|
39
|
+
- !ruby/object:Gem::Dependency
|
40
|
+
version_requirements: &id002 !ruby/object:Gem::Requirement
|
43
41
|
none: false
|
44
42
|
requirements:
|
45
43
|
- - ">="
|
@@ -50,12 +48,12 @@ dependencies:
|
|
50
48
|
- 5
|
51
49
|
- 1
|
52
50
|
version: 0.5.1
|
51
|
+
requirement: *id002
|
53
52
|
type: :runtime
|
54
|
-
|
55
|
-
- !ruby/object:Gem::Dependency
|
56
|
-
name: yajl-ruby
|
53
|
+
name: multi_xml
|
57
54
|
prerelease: false
|
58
|
-
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
version_requirements: &id003 !ruby/object:Gem::Requirement
|
59
57
|
none: false
|
60
58
|
requirements:
|
61
59
|
- - ">="
|
@@ -66,12 +64,12 @@ dependencies:
|
|
66
64
|
- 1
|
67
65
|
- 0
|
68
66
|
version: 1.1.0
|
67
|
+
requirement: *id003
|
69
68
|
type: :runtime
|
70
|
-
|
71
|
-
- !ruby/object:Gem::Dependency
|
72
|
-
name: nokogiri
|
69
|
+
name: yajl-ruby
|
73
70
|
prerelease: false
|
74
|
-
|
71
|
+
- !ruby/object:Gem::Dependency
|
72
|
+
version_requirements: &id004 !ruby/object:Gem::Requirement
|
75
73
|
none: false
|
76
74
|
requirements:
|
77
75
|
- - ">="
|
@@ -82,12 +80,12 @@ dependencies:
|
|
82
80
|
- 4
|
83
81
|
- 4
|
84
82
|
version: 1.4.4
|
83
|
+
requirement: *id004
|
85
84
|
type: :runtime
|
86
|
-
|
87
|
-
- !ruby/object:Gem::Dependency
|
88
|
-
name: httparty
|
85
|
+
name: nokogiri
|
89
86
|
prerelease: false
|
90
|
-
|
87
|
+
- !ruby/object:Gem::Dependency
|
88
|
+
version_requirements: &id005 !ruby/object:Gem::Requirement
|
91
89
|
none: false
|
92
90
|
requirements:
|
93
91
|
- - ">="
|
@@ -98,12 +96,12 @@ dependencies:
|
|
98
96
|
- 8
|
99
97
|
- 3
|
100
98
|
version: 0.8.3
|
99
|
+
requirement: *id005
|
101
100
|
type: :runtime
|
102
|
-
|
103
|
-
- !ruby/object:Gem::Dependency
|
104
|
-
name: fastercsv
|
101
|
+
name: httparty
|
105
102
|
prerelease: false
|
106
|
-
|
103
|
+
- !ruby/object:Gem::Dependency
|
104
|
+
version_requirements: &id006 !ruby/object:Gem::Requirement
|
107
105
|
none: false
|
108
106
|
requirements:
|
109
107
|
- - ">="
|
@@ -114,12 +112,12 @@ dependencies:
|
|
114
112
|
- 5
|
115
113
|
- x
|
116
114
|
version: 1.5.x
|
115
|
+
requirement: *id006
|
117
116
|
type: :runtime
|
118
|
-
|
119
|
-
- !ruby/object:Gem::Dependency
|
120
|
-
name: ox
|
117
|
+
name: fastercsv
|
121
118
|
prerelease: false
|
122
|
-
|
119
|
+
- !ruby/object:Gem::Dependency
|
120
|
+
version_requirements: &id007 !ruby/object:Gem::Requirement
|
123
121
|
none: false
|
124
122
|
requirements:
|
125
123
|
- - ">="
|
@@ -130,12 +128,12 @@ dependencies:
|
|
130
128
|
- 5
|
131
129
|
- 9
|
132
130
|
version: 1.5.9
|
131
|
+
requirement: *id007
|
133
132
|
type: :runtime
|
134
|
-
|
135
|
-
- !ruby/object:Gem::Dependency
|
136
|
-
name: ruby-debug
|
133
|
+
name: ox
|
137
134
|
prerelease: false
|
138
|
-
|
135
|
+
- !ruby/object:Gem::Dependency
|
136
|
+
version_requirements: &id008 !ruby/object:Gem::Requirement
|
139
137
|
none: false
|
140
138
|
requirements:
|
141
139
|
- - ">="
|
@@ -144,12 +142,12 @@ dependencies:
|
|
144
142
|
segments:
|
145
143
|
- 0
|
146
144
|
version: "0"
|
145
|
+
requirement: *id008
|
147
146
|
type: :development
|
148
|
-
|
149
|
-
- !ruby/object:Gem::Dependency
|
150
|
-
name: rcov
|
147
|
+
name: ruby-debug
|
151
148
|
prerelease: false
|
152
|
-
|
149
|
+
- !ruby/object:Gem::Dependency
|
150
|
+
version_requirements: &id009 !ruby/object:Gem::Requirement
|
153
151
|
none: false
|
154
152
|
requirements:
|
155
153
|
- - ">="
|
@@ -160,12 +158,12 @@ dependencies:
|
|
160
158
|
- 9
|
161
159
|
- 9
|
162
160
|
version: 0.9.9
|
161
|
+
requirement: *id009
|
163
162
|
type: :development
|
164
|
-
|
165
|
-
- !ruby/object:Gem::Dependency
|
166
|
-
name: rake
|
163
|
+
name: rcov
|
167
164
|
prerelease: false
|
168
|
-
|
165
|
+
- !ruby/object:Gem::Dependency
|
166
|
+
version_requirements: &id010 !ruby/object:Gem::Requirement
|
169
167
|
none: false
|
170
168
|
requirements:
|
171
169
|
- - "="
|
@@ -176,12 +174,12 @@ dependencies:
|
|
176
174
|
- 8
|
177
175
|
- 7
|
178
176
|
version: 0.8.7
|
177
|
+
requirement: *id010
|
179
178
|
type: :development
|
180
|
-
|
181
|
-
- !ruby/object:Gem::Dependency
|
182
|
-
name: rspec
|
179
|
+
name: rake
|
183
180
|
prerelease: false
|
184
|
-
|
181
|
+
- !ruby/object:Gem::Dependency
|
182
|
+
version_requirements: &id011 !ruby/object:Gem::Requirement
|
185
183
|
none: false
|
186
184
|
requirements:
|
187
185
|
- - "="
|
@@ -192,8 +190,10 @@ dependencies:
|
|
192
190
|
- 6
|
193
191
|
- 0
|
194
192
|
version: 2.6.0
|
193
|
+
requirement: *id011
|
195
194
|
type: :development
|
196
|
-
|
195
|
+
name: rspec
|
196
|
+
prerelease: false
|
197
197
|
description: A library for communicating with the Cosm REST API, parsing and rendering Cosm feed formats
|
198
198
|
email:
|
199
199
|
- paul.a.bellamy@gmail.com
|