eeml 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +0 -0
- data/LICENSE +25 -0
- data/Manifest +30 -0
- data/README +8 -0
- data/Rakefile +25 -0
- data/eeml.gemspec +46 -0
- data/example.rb +33 -0
- data/lib/blank.rb +50 -0
- data/lib/eeml/constants.rb +17 -0
- data/lib/eeml/csv_parser.rb +16 -0
- data/lib/eeml/environment.rb +113 -0
- data/lib/eeml/exceptions.rb +59 -0
- data/lib/eeml/feed_output.rb +169 -0
- data/lib/eeml/feed_retriever.rb +103 -0
- data/lib/eeml/json_environment_parser.rb +11 -0
- data/lib/eeml/libxml_eeml_output_v005.rb +120 -0
- data/lib/eeml/libxml_eeml_parser_v005.rb +179 -0
- data/lib/eeml/output_registry.rb +13 -0
- data/lib/eeml/parser_registry.rb +14 -0
- data/lib/eeml.rb +35 -0
- data/schemas/eeml/005.xsd +134 -0
- data/test/data/doc_1.json +2 -0
- data/test/data/doc_1.xml +32 -0
- data/test/data/minimal.xml +9 -0
- data/test/data/out_empty.xml +4 -0
- data/test/libxml_test_helper.rb +39 -0
- data/test/test_environment.rb +370 -0
- data/test/test_helper.rb +56 -0
- data/test/test_libxml_eeml_parser_v005.rb +9 -0
- data/test/test_libxml_test_helper.rb +85 -0
- data.tar.gz.sig +1 -0
- metadata +177 -0
- metadata.gz.sig +3 -0
data/CHANGELOG
ADDED
File without changes
|
data/LICENSE
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
Copyright (c) 2009, Neill Bogie, Samuel Mulube.
|
2
|
+
All rights reserved.
|
3
|
+
|
4
|
+
Redistribution and use in source and binary forms, with or without modification,
|
5
|
+
are permitted provided that the following conditions are met:
|
6
|
+
|
7
|
+
* Redistributions of source code must retain the above copyright notice, this
|
8
|
+
list of conditions and the following disclaimer.
|
9
|
+
* Redistributions in binary form must reproduce the above copyright notice,
|
10
|
+
this list of conditions and the following disclaimer in the documentation
|
11
|
+
and/or other materials provided with the distribution.
|
12
|
+
* Neither the name of the <ORGANIZATION> nor the names of its contributors
|
13
|
+
may be used to endorse or promote products derived from this software without
|
14
|
+
specific prior written permission.
|
15
|
+
|
16
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
17
|
+
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
18
|
+
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
19
|
+
IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
20
|
+
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
21
|
+
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
22
|
+
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
23
|
+
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
|
24
|
+
OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
25
|
+
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
data/Manifest
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
example.rb
|
2
|
+
eeml.gemspec
|
3
|
+
LICENSE
|
4
|
+
CHANGELOG
|
5
|
+
README
|
6
|
+
test/test_environment.rb
|
7
|
+
test/test_libxml_test_helper.rb
|
8
|
+
test/libxml_test_helper.rb
|
9
|
+
test/test_libxml_eeml_parser_v005.rb
|
10
|
+
test/test_helper.rb
|
11
|
+
test/data/minimal.xml
|
12
|
+
test/data/out_empty.xml
|
13
|
+
test/data/doc_1.xml
|
14
|
+
test/data/doc_1.json
|
15
|
+
lib/eeml.rb
|
16
|
+
lib/eeml/constants.rb
|
17
|
+
lib/eeml/feed_retriever.rb
|
18
|
+
lib/eeml/json_environment_parser.rb
|
19
|
+
lib/eeml/output_registry.rb
|
20
|
+
lib/eeml/parser_registry.rb
|
21
|
+
lib/eeml/libxml_eeml_output_v005.rb
|
22
|
+
lib/eeml/feed_output.rb
|
23
|
+
lib/eeml/libxml_eeml_parser_v005.rb
|
24
|
+
lib/eeml/exceptions.rb
|
25
|
+
lib/eeml/csv_parser.rb
|
26
|
+
lib/eeml/environment.rb
|
27
|
+
lib/blank.rb
|
28
|
+
schemas/eeml/005.xsd
|
29
|
+
Rakefile
|
30
|
+
Manifest
|
data/README
ADDED
data/Rakefile
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'echoe'
|
2
|
+
|
3
|
+
$:.unshift(File.join(File.dirname(__FILE__), "lib"))
|
4
|
+
|
5
|
+
require 'eeml'
|
6
|
+
|
7
|
+
Echoe.new("eeml") do |p|
|
8
|
+
p.author = "Neill Bogie, Sam Mulube"
|
9
|
+
p.email = "sam.mulube@gmail.com"
|
10
|
+
p.description = "Simple little library for programmatically manipulating EEML documents, in particular this library is designed to work with the Pachube web service."
|
11
|
+
p.summary = "Simple little library for programmatically manipulating EEML documents."
|
12
|
+
p.version = Eeml::VERSION
|
13
|
+
p.runtime_dependencies = [
|
14
|
+
"libxml-ruby >= 1.1.3",
|
15
|
+
"json >= 1.1.3"
|
16
|
+
]
|
17
|
+
p.development_dependencies = [
|
18
|
+
"rake >= 0.8.4",
|
19
|
+
"mocha >= 0.9.6"
|
20
|
+
]
|
21
|
+
p.ignore_pattern = [
|
22
|
+
"test/data/real_xmls/v005/oks/*",
|
23
|
+
"test/data/real_xmls/v005/*"
|
24
|
+
]
|
25
|
+
end
|
data/eeml.gemspec
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
|
3
|
+
Gem::Specification.new do |s|
|
4
|
+
s.name = %q{eeml}
|
5
|
+
s.version = "0.0.1"
|
6
|
+
|
7
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 1.2") if s.respond_to? :required_rubygems_version=
|
8
|
+
s.authors = ["Neill Bogie, Sam Mulube"]
|
9
|
+
s.cert_chain = ["/home/sam/.gem/gem-public_cert.pem"]
|
10
|
+
s.date = %q{2009-04-17}
|
11
|
+
s.description = %q{Simple little library for programmatically manipulating EEML documents, in particular this library is designed to work with the Pachube web service.}
|
12
|
+
s.email = %q{sam.mulube@gmail.com}
|
13
|
+
s.extra_rdoc_files = ["LICENSE", "CHANGELOG", "README", "lib/eeml.rb", "lib/eeml/constants.rb", "lib/eeml/feed_retriever.rb", "lib/eeml/json_environment_parser.rb", "lib/eeml/output_registry.rb", "lib/eeml/parser_registry.rb", "lib/eeml/libxml_eeml_output_v005.rb", "lib/eeml/feed_output.rb", "lib/eeml/libxml_eeml_parser_v005.rb", "lib/eeml/exceptions.rb", "lib/eeml/csv_parser.rb", "lib/eeml/environment.rb", "lib/blank.rb"]
|
14
|
+
s.files = ["example.rb", "eeml.gemspec", "LICENSE", "CHANGELOG", "README", "test/test_environment.rb", "test/test_libxml_test_helper.rb", "test/libxml_test_helper.rb", "test/test_libxml_eeml_parser_v005.rb", "test/test_helper.rb", "test/data/minimal.xml", "test/data/out_empty.xml", "test/data/doc_1.xml", "test/data/doc_1.json", "lib/eeml.rb", "lib/eeml/constants.rb", "lib/eeml/feed_retriever.rb", "lib/eeml/json_environment_parser.rb", "lib/eeml/output_registry.rb", "lib/eeml/parser_registry.rb", "lib/eeml/libxml_eeml_output_v005.rb", "lib/eeml/feed_output.rb", "lib/eeml/libxml_eeml_parser_v005.rb", "lib/eeml/exceptions.rb", "lib/eeml/csv_parser.rb", "lib/eeml/environment.rb", "lib/blank.rb", "schemas/eeml/005.xsd", "Rakefile", "Manifest"]
|
15
|
+
s.has_rdoc = true
|
16
|
+
s.homepage = %q{}
|
17
|
+
s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Eeml", "--main", "README"]
|
18
|
+
s.require_paths = ["lib"]
|
19
|
+
s.rubyforge_project = %q{eeml}
|
20
|
+
s.rubygems_version = %q{1.3.1}
|
21
|
+
s.signing_key = %q{/home/sam/.gem/gem-private_key.pem}
|
22
|
+
s.summary = %q{Simple little library for programmatically manipulating EEML documents.}
|
23
|
+
s.test_files = ["test/test_environment.rb", "test/test_libxml_test_helper.rb", "test/test_libxml_eeml_parser_v005.rb", "test/test_helper.rb"]
|
24
|
+
|
25
|
+
if s.respond_to? :specification_version then
|
26
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
27
|
+
s.specification_version = 2
|
28
|
+
|
29
|
+
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
30
|
+
s.add_runtime_dependency(%q<libxml-ruby>, [">= 0", "= 1.1.3"])
|
31
|
+
s.add_runtime_dependency(%q<json>, [">= 0", "= 1.1.3"])
|
32
|
+
s.add_development_dependency(%q<rake>, [">= 0", "= 0.8.4"])
|
33
|
+
s.add_development_dependency(%q<mocha>, [">= 0", "= 0.9.6"])
|
34
|
+
else
|
35
|
+
s.add_dependency(%q<libxml-ruby>, [">= 0", "= 1.1.3"])
|
36
|
+
s.add_dependency(%q<json>, [">= 0", "= 1.1.3"])
|
37
|
+
s.add_dependency(%q<rake>, [">= 0", "= 0.8.4"])
|
38
|
+
s.add_dependency(%q<mocha>, [">= 0", "= 0.9.6"])
|
39
|
+
end
|
40
|
+
else
|
41
|
+
s.add_dependency(%q<libxml-ruby>, [">= 0", "= 1.1.3"])
|
42
|
+
s.add_dependency(%q<json>, [">= 0", "= 1.1.3"])
|
43
|
+
s.add_dependency(%q<rake>, [">= 0", "= 0.8.4"])
|
44
|
+
s.add_dependency(%q<mocha>, [">= 0", "= 0.9.6"])
|
45
|
+
end
|
46
|
+
end
|
data/example.rb
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
#should invoke this with (e.g.) ruby -Ilib example.rb in order to add lib/ to your search path
|
4
|
+
|
5
|
+
require 'rubygems' #only if your libxml is installed under rubygems
|
6
|
+
require 'eeml'
|
7
|
+
|
8
|
+
include Eeml #allows you to refer to Environment rather than Eeml::Environment
|
9
|
+
|
10
|
+
#Example: make an environment from scratch
|
11
|
+
env = Environment.new(:creator => 'http://www.example.com/ourstudio/', :feed_url => 'http://www.example.com/ourstudio/feeds/house.xml')
|
12
|
+
|
13
|
+
env.title = 'my example feed'
|
14
|
+
env.datastreams << DataStream.new(:value => 93.0, :identifier => 'room.1.humidity')
|
15
|
+
env.datastreams << DataStream.new(:value => 91.0, :identifier => 'room.2.humidity')
|
16
|
+
|
17
|
+
#print out its eeml representation
|
18
|
+
puts env.to_eeml
|
19
|
+
|
20
|
+
|
21
|
+
#Example: parse an environment from an eeml doc:
|
22
|
+
eeml_str = File.read('test/data/doc_1.xml')
|
23
|
+
env2 = Environment.new_from_eeml(eeml_str)
|
24
|
+
env2.datastreams.each do |ds|
|
25
|
+
puts "ds %8s value is %6s (min:%8s, max:%8s)" %[ds.identifier, ds.value, ds.min_value, ds.max_value]
|
26
|
+
end
|
27
|
+
|
28
|
+
#TODO: Example: http-fetch an environment
|
29
|
+
|
30
|
+
#TODO: Example: publish an environment to pachube
|
31
|
+
|
32
|
+
#TODO: Example: configure a different logger (to file; to stderr; different timestamp / format; use an existing rails logger)
|
33
|
+
|
data/lib/blank.rb
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
class Object
|
2
|
+
# An object is blank if it's nil, empty, or a whitespace string.
|
3
|
+
# For example, "", " ", nil, [], and {} are blank.
|
4
|
+
#
|
5
|
+
# This simplifies
|
6
|
+
# if !address.nil? && !address.empty?
|
7
|
+
# to
|
8
|
+
# if !address.blank?
|
9
|
+
def blank?
|
10
|
+
respond_to?(:empty?) ? empty? : !self
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
class NilClass #:nodoc:
|
15
|
+
def blank?
|
16
|
+
true
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
class FalseClass #:nodoc:
|
21
|
+
def blank?
|
22
|
+
true
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
class TrueClass #:nodoc:
|
27
|
+
def blank?
|
28
|
+
false
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
class Array #:nodoc:
|
33
|
+
alias_method :blank?, :empty?
|
34
|
+
end
|
35
|
+
|
36
|
+
class Hash #:nodoc:
|
37
|
+
alias_method :blank?, :empty?
|
38
|
+
end
|
39
|
+
|
40
|
+
class String #:nodoc:
|
41
|
+
def blank?
|
42
|
+
self !~ /\S/
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
class Numeric #:nodoc:
|
47
|
+
def blank?
|
48
|
+
false
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Eeml
|
2
|
+
module Constants
|
3
|
+
#LOCAL_EEML_SCHEMA_LOCATION = "schemas/eeml/005.xsd"
|
4
|
+
EEML_HREF = "http://www.eeml.org/xsd/005"
|
5
|
+
EEML_VERSION = "5"
|
6
|
+
EEML_SCHEMA_LOCATION = "http://www.eeml.org/xsd/005 http://www.eeml.org/xsd/005/005.xsd"
|
7
|
+
|
8
|
+
EEML_NAMESPACE = ":#{EEML_HREF}"
|
9
|
+
XSI_NAMESPACE = "http://www.w3.org/2001/XMLSchema-instance"
|
10
|
+
|
11
|
+
#TODO: better encapsulated as a set of methods.
|
12
|
+
XML_TIME_FORMAT_STRING = "%Y-%m-%dT%H:%M:%SZ"
|
13
|
+
|
14
|
+
DEFAULT_HOST = 'pachube.com'
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module Eeml
|
2
|
+
class CsvParser
|
3
|
+
|
4
|
+
#update the datastreams for the given environment, using the content in the given csv string.
|
5
|
+
def update_datastreams_from_csv(csv_content, environment)
|
6
|
+
# split values at commas
|
7
|
+
datastream_values = csv_content.split(/,/)
|
8
|
+
|
9
|
+
# now strip any whitespace
|
10
|
+
datastream_values.map! { |d| d.strip }
|
11
|
+
|
12
|
+
logger.debug("*** New datastream values: #{datastream_values}")
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,113 @@
|
|
1
|
+
module Eeml
|
2
|
+
include Eeml::Constants
|
3
|
+
|
4
|
+
class Location
|
5
|
+
attr_accessor :name, :latitude, :longitude, :elevation
|
6
|
+
attr_accessor :domain, :exposure, :disposition
|
7
|
+
end
|
8
|
+
|
9
|
+
class DataStream
|
10
|
+
# include FeedOutput::DataStreamNode
|
11
|
+
attr_accessor :identifier, :value, :tags, :min_value, :max_value, :unit_symbol, :unit_type, :unit_value
|
12
|
+
|
13
|
+
def initialize(options = {})
|
14
|
+
@identifier = options[:identifier]
|
15
|
+
@value = options[:value]
|
16
|
+
@max_value = options[:max_value]
|
17
|
+
@min_value = options[:min_value]
|
18
|
+
@tags = []
|
19
|
+
@unit_symbol = options[:unit_symbol]
|
20
|
+
@unit_type = options[:unit_type]
|
21
|
+
@unit_value = options[:unit_value]
|
22
|
+
end
|
23
|
+
|
24
|
+
def to_s
|
25
|
+
"identifier: '#{@identifier}', value: '#{@value}', min_value: '#{@min_value}', max_value: '#{@max_value}', tags: '#{@tags.join(", ")}'"
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
|
30
|
+
class Environment
|
31
|
+
include FeedOutput::EnvironmentNode
|
32
|
+
attr_accessor :identifier, :updated, :creator
|
33
|
+
attr_accessor :title, :description, :feed_url, :website, :email, :icon, :status
|
34
|
+
attr_accessor :location
|
35
|
+
attr_accessor :datastreams
|
36
|
+
|
37
|
+
# stuff so far needed only for FeedOutput module
|
38
|
+
# attr_accessor :retrieved_at
|
39
|
+
|
40
|
+
@@logger = nil
|
41
|
+
def self.logger=(logger)
|
42
|
+
@@logger = logger
|
43
|
+
end
|
44
|
+
|
45
|
+
def logger
|
46
|
+
return @@logger
|
47
|
+
end
|
48
|
+
|
49
|
+
def initialize(options = {})
|
50
|
+
@datastreams = []
|
51
|
+
@identifier = options[:identifier]
|
52
|
+
@creator = options[:creator]
|
53
|
+
@title = options[:title]
|
54
|
+
@status = options[:status]
|
55
|
+
@feed_url = options[:feed_url]
|
56
|
+
end
|
57
|
+
|
58
|
+
def add_datastream(datastream)
|
59
|
+
#TODO: consider checking for unique identifier
|
60
|
+
datastreams << datastream
|
61
|
+
end
|
62
|
+
|
63
|
+
def remove_last_datastream
|
64
|
+
datastreams.pop
|
65
|
+
end
|
66
|
+
|
67
|
+
def self.new_from_eeml(xml_str)
|
68
|
+
parser = ParserRegistry.get_xml_parser_for(xml_str)
|
69
|
+
return parser.make_environment_from_xml(xml_str)
|
70
|
+
end
|
71
|
+
|
72
|
+
def self.new_from_json(json_str)
|
73
|
+
parser = ParserRegistry.get_json_parser_for(json_str)
|
74
|
+
return parser.make_environment_from_json(json_str)
|
75
|
+
end
|
76
|
+
|
77
|
+
def update_datastreams_from_csv_values!(csv_values)
|
78
|
+
|
79
|
+
csv_values.each_with_index do |new_val, index|
|
80
|
+
datastream = datastreams[index]
|
81
|
+
#if we don't have an existing datastream at same index, create new one
|
82
|
+
if datastream.nil?
|
83
|
+
self.datastreams << DataStream.new(:identifier => index, :value => new_val, :ordering => index)
|
84
|
+
else
|
85
|
+
#we had a match, so update the existing datastream
|
86
|
+
datastream.value = new_val
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
# if the csv specifies FEWER feeds than the env currently has.
|
91
|
+
if csv_values.size < self.datastreams.size
|
92
|
+
# remove the excess from the end of the env's list.
|
93
|
+
num_extra = datastreams.size - csv_values.size
|
94
|
+
1.upto(num_extra) { remove_last_datastream }
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
#--------------------------------------------------------------------------
|
99
|
+
#----- state tracking stuff -----------------------------------------------
|
100
|
+
#--------------------------------------------------------------------------
|
101
|
+
def live?
|
102
|
+
#TODO
|
103
|
+
true
|
104
|
+
end
|
105
|
+
|
106
|
+
def to_eeml(version = Constants::EEML_VERSION)
|
107
|
+
outputter = OutputRegistry.get_xml_output_for(version)
|
108
|
+
outputter.to_eeml(self)
|
109
|
+
end
|
110
|
+
|
111
|
+
end
|
112
|
+
|
113
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
module Eeml
|
2
|
+
# exceptions
|
3
|
+
#TODO: have these inherit from a base parser error
|
4
|
+
class Unavailable < StandardError; end
|
5
|
+
class BadResponse < StandardError; end
|
6
|
+
class ApiKeyMissing < StandardError; end
|
7
|
+
class AuthenticationFailure < StandardError; end
|
8
|
+
|
9
|
+
class BadEeml < StandardError #eeml being parsed was ok xml but bad eeml
|
10
|
+
attr_accessor :line_num, :node_name #no guarantees either is available
|
11
|
+
def to_s
|
12
|
+
extras = []
|
13
|
+
extras << " node name: '" + node_name + "'" if node_name
|
14
|
+
extras << " line_num: #{line_num}" if line_num
|
15
|
+
super.to_s + extras.join(',')
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
class BadXML < StandardError; end #xml being parsed was malformed
|
20
|
+
class DataMissingValue < BadEeml; end
|
21
|
+
class DataHasMultipleUnits < BadEeml; end
|
22
|
+
class DataHasMultipleValues < BadEeml; end
|
23
|
+
class NoDataStreams < BadEeml; end
|
24
|
+
|
25
|
+
|
26
|
+
#A structured exception which holds info about what was missing and from where.
|
27
|
+
#Note: Some reasons we don't just hold everything in an unstructured exception message:
|
28
|
+
#1. some bits might be useful for dev but not for the public,
|
29
|
+
#2. testing is simplified by having the missing node name recorded explicitly (rather than in a human-readable, changeable string).
|
30
|
+
class MissingNode < BadEeml
|
31
|
+
attr_accessor :base_node_name, :sought_description, :sought_xpath
|
32
|
+
|
33
|
+
def initialize(base_node_name, sought_description, sought_xpath = nil)
|
34
|
+
@base_node_name = base_node_name
|
35
|
+
@sought_description = sought_description
|
36
|
+
@sought_xpath = sought_xpath
|
37
|
+
end
|
38
|
+
|
39
|
+
def to_s
|
40
|
+
"Missing '#@sought_description' node from base node: '#@base_node_name'" +
|
41
|
+
(@sought_xpath ? "with xpath: '#@sought_xpath'" : "")
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
|
46
|
+
class MissingAttribute < BadEeml
|
47
|
+
attr_accessor :node_name, :attribute_name
|
48
|
+
|
49
|
+
def initialize(node_name, attribute_name)
|
50
|
+
@node_name = node_name
|
51
|
+
@attribute_name = attribute_name
|
52
|
+
end
|
53
|
+
|
54
|
+
def to_s
|
55
|
+
"Missing attribute '#@attribute_name' from node '#@node_name'"
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
@@ -0,0 +1,169 @@
|
|
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
|