eeml 0.0.1 → 0.0.2
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/CHANGELOG +506 -0
- data/Manifest +6 -3
- data/README +2 -2
- data/Rakefile +1 -1
- data/eeml.gemspec +7 -7
- data/example.rb +11 -6
- data/lib/eeml/constants.rb +4 -3
- data/lib/eeml/csv_parser.rb +0 -1
- data/lib/eeml/environment.rb +35 -23
- data/lib/eeml/exceptions.rb +58 -54
- data/lib/eeml/json_environment_parser_v005.rb +69 -0
- data/lib/eeml/json_output.rb +86 -0
- data/lib/eeml/libxml_eeml_parser_v005.rb +30 -5
- data/lib/eeml/output_registry.rb +2 -2
- data/lib/eeml/parser_registry.rb +3 -2
- data/lib/eeml.rb +7 -14
- data/test/data/doc_1.json +30 -2
- data/test/data/doc_2.xml +36 -0
- data/test/data/doc_2_expected.json +35 -0
- data/test/data/list.xml +38 -0
- data/test/data/no_namespace.xml +9 -0
- data/test/test_environment.rb +147 -9
- data/test/test_helper.rb +62 -2
- data/test/test_libxml_eeml_parser_v005.rb +3 -0
- data.tar.gz.sig +0 -0
- metadata +11 -9
- metadata.gz.sig +1 -3
- data/lib/eeml/feed_output.rb +0 -169
- data/lib/eeml/feed_retriever.rb +0 -103
- data/lib/eeml/json_environment_parser.rb +0 -11
data/test/test_environment.rb
CHANGED
@@ -163,6 +163,30 @@ class TestEnvironment < Test::Unit::TestCase
|
|
163
163
|
assert_equal "36.2", datastream.value
|
164
164
|
end
|
165
165
|
|
166
|
+
test "fails if no default namespace provided" do
|
167
|
+
assert_raise(MissingNamespace) {env = create_env_from_xml_file('no_namespace.xml')}
|
168
|
+
end
|
169
|
+
|
170
|
+
test "creates multiple environments from list xml" do
|
171
|
+
xml = File.read('test/data/list.xml')
|
172
|
+
list = Environment.new_list_from_eeml(xml)
|
173
|
+
assert 3, list.size
|
174
|
+
list.each do |obj|
|
175
|
+
assert obj.is_a? Environment
|
176
|
+
end
|
177
|
+
titles = list.map {|e| e.title}.sort
|
178
|
+
expected_titles = ["Badgerpower", "CurrentCost for house", "Power and Temperature"]
|
179
|
+
assert_equal expected_titles, titles
|
180
|
+
#TODO: check the environments fully (that no aliasing or other confusion has occurred in their parsing)
|
181
|
+
end
|
182
|
+
|
183
|
+
test "creates zero environments from list xml when has none" do
|
184
|
+
original_xml = File.read('test/data/list.xml')
|
185
|
+
xml = remove_nodes_called('environment', original_xml)
|
186
|
+
list = Environment.new_list_from_eeml(xml)
|
187
|
+
assert list.empty?, "should be empty list"
|
188
|
+
end
|
189
|
+
|
166
190
|
def read_xml_file_one
|
167
191
|
return File.read('test/data/doc_1.xml')
|
168
192
|
end
|
@@ -246,20 +270,75 @@ class TestEnvironment < Test::Unit::TestCase
|
|
246
270
|
assert_equal 'http://www.example.com/ourstudio/feeds/house.xml', env.feed_url
|
247
271
|
end
|
248
272
|
|
249
|
-
# ---
|
250
|
-
# --- json stuff
|
251
|
-
# ---
|
273
|
+
# --- ------------------------------------------------------
|
274
|
+
# --- json input stuff ------------------------------------------------------
|
275
|
+
# --- ------------------------------------------------------
|
252
276
|
|
253
277
|
test "creating Env obj from a JSON string" do
|
254
278
|
env = create_env_from_json_file_one
|
255
279
|
assert_not_nil env
|
256
280
|
assert_instance_of Environment, env
|
281
|
+
assert_equal('title here', env.title)
|
282
|
+
assert_equal('description here', env.description)
|
283
|
+
assert_equal('http://example.com/api/1247.xml', env.feed_url)
|
284
|
+
assert_equal('http://example.com/studio/', env.website)
|
285
|
+
assert_equal('frozen', env.status)
|
286
|
+
assert_equal('someone@example.com', env.email)
|
287
|
+
assert_equal('http://example.com/some/icon.gif', env.icon)
|
288
|
+
|
289
|
+
#env attrs
|
290
|
+
assert_equal('1247', env.identifier)
|
291
|
+
assert_equal('2009-02-11T10:56:56Z', env.updated.strftime("%Y-%m-%dT%H:%M:%SZ"))
|
257
292
|
end
|
258
293
|
|
294
|
+
test "location parses ok from json" do
|
295
|
+
env = create_env_from_json_file_one
|
296
|
+
assert_not_nil env.location
|
297
|
+
location = env.location
|
298
|
+
assert_equal "Up on the roof (somewhere)", location.name
|
299
|
+
assert_equal "50.1", location.latitude
|
300
|
+
assert_equal "48.7", location.longitude
|
301
|
+
assert_equal "1.34", location.elevation
|
302
|
+
assert_equal "physical", location.domain
|
303
|
+
assert_equal "outdoor", location.exposure
|
304
|
+
assert_equal "mobile", location.disposition
|
305
|
+
end
|
259
306
|
|
260
|
-
|
261
|
-
|
262
|
-
|
307
|
+
test "datastreams parse ok from json" do
|
308
|
+
env = create_env_from_json_file_one
|
309
|
+
assert_equal 3, env.datastreams.size
|
310
|
+
|
311
|
+
#the expected values for the datastreams in the test doc
|
312
|
+
expectations_list = [
|
313
|
+
#id, tag array, min, max, value, unit_symbol, unit_type, unit_value
|
314
|
+
['0', ['tagD0'], '-9999.0', '1022.0', '0', 'C', 'basicSI', 'Celsius'],
|
315
|
+
['1', [], '0.0', '1023.0', '33', nil, nil, nil],
|
316
|
+
['2', ['tagD2a', 'tagD2b', 'tagD2c'], '23.4', '1021.0', '42.1', nil, nil, nil]
|
317
|
+
]
|
318
|
+
env.datastreams.each_with_index do |ds, i|
|
319
|
+
|
320
|
+
e_identifier, e_tags, e_min_value, e_max_value, e_value, e_unit_symbol, e_unit_type, e_unit_value = expectations_list[i]
|
321
|
+
|
322
|
+
assert_equal e_identifier, ds.identifier
|
323
|
+
|
324
|
+
assert_equal e_tags.size, ds.tags.size, "should have right num of tags"
|
325
|
+
|
326
|
+
e_tags.each do |expected_tag|
|
327
|
+
ds.tags.member? expected_tag
|
328
|
+
end
|
329
|
+
|
330
|
+
assert_equal e_min_value, ds.min_value
|
331
|
+
assert_equal e_max_value, ds.max_value
|
332
|
+
assert_equal e_value, ds.value
|
333
|
+
assert_equal e_unit_symbol, ds.unit_symbol
|
334
|
+
assert_equal e_unit_type, ds.unit_type
|
335
|
+
assert_equal e_unit_value, ds.unit_value
|
336
|
+
end
|
337
|
+
end
|
338
|
+
|
339
|
+
# --- -------------------------------------------------------
|
340
|
+
# --- csv input stuff -------------------------------------------------------
|
341
|
+
# --- -------------------------------------------------------
|
263
342
|
|
264
343
|
def create_env_with_datastream_values(values)
|
265
344
|
e = Environment.new
|
@@ -305,9 +384,10 @@ class TestEnvironment < Test::Unit::TestCase
|
|
305
384
|
env.update_datastreams_from_csv_values!(values)
|
306
385
|
assert_equal values, env.values_quick
|
307
386
|
end
|
308
|
-
|
309
|
-
# ---
|
310
|
-
# ---
|
387
|
+
|
388
|
+
# --- -----------------------------------------------------
|
389
|
+
# --- eeml output stuff -----------------------------------------------------
|
390
|
+
# --- -----------------------------------------------------
|
311
391
|
|
312
392
|
test "should output to xml ok" do
|
313
393
|
env = create_env_from_xml_file_one
|
@@ -331,7 +411,58 @@ class TestEnvironment < Test::Unit::TestCase
|
|
331
411
|
assert_equal expected_xml, output_xml
|
332
412
|
end
|
333
413
|
|
414
|
+
# --- -----------------------------------------------------
|
415
|
+
# --- json output stuff -----------------------------------------------------
|
416
|
+
# --- -----------------------------------------------------
|
417
|
+
#DEV NOTE: use jsondiff tool to visual-diff expected and actual json http://tlrobinson.net/projects/js/jsondiff/
|
418
|
+
|
419
|
+
#TODO: decide what trailing whitespace should be output after json, and eeml, and correct tests
|
420
|
+
test "basic output in public json format" do
|
421
|
+
input_xml = File.read('test/data/doc_2.xml')
|
422
|
+
env = create_env_from_xml_string(input_xml)
|
423
|
+
output_json = env.to_json
|
424
|
+
expected_json = File.read('test/data/doc_2_expected.json').rstrip
|
425
|
+
expected_hash = JSON.parse(expected_json)
|
426
|
+
output_hash = JSON.parse(output_json)
|
427
|
+
assert_equal(expected_hash, output_hash)
|
428
|
+
end
|
334
429
|
|
430
|
+
test "basic output in public json format - no location" do
|
431
|
+
input_xml = File.read('test/data/doc_2.xml')
|
432
|
+
input_xml = remove_first_node_called('location', input_xml)
|
433
|
+
env = create_env_from_xml_string(input_xml)
|
434
|
+
output_json = env.to_json
|
435
|
+
output_hash = JSON.parse(output_json)
|
436
|
+
|
437
|
+
expected_json = File.read('test/data/doc_2_expected.json')
|
438
|
+
expected_hash = JSON.parse(expected_json)
|
439
|
+
assert_not_nil expected_hash.delete("location")
|
440
|
+
assert_json_hashes_equal(expected_hash, output_hash)
|
441
|
+
end
|
442
|
+
|
443
|
+
test "basic output in public json format - location but no latitude" do
|
444
|
+
input_xml = File.read('test/data/doc_2.xml')
|
445
|
+
input_xml = remove_first_node_called('lat', input_xml)
|
446
|
+
env = create_env_from_xml_string(input_xml)
|
447
|
+
actual_json = env.to_json
|
448
|
+
actual_hash = JSON.parse(actual_json)
|
449
|
+
|
450
|
+
assert_nil env.location.latitude
|
451
|
+
expected_json = File.read('test/data/doc_2_expected.json')
|
452
|
+
expected_hash = JSON.parse(expected_json)
|
453
|
+
expected_hash["location"].delete("lat")
|
454
|
+
#File.open('tmp_expected.json', 'w') {|f| f.write expected_hash.to_json }
|
455
|
+
#File.open('tmp_actual.json', 'w') {|f| f.write actual_hash.to_json }
|
456
|
+
|
457
|
+
assert_json_hashes_equal(expected_hash, actual_hash)
|
458
|
+
end
|
459
|
+
|
460
|
+
test "basic output in public json format - minimal env" do
|
461
|
+
env = Environment.new
|
462
|
+
assert_nil env.identifier
|
463
|
+
output_json = env.to_json
|
464
|
+
assert_not_nil output_json
|
465
|
+
end
|
335
466
|
|
336
467
|
# --- convenience stuff - don't put tests under here ------------------------------
|
337
468
|
|
@@ -366,5 +497,12 @@ class TestEnvironment < Test::Unit::TestCase
|
|
366
497
|
return Environment.new_from_json(json)
|
367
498
|
end
|
368
499
|
|
500
|
+
def prep_json_for_reading(json)
|
501
|
+
return nil if json.nil?
|
502
|
+
json.gsub(/","/, '"' + "\n" + '"').sort
|
503
|
+
end
|
504
|
+
|
505
|
+
|
506
|
+
|
369
507
|
|
370
508
|
end
|
data/test/test_helper.rb
CHANGED
@@ -5,13 +5,12 @@ require 'test/libxml_test_helper'
|
|
5
5
|
# Thought a mock library will be useful for testing out any stuff that
|
6
6
|
# does any http-ing, but have no strong feelings about which one to use.
|
7
7
|
# Looking at the syntax of each of the libraries, I liked the look of the
|
8
|
-
# mocha syntax more, so was thinking to use that when required.
|
8
|
+
# mocha syntax more, so was thinking to use that when/if required.
|
9
9
|
#
|
10
10
|
# require 'flexmock'
|
11
11
|
require 'mocha'
|
12
12
|
|
13
13
|
|
14
|
-
|
15
14
|
#consider adding custom assertions to clean code up
|
16
15
|
#http://www.ruby-doc.org/stdlib/libdoc/test/unit/rdoc/classes/Test/Unit/Assertions.html
|
17
16
|
|
@@ -47,10 +46,71 @@ class Test::Unit::TestCase
|
|
47
46
|
out
|
48
47
|
end
|
49
48
|
|
49
|
+
#compare not the given json strings directly but their hash structures after parsing.
|
50
|
+
#also try to give a more concise diff, if they are different, using Hash.diff from activesupport
|
51
|
+
def assert_json_strings_equal(expected_string, actual_string, message=nil)
|
52
|
+
expected_structure = JSON.parse(expected_string)
|
53
|
+
actual_structure = JSON.parse(actual_string)
|
54
|
+
|
55
|
+
diff = expected_structure.diff(actual_structure)
|
56
|
+
diff_string = diff.inspect.gsub(/"/, "'")
|
57
|
+
full_message = build_message(message, "Parsed JSON structure doesn't match expected. Hash Diff (quotes changed): <?>\n" +
|
58
|
+
"Full text: Expected: \n<?>\nbut was: <?>.\n",
|
59
|
+
diff_string, expected_string, actual_string)
|
60
|
+
assert_block(full_message) do
|
61
|
+
expected_structure == actual_structure
|
62
|
+
end
|
63
|
+
#File.open('tmp.json', 'w') {|f| f.write output_json }
|
64
|
+
#File.open('tmp_split.json', 'w') {|f| f.write prep_json_for_reading(output_json) }
|
65
|
+
#File.open('tmp_expected_split.json', 'w') {|f| f.write prep_json_for_reading(expected_json)}
|
66
|
+
|
67
|
+
#TODO: consider allowing submission of both to a json visual diff app, too. (only if switched on by an environment variable).
|
68
|
+
end
|
69
|
+
|
70
|
+
def assert_json_hashes_equal(expected_structure, actual_structure, message=nil)
|
71
|
+
diff = expected_structure.diff(actual_structure)
|
72
|
+
diff_string = diff.inspect.gsub(/"/, "'")
|
73
|
+
full_message = build_message(message, "JSON structure doesn't match expected. Hash Diff (quotes changed): <?>\n" +
|
74
|
+
"Full values: Expected: \n<?>\nbut was: <?>.\n", diff_string, expected_structure.inspect, actual_structure.inspect)
|
75
|
+
assert_block(full_message) do
|
76
|
+
expected_structure == actual_structure
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
50
80
|
end
|
51
81
|
|
82
|
+
|
83
|
+
|
84
|
+
#TODO: don't add this Hash.diff(h2) for all hashes, only for ones we want to diff (e.g. on the fly during assert_json_strings_equal)
|
85
|
+
#TODO: check rails license
|
86
|
+
module ASCoreExtensions #was ActiveSupport
|
87
|
+
module Hash #:nodoc:
|
88
|
+
module Diff
|
89
|
+
# Returns a hash that represents the difference between two hashes.
|
90
|
+
#
|
91
|
+
# Examples:
|
92
|
+
#
|
93
|
+
# {1 => 2}.diff(1 => 2) # => {}
|
94
|
+
# {1 => 2}.diff(1 => 3) # => {1 => 2}
|
95
|
+
# {}.diff(1 => 2) # => {1 => 2}
|
96
|
+
# {1 => 2, 3 => 4}.diff(1 => 2) # => {3 => 4}
|
97
|
+
def diff(h2)
|
98
|
+
self.dup.delete_if { |k, v| h2[k] == v }.merge(h2.dup.delete_if { |k, v| self.has_key?(k) })
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
class Hash #:nodoc:
|
105
|
+
include ASCoreExtensions::Hash::Diff
|
106
|
+
end
|
107
|
+
|
108
|
+
|
109
|
+
|
52
110
|
$:.unshift(File.join(File.dirname(__FILE__), "..", "lib"))
|
53
111
|
|
54
112
|
require 'eeml'
|
55
113
|
|
56
114
|
include Eeml
|
115
|
+
|
116
|
+
|
data.tar.gz.sig
CHANGED
Binary file
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: eeml
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Neill Bogie, Sam Mulube
|
@@ -30,7 +30,7 @@ cert_chain:
|
|
30
30
|
yyRwZdVyDdsafg==
|
31
31
|
-----END CERTIFICATE-----
|
32
32
|
|
33
|
-
date: 2009-
|
33
|
+
date: 2009-05-05 00:00:00 +01:00
|
34
34
|
default_executable:
|
35
35
|
dependencies:
|
36
36
|
- !ruby/object:Gem::Dependency
|
@@ -57,7 +57,7 @@ dependencies:
|
|
57
57
|
version: "0"
|
58
58
|
- - "="
|
59
59
|
- !ruby/object:Gem::Version
|
60
|
-
version: 1.1.
|
60
|
+
version: 1.1.4
|
61
61
|
version:
|
62
62
|
- !ruby/object:Gem::Dependency
|
63
63
|
name: rake
|
@@ -97,15 +97,14 @@ extra_rdoc_files:
|
|
97
97
|
- README
|
98
98
|
- lib/eeml.rb
|
99
99
|
- lib/eeml/constants.rb
|
100
|
-
- lib/eeml/
|
101
|
-
- lib/eeml/json_environment_parser.rb
|
100
|
+
- lib/eeml/json_environment_parser_v005.rb
|
102
101
|
- lib/eeml/output_registry.rb
|
103
102
|
- lib/eeml/parser_registry.rb
|
104
103
|
- lib/eeml/libxml_eeml_output_v005.rb
|
105
|
-
- lib/eeml/feed_output.rb
|
106
104
|
- lib/eeml/libxml_eeml_parser_v005.rb
|
107
105
|
- lib/eeml/exceptions.rb
|
108
106
|
- lib/eeml/csv_parser.rb
|
107
|
+
- lib/eeml/json_output.rb
|
109
108
|
- lib/eeml/environment.rb
|
110
109
|
- lib/blank.rb
|
111
110
|
files:
|
@@ -120,20 +119,23 @@ files:
|
|
120
119
|
- test/test_libxml_eeml_parser_v005.rb
|
121
120
|
- test/test_helper.rb
|
122
121
|
- test/data/minimal.xml
|
122
|
+
- test/data/doc_2_expected.json
|
123
|
+
- test/data/list.xml
|
123
124
|
- test/data/out_empty.xml
|
125
|
+
- test/data/no_namespace.xml
|
124
126
|
- test/data/doc_1.xml
|
125
127
|
- test/data/doc_1.json
|
128
|
+
- test/data/doc_2.xml
|
126
129
|
- lib/eeml.rb
|
127
130
|
- lib/eeml/constants.rb
|
128
|
-
- lib/eeml/
|
129
|
-
- lib/eeml/json_environment_parser.rb
|
131
|
+
- lib/eeml/json_environment_parser_v005.rb
|
130
132
|
- lib/eeml/output_registry.rb
|
131
133
|
- lib/eeml/parser_registry.rb
|
132
134
|
- lib/eeml/libxml_eeml_output_v005.rb
|
133
|
-
- lib/eeml/feed_output.rb
|
134
135
|
- lib/eeml/libxml_eeml_parser_v005.rb
|
135
136
|
- lib/eeml/exceptions.rb
|
136
137
|
- lib/eeml/csv_parser.rb
|
138
|
+
- lib/eeml/json_output.rb
|
137
139
|
- lib/eeml/environment.rb
|
138
140
|
- lib/blank.rb
|
139
141
|
- schemas/eeml/005.xsd
|
metadata.gz.sig
CHANGED
@@ -1,3 +1 @@
|
|
1
|
-
|
2
|
-
A���5jj�Bh�k_�G�F�ȴ'*KLY�|4��Q��
|
3
|
-
��<R���57z>ӱ�|�|]m��E:��a�.{�ҹ�J��h:�C�C�Է��DT���д���w�^d^
|
1
|
+
>�t�{�����)g�Bcg�T8�Z"B��.���C釴�d��3����M|�����I����uJ��Z�����Z%t4y��jM�����9 �=4<�+W���Y��l��M��et^>puEz�J4���?@�Mn\�kR�1���)�/�ʶTMy{��mb��J71_&v��5&�g�ˡ�l���JJ�v���c�؏oY�w���d�wN�9�[��Z����8S1�<wC�p�@�'�.�I�X�"X���B}�
|
data/lib/eeml/feed_output.rb
DELETED
@@ -1,169 +0,0 @@
|
|
1
|
-
module FeedOutput # :nodoc:
|
2
|
-
#TODO: move away from mixins for this functionality.
|
3
|
-
#TODO: This is v005-specific.
|
4
|
-
module EnvironmentNode # :nodoc:
|
5
|
-
include LibXML
|
6
|
-
#assumes a logger()
|
7
|
-
#assumes retrieved_at()
|
8
|
-
|
9
|
-
#TODO: Move these (now unused) methods to the publisher (e.g. a rails controller?) which will decide where it's going to host the env,
|
10
|
-
# and which will set the feed property accordingly before serialising the env.
|
11
|
-
# def public_feed_url
|
12
|
-
# return "http://#{DEFAULT_HOST}/api/#{self.id}.xml"
|
13
|
-
# end
|
14
|
-
|
15
|
-
# def public_csv_url
|
16
|
-
# return "http://#{DEFAULT_HOST}/api/#{self.id}.csv"
|
17
|
-
# end
|
18
|
-
|
19
|
-
# def public_json_url
|
20
|
-
# return "http://#{DEFAULT_HOST}/api/#{self.id}.json"
|
21
|
-
# end
|
22
|
-
|
23
|
-
|
24
|
-
def create_eeml_document
|
25
|
-
doc = XML::Document.new
|
26
|
-
eeml = doc.root = XML::Node.new('eeml')
|
27
|
-
XML::Namespace.new(eeml, nil, Eeml::EEML_HREF)
|
28
|
-
XML::Namespace.new(eeml, 'xsi', Eeml::XSI_NAMESPACE)
|
29
|
-
eeml['version'] = Eeml::EEML_VERSION
|
30
|
-
eeml['xsi:schemaLocation'] = Eeml::EEML_SCHEMA_LOCATION
|
31
|
-
return doc
|
32
|
-
end
|
33
|
-
|
34
|
-
# Create a csv representation of this environment by iterating through all datastreams and returning
|
35
|
-
# their values.
|
36
|
-
def to_csv
|
37
|
-
return self.datastreams.map { |d| d.value }.join(",")
|
38
|
-
end
|
39
|
-
|
40
|
-
# Create an xml representation of this environment. The document returned should be valid EEML.
|
41
|
-
# def to_eeml(options = { :full => true })
|
42
|
-
# # Returns the public feed URL for this environment.
|
43
|
-
|
44
|
-
|
45
|
-
# logger.debug("*** Returning eeml representation of environment: #{self.identifier}")
|
46
|
-
|
47
|
-
# doc = create_eeml_document
|
48
|
-
|
49
|
-
# doc.root << to_xml_node(options)
|
50
|
-
|
51
|
-
# return doc.to_s(:encoding => XML::Encoding::UTF_8)
|
52
|
-
# end
|
53
|
-
|
54
|
-
def to_xml_node_old(options = { :full => true })
|
55
|
-
logger.debug("*** Creating xml node for environment: #{self.identifier}")
|
56
|
-
|
57
|
-
environment_node = XML::Node.new('environment')
|
58
|
-
#TODO: this was retrieved_at in the db, but it's 'updated' in the xml. Clarify w sam...
|
59
|
-
# ... env.retrieved_at doesn't make much sense to clients generating eeml using the gem.
|
60
|
-
environment_node['updated'] = self.updated.strftime(XML_TIME_FORMAT_STRING) unless self.updated.nil?
|
61
|
-
environment_node['id'] = self.identifier.to_s unless self.identifier.blank?
|
62
|
-
#TODO: write all these strings out safely for xml
|
63
|
-
environment_node['creator'] = self.creator.to_s unless self.creator.blank?
|
64
|
-
|
65
|
-
#TODO: these all should really appear, even when absent? likely make conditional.
|
66
|
-
unless self.title.blank?
|
67
|
-
environment_node << title_node = XML::Node.new('title')
|
68
|
-
title_node << self.title
|
69
|
-
end
|
70
|
-
|
71
|
-
unless self.feed_url.blank?
|
72
|
-
environment_node << feed_node = XML::Node.new('feed')
|
73
|
-
feed_node << self.feed_url
|
74
|
-
end
|
75
|
-
|
76
|
-
unless self.status.blank?
|
77
|
-
environment_node << status_node = XML::Node.new('status')
|
78
|
-
status_node << self.status
|
79
|
-
end
|
80
|
-
|
81
|
-
unless self.description.blank?
|
82
|
-
environment_node << description_node = XML::Node.new('description')
|
83
|
-
description_node << self.description
|
84
|
-
end
|
85
|
-
|
86
|
-
unless self.icon.blank?
|
87
|
-
environment_node << icon_node = XML::Node.new('icon')
|
88
|
-
icon_node << self.icon
|
89
|
-
end
|
90
|
-
|
91
|
-
unless self.website.blank?
|
92
|
-
environment_node << website_node = XML::Node.new('website')
|
93
|
-
website_node << self.website
|
94
|
-
end
|
95
|
-
|
96
|
-
unless self.email.blank?
|
97
|
-
environment_node << email_node = XML::Node.new('email')
|
98
|
-
email_node << self.email
|
99
|
-
end
|
100
|
-
|
101
|
-
unless self.location.nil?
|
102
|
-
environment_node << location_node = XML::Node.new('location')
|
103
|
-
location_node['domain'] = self.location.domain
|
104
|
-
location_node['exposure'] = self.location.exposure unless self.location.exposure.blank?
|
105
|
-
location_node['disposition'] = self.location.disposition unless self.location.disposition.blank?
|
106
|
-
|
107
|
-
unless self.location.name.blank?
|
108
|
-
location_node << location_name_node = XML::Node.new('name')
|
109
|
-
location_name_node << self.location.name
|
110
|
-
end
|
111
|
-
|
112
|
-
location_node << lat_node = XML::Node.new('lat')
|
113
|
-
lat_node << self.location.latitude
|
114
|
-
|
115
|
-
location_node << lng_node = XML::Node.new('lon')
|
116
|
-
lng_node << self.location.longitude
|
117
|
-
|
118
|
-
unless self.location.elevation.blank?
|
119
|
-
location_node << elevation_node = XML::Node.new('ele')
|
120
|
-
elevation_node << self.location.elevation
|
121
|
-
end
|
122
|
-
end
|
123
|
-
|
124
|
-
if options[:full] == true
|
125
|
-
self.datastreams.each do |datastream|
|
126
|
-
environment_node << datastream.to_xml_node unless datastream.nil?
|
127
|
-
end
|
128
|
-
end
|
129
|
-
|
130
|
-
return environment_node
|
131
|
-
end
|
132
|
-
end
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
module DataStreamNode # :nodoc:
|
137
|
-
include LibXML
|
138
|
-
# Create and return an XML::Node object representing this datastream. This method creates all
|
139
|
-
# required child nodes of the datastream object, including the list of tag elements, any units element
|
140
|
-
# and the value.
|
141
|
-
def to_xml_node
|
142
|
-
datastream_node = XML::Node.new('data')
|
143
|
-
datastream_node['id'] = self.identifier.to_s
|
144
|
-
|
145
|
-
self.tags.each do |tag|
|
146
|
-
tag_node = XML::Node.new('tag')
|
147
|
-
tag_node << tag
|
148
|
-
datastream_node << tag_node
|
149
|
-
end
|
150
|
-
|
151
|
-
datastream_node << value_node = XML::Node.new('value')
|
152
|
-
|
153
|
-
value_node['minValue'] = self.min_value.to_s unless self.min_value.to_s.empty?
|
154
|
-
value_node['maxValue'] = self.max_value.to_s unless self.max_value.to_s.empty?
|
155
|
-
|
156
|
-
value_node << self.value.to_s
|
157
|
-
|
158
|
-
unless self.unit_value.to_s.empty? && self.unit_type.to_s.empty? && self.unit_symbol.to_s.empty?
|
159
|
-
datastream_node << unit_node = XML::Node.new('unit')
|
160
|
-
unit_node['type'] = self.unit_type.to_s unless self.unit_type.to_s.empty?
|
161
|
-
unit_node['symbol'] = self.unit_symbol.to_s unless self.unit_symbol.to_s.empty?
|
162
|
-
unit_node << self.unit_value.to_s unless self.unit_value.to_s.empty?
|
163
|
-
end
|
164
|
-
|
165
|
-
return datastream_node
|
166
|
-
end
|
167
|
-
end
|
168
|
-
|
169
|
-
end
|
data/lib/eeml/feed_retriever.rb
DELETED
@@ -1,103 +0,0 @@
|
|
1
|
-
require 'uri'
|
2
|
-
require 'net/http'
|
3
|
-
module Eeml
|
4
|
-
|
5
|
-
class FeedRetriever
|
6
|
-
|
7
|
-
DEFAULT_TIMEOUT = 5
|
8
|
-
PREMIUM_ENVIRONMENT_AGE = raise 3
|
9
|
-
|
10
|
-
attr_accessor :retrieval_errors #will hold an array of string error messages populated during feed retrieval. currently populated only in fetch_remote_data
|
11
|
-
attr_accessor :logger
|
12
|
-
attr_accessor :feed_url, :retrieved_at
|
13
|
-
attr_accessor :feed_changed, :feed_retrieved
|
14
|
-
attr_accessor :feed_content, :mime_type
|
15
|
-
|
16
|
-
def initialize
|
17
|
-
end
|
18
|
-
|
19
|
-
# only attempt to retrieve data if request is after our minimum time delta
|
20
|
-
#currently makes use of get_response() and fetch() to do actual retrieval.
|
21
|
-
def fetch_remote_data
|
22
|
-
@retrieval_errors = []
|
23
|
-
logger.debug("*** Attempting to fetch remote data")
|
24
|
-
|
25
|
-
# only attempt to retrieve data if this environment has a feed_url
|
26
|
-
if !self.feed_url.blank? && (self.retrieved_at.nil? || (Time.now.utc - self.retrieved_at.utc) > PREMIUM_ENVIRONMENT_AGE)
|
27
|
-
logger.debug("*** Our refresh delta has passed so retrieve remote data")
|
28
|
-
|
29
|
-
self.feed_changed = false
|
30
|
-
self.feed_retrieved = false
|
31
|
-
|
32
|
-
response = get_response
|
33
|
-
|
34
|
-
case response
|
35
|
-
when Net::HTTPSuccess
|
36
|
-
logger.debug("*** 200 ok... checking mime type #{response.content_type}.")
|
37
|
-
if MIME_TYPES.include?(response.content_type)
|
38
|
-
logger.debug("*** We have a valid mime type")
|
39
|
-
|
40
|
-
self.feed_content = response.body.to_s.strip
|
41
|
-
self.mime_type = response.content_type
|
42
|
-
|
43
|
-
self.retrieved_at = Time.now.utc.to_s(:db)
|
44
|
-
else
|
45
|
-
logger.debug("*** wrong mime-type.")
|
46
|
-
white_list = ['text/html', 'text/javascript', 'application/javascript'] # acceptably WRONG header values.
|
47
|
-
filtered_advice = ( white_list.member?(response.content_type) ? " Got '#{response.content_type}'." : "" )
|
48
|
-
@retrieval_errors << "Wrong mime-type. Need application/xml, text/csv, or variants." + filtered_advice
|
49
|
-
end
|
50
|
-
else
|
51
|
-
self.feed_retrieved = false
|
52
|
-
self.feed_changed = false
|
53
|
-
logger.debug("*** Unable to fetch remote data")
|
54
|
-
end
|
55
|
-
else
|
56
|
-
logger.debug("*** No feed url present or refresh delta not yet expired - don't do nothin")
|
57
|
-
# TODO remove after development
|
58
|
-
end
|
59
|
-
rescue URI::InvalidURIError, Timeout::Error, SystemCallError => e
|
60
|
-
self.feed_retrieved = false
|
61
|
-
self.feed_changed = false
|
62
|
-
@retrieval_errors << "Url bad or unavailable."
|
63
|
-
logger.error("*** Error retrieving feed from remote source: #{e}")
|
64
|
-
end
|
65
|
-
|
66
|
-
# private
|
67
|
-
|
68
|
-
# separating this method out makes mocking our response fairly simple
|
69
|
-
# basically we just create a dummy response object, and override this
|
70
|
-
# method with a stubbed version that returns our dummy response
|
71
|
-
def get_response
|
72
|
-
return fetch(feed_url)
|
73
|
-
end
|
74
|
-
|
75
|
-
# TODO: update test specs so this passes properly
|
76
|
-
# this fetch method recursively follows redirections up to a maximum depth of 10 redirections
|
77
|
-
def fetch(uri_str, limit = 10)
|
78
|
-
uri = create_uri(uri_str)
|
79
|
-
|
80
|
-
logger.debug("*** Fetching content from :#{uri}")
|
81
|
-
http_client = Net::HTTP.new(uri.host, uri.port)
|
82
|
-
|
83
|
-
# the default timeout appears to be 60 seconds. this is very long
|
84
|
-
# override it to be 5 seconds
|
85
|
-
http_client.open_timeout = DEFAULT_TIMEOUT
|
86
|
-
http_client.read_timeout = DEFAULT_TIMEOUT
|
87
|
-
response = http_client.request_get(uri.request_uri)
|
88
|
-
logger.debug("*** Got response: #{response}")
|
89
|
-
case response
|
90
|
-
when Net::HTTPSuccess then response
|
91
|
-
when Net::HTTPRedirection then fetch(response['location'], limit - 1)
|
92
|
-
else response
|
93
|
-
end
|
94
|
-
end
|
95
|
-
|
96
|
-
def create_uri(uri_str)
|
97
|
-
logger.debug("*** Creating uri from: #{uri_str}")
|
98
|
-
uri = URI.parse(uri_str)
|
99
|
-
raise URI::InvalidURIError unless uri.is_a?(URI::HTTP) or uri.is_a?(URI::HTTPS)
|
100
|
-
return uri
|
101
|
-
end
|
102
|
-
end
|
103
|
-
end
|