openstudio-analysis 1.3.6 → 1.3.7
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.
- checksums.yaml +4 -4
- data/.github/workflows/openstudio-analysis.yml +40 -40
- data/.gitignore +21 -21
- data/.rubocop.yml +9 -9
- data/CHANGELOG.md +274 -269
- data/Gemfile +14 -14
- data/README.md +102 -102
- data/Rakefile +40 -40
- data/lib/openstudio/analysis/algorithm_attributes.rb +47 -47
- data/lib/openstudio/analysis/formulation.rb +881 -857
- data/lib/openstudio/analysis/server_api.rb +862 -862
- data/lib/openstudio/analysis/server_scripts.rb +108 -108
- data/lib/openstudio/analysis/support_files.rb +104 -104
- data/lib/openstudio/analysis/translator/datapoints.rb +454 -454
- data/lib/openstudio/analysis/translator/excel.rb +893 -893
- data/lib/openstudio/analysis/translator/workflow.rb +143 -143
- data/lib/openstudio/analysis/version.rb +12 -12
- data/lib/openstudio/analysis/workflow.rb +302 -279
- data/lib/openstudio/analysis/workflow_step.rb +523 -523
- data/lib/openstudio/analysis.rb +144 -144
- data/lib/openstudio/helpers/hash.rb +10 -10
- data/lib/openstudio/helpers/string.rb +36 -36
- data/lib/openstudio/helpers/utils.rb +36 -36
- data/lib/openstudio/weather/epw.rb +178 -178
- data/lib/openstudio-analysis.rb +47 -47
- data/openstudio-analysis.gemspec +38 -38
- data/update_license.rb +60 -60
- metadata +2 -2
data/lib/openstudio/analysis.rb
CHANGED
@@ -1,144 +1,144 @@
|
|
1
|
-
# *******************************************************************************
|
2
|
-
# OpenStudio(R), Copyright (c) Alliance for Sustainable Energy, LLC.
|
3
|
-
# See also https://openstudio.net/license
|
4
|
-
# *******************************************************************************
|
5
|
-
|
6
|
-
# OpenStudio::Analysis Module instantiates versions of formulations
|
7
|
-
module OpenStudio
|
8
|
-
module Analysis
|
9
|
-
# Create a new analysis
|
10
|
-
def self.create(display_name)
|
11
|
-
OpenStudio::Analysis::Formulation.new(display_name)
|
12
|
-
end
|
13
|
-
|
14
|
-
# Load the analysis json or from a file. If this is a json then it must have
|
15
|
-
# symbolized keys
|
16
|
-
def self.load(h)
|
17
|
-
h = MultiJson.load(h, symbolize_keys: true) unless h.is_a? Hash
|
18
|
-
OpenStudio::Analysis::Formulation.from_hash h
|
19
|
-
end
|
20
|
-
|
21
|
-
# Load an analysis from excel. This will create an array of analyses because
|
22
|
-
# excel can create more than one analyses
|
23
|
-
def self.from_excel(filename)
|
24
|
-
excel = OpenStudio::Analysis::Translator::Excel.new(filename)
|
25
|
-
excel.process
|
26
|
-
excel.analyses
|
27
|
-
end
|
28
|
-
|
29
|
-
# Load an set of batch datapoints from a csv. This will create a analysis
|
30
|
-
# of type 'batch_datapoints' which requires 'batch_run'
|
31
|
-
def self.from_csv(filename)
|
32
|
-
csv = OpenStudio::Analysis::Translator::Datapoints.new(filename)
|
33
|
-
csv.process
|
34
|
-
csv.analysis
|
35
|
-
end
|
36
|
-
|
37
|
-
# Process an OSA with a set of OSDs into OSWs
|
38
|
-
def self.make_osws(osa_filename, osd_array)
|
39
|
-
translator = OpenStudio::Analysis::Translator::Workflow.new(osa_filename)
|
40
|
-
osd_array.each { |osd| translator.process_datapoints osd }
|
41
|
-
end
|
42
|
-
|
43
|
-
# Retrieve aws instance options from a project. This will return a hash
|
44
|
-
def self.aws_instance_options(filename)
|
45
|
-
if File.extname(filename) == '.xlsx'
|
46
|
-
excel = OpenStudio::Analysis::Translator::Excel.new(filename)
|
47
|
-
excel.process
|
48
|
-
options = {
|
49
|
-
os_server_version: excel.settings['openstudio_server_version'],
|
50
|
-
server_instance_type: excel.settings['server_instance_type'],
|
51
|
-
worker_instance_type: excel.settings['worker_instance_type'],
|
52
|
-
worker_node_number: excel.settings['worker_nodes'].to_i,
|
53
|
-
user_id: excel.settings['user_id'],
|
54
|
-
aws_tags: excel.aws_tags,
|
55
|
-
analysis_type: excel.analyses.first.analysis_type,
|
56
|
-
cluster_name: excel.cluster_name
|
57
|
-
}
|
58
|
-
elsif File.extname(filename) == '.csv'
|
59
|
-
csv = OpenStudio::Analysis::Translator::Datapoints.new(filename)
|
60
|
-
csv.process
|
61
|
-
options = csv.settings
|
62
|
-
else
|
63
|
-
raise 'Invalid file extension'
|
64
|
-
end
|
65
|
-
|
66
|
-
return options
|
67
|
-
end
|
68
|
-
|
69
|
-
# Generate a DEnCity complient hash for uploading from the analysis hash
|
70
|
-
# TODO make this work off of the analysis object, not the hash.
|
71
|
-
def self.to_dencity_analysis(analysis_hash, analysis_uuid)
|
72
|
-
dencity_hash = {}
|
73
|
-
a = analysis_hash[:analysis]
|
74
|
-
provenance = {}
|
75
|
-
provenance[:user_defined_id] = analysis_uuid
|
76
|
-
provenance[:user_created_date] = ::Time.now
|
77
|
-
provenance[:analysis_types] = [a[:problem][:analysis_type]]
|
78
|
-
provenance[:name] = a[:name]
|
79
|
-
provenance[:display_name] = a[:display_name]
|
80
|
-
provenance[:description] = 'Auto-generated DEnCity analysis hash using the OpenStudio Analysis Gem'
|
81
|
-
measure_metadata = []
|
82
|
-
if a[:problem]
|
83
|
-
if a[:problem][:algorithm]
|
84
|
-
provenance[:analysis_information] = a[:problem][:algorithm]
|
85
|
-
else
|
86
|
-
raise 'No algorithm found in the analysis.json.'
|
87
|
-
end
|
88
|
-
|
89
|
-
if a[:problem][:workflow]
|
90
|
-
a[:problem][:workflow].each do |wf|
|
91
|
-
new_wfi = {}
|
92
|
-
new_wfi[:id] = wf[:measure_definition_uuid]
|
93
|
-
new_wfi[:version_id] = wf[:measure_definition_version_uuid]
|
94
|
-
|
95
|
-
# Eventually all of this could be pulled directly from BCL
|
96
|
-
new_wfi[:name] = wf[:measure_definition_class_name] if wf[:measure_definition_class_name]
|
97
|
-
new_wfi[:display_name] = wf[:measure_definition_display_name] if wf[:measure_definition_display_name]
|
98
|
-
new_wfi[:type] = wf[:measure_type] if wf[:measure_type]
|
99
|
-
new_wfi[:modeler_description] = wf[:modeler_description] if wf[:modeler_description]
|
100
|
-
new_wfi[:description] = wf[:description] if wf[:description]
|
101
|
-
new_wfi[:arguments] = []
|
102
|
-
|
103
|
-
wf[:arguments]&.each do |arg|
|
104
|
-
wfi_arg = {}
|
105
|
-
wfi_arg[:display_name] = arg[:display_name] if arg[:display_name]
|
106
|
-
wfi_arg[:display_name_short] = arg[:display_name_short] if arg[:display_name_short]
|
107
|
-
wfi_arg[:name] = arg[:name] if arg[:name]
|
108
|
-
wfi_arg[:data_type] = arg[:value_type] if arg[:value_type]
|
109
|
-
wfi_arg[:default_value] = nil
|
110
|
-
wfi_arg[:description] = ''
|
111
|
-
wfi_arg[:display_units] = '' # should be haystack compatible unit strings
|
112
|
-
wfi_arg[:units] = '' # should be haystack compatible unit strings
|
113
|
-
|
114
|
-
new_wfi[:arguments] << wfi_arg
|
115
|
-
end
|
116
|
-
|
117
|
-
wf[:variables]&.each do |arg|
|
118
|
-
wfi_var = {}
|
119
|
-
wfi_var[:display_name] = arg[:argument][:display_name] if arg[:argument][:display_name]
|
120
|
-
wfi_var[:display_name_short] = arg[:argument][:display_name_short] if arg[:argument][:display_name_short]
|
121
|
-
wfi_var[:name] = arg[:argument][:name] if arg[:argument][:name]
|
122
|
-
wfi_var[:default_value] = nil
|
123
|
-
wfi_var[:data_type] = arg[:argument][:value_type] if arg[:argument][:value_type]
|
124
|
-
wfi_var[:description] = ''
|
125
|
-
wfi_var[:display_units] = arg[:units] if arg[:units]
|
126
|
-
wfi_var[:units] = '' # should be haystack compatible unit strings
|
127
|
-
new_wfi[:arguments] << wfi_var
|
128
|
-
end
|
129
|
-
|
130
|
-
measure_metadata << new_wfi
|
131
|
-
end
|
132
|
-
else
|
133
|
-
raise 'No workflow found in the analysis.json'
|
134
|
-
end
|
135
|
-
|
136
|
-
dencity_hash[:analysis] = provenance
|
137
|
-
dencity_hash[:measure_definitions] = measure_metadata
|
138
|
-
else
|
139
|
-
raise 'No problem found in the analysis.json'
|
140
|
-
end
|
141
|
-
return dencity_hash
|
142
|
-
end
|
143
|
-
end
|
144
|
-
end
|
1
|
+
# *******************************************************************************
|
2
|
+
# OpenStudio(R), Copyright (c) Alliance for Sustainable Energy, LLC.
|
3
|
+
# See also https://openstudio.net/license
|
4
|
+
# *******************************************************************************
|
5
|
+
|
6
|
+
# OpenStudio::Analysis Module instantiates versions of formulations
|
7
|
+
module OpenStudio
|
8
|
+
module Analysis
|
9
|
+
# Create a new analysis
|
10
|
+
def self.create(display_name)
|
11
|
+
OpenStudio::Analysis::Formulation.new(display_name)
|
12
|
+
end
|
13
|
+
|
14
|
+
# Load the analysis json or from a file. If this is a json then it must have
|
15
|
+
# symbolized keys
|
16
|
+
def self.load(h)
|
17
|
+
h = MultiJson.load(h, symbolize_keys: true) unless h.is_a? Hash
|
18
|
+
OpenStudio::Analysis::Formulation.from_hash h
|
19
|
+
end
|
20
|
+
|
21
|
+
# Load an analysis from excel. This will create an array of analyses because
|
22
|
+
# excel can create more than one analyses
|
23
|
+
def self.from_excel(filename)
|
24
|
+
excel = OpenStudio::Analysis::Translator::Excel.new(filename)
|
25
|
+
excel.process
|
26
|
+
excel.analyses
|
27
|
+
end
|
28
|
+
|
29
|
+
# Load an set of batch datapoints from a csv. This will create a analysis
|
30
|
+
# of type 'batch_datapoints' which requires 'batch_run'
|
31
|
+
def self.from_csv(filename)
|
32
|
+
csv = OpenStudio::Analysis::Translator::Datapoints.new(filename)
|
33
|
+
csv.process
|
34
|
+
csv.analysis
|
35
|
+
end
|
36
|
+
|
37
|
+
# Process an OSA with a set of OSDs into OSWs
|
38
|
+
def self.make_osws(osa_filename, osd_array)
|
39
|
+
translator = OpenStudio::Analysis::Translator::Workflow.new(osa_filename)
|
40
|
+
osd_array.each { |osd| translator.process_datapoints osd }
|
41
|
+
end
|
42
|
+
|
43
|
+
# Retrieve aws instance options from a project. This will return a hash
|
44
|
+
def self.aws_instance_options(filename)
|
45
|
+
if File.extname(filename) == '.xlsx'
|
46
|
+
excel = OpenStudio::Analysis::Translator::Excel.new(filename)
|
47
|
+
excel.process
|
48
|
+
options = {
|
49
|
+
os_server_version: excel.settings['openstudio_server_version'],
|
50
|
+
server_instance_type: excel.settings['server_instance_type'],
|
51
|
+
worker_instance_type: excel.settings['worker_instance_type'],
|
52
|
+
worker_node_number: excel.settings['worker_nodes'].to_i,
|
53
|
+
user_id: excel.settings['user_id'],
|
54
|
+
aws_tags: excel.aws_tags,
|
55
|
+
analysis_type: excel.analyses.first.analysis_type,
|
56
|
+
cluster_name: excel.cluster_name
|
57
|
+
}
|
58
|
+
elsif File.extname(filename) == '.csv'
|
59
|
+
csv = OpenStudio::Analysis::Translator::Datapoints.new(filename)
|
60
|
+
csv.process
|
61
|
+
options = csv.settings
|
62
|
+
else
|
63
|
+
raise 'Invalid file extension'
|
64
|
+
end
|
65
|
+
|
66
|
+
return options
|
67
|
+
end
|
68
|
+
|
69
|
+
# Generate a DEnCity complient hash for uploading from the analysis hash
|
70
|
+
# TODO make this work off of the analysis object, not the hash.
|
71
|
+
def self.to_dencity_analysis(analysis_hash, analysis_uuid)
|
72
|
+
dencity_hash = {}
|
73
|
+
a = analysis_hash[:analysis]
|
74
|
+
provenance = {}
|
75
|
+
provenance[:user_defined_id] = analysis_uuid
|
76
|
+
provenance[:user_created_date] = ::Time.now
|
77
|
+
provenance[:analysis_types] = [a[:problem][:analysis_type]]
|
78
|
+
provenance[:name] = a[:name]
|
79
|
+
provenance[:display_name] = a[:display_name]
|
80
|
+
provenance[:description] = 'Auto-generated DEnCity analysis hash using the OpenStudio Analysis Gem'
|
81
|
+
measure_metadata = []
|
82
|
+
if a[:problem]
|
83
|
+
if a[:problem][:algorithm]
|
84
|
+
provenance[:analysis_information] = a[:problem][:algorithm]
|
85
|
+
else
|
86
|
+
raise 'No algorithm found in the analysis.json.'
|
87
|
+
end
|
88
|
+
|
89
|
+
if a[:problem][:workflow]
|
90
|
+
a[:problem][:workflow].each do |wf|
|
91
|
+
new_wfi = {}
|
92
|
+
new_wfi[:id] = wf[:measure_definition_uuid]
|
93
|
+
new_wfi[:version_id] = wf[:measure_definition_version_uuid]
|
94
|
+
|
95
|
+
# Eventually all of this could be pulled directly from BCL
|
96
|
+
new_wfi[:name] = wf[:measure_definition_class_name] if wf[:measure_definition_class_name]
|
97
|
+
new_wfi[:display_name] = wf[:measure_definition_display_name] if wf[:measure_definition_display_name]
|
98
|
+
new_wfi[:type] = wf[:measure_type] if wf[:measure_type]
|
99
|
+
new_wfi[:modeler_description] = wf[:modeler_description] if wf[:modeler_description]
|
100
|
+
new_wfi[:description] = wf[:description] if wf[:description]
|
101
|
+
new_wfi[:arguments] = []
|
102
|
+
|
103
|
+
wf[:arguments]&.each do |arg|
|
104
|
+
wfi_arg = {}
|
105
|
+
wfi_arg[:display_name] = arg[:display_name] if arg[:display_name]
|
106
|
+
wfi_arg[:display_name_short] = arg[:display_name_short] if arg[:display_name_short]
|
107
|
+
wfi_arg[:name] = arg[:name] if arg[:name]
|
108
|
+
wfi_arg[:data_type] = arg[:value_type] if arg[:value_type]
|
109
|
+
wfi_arg[:default_value] = nil
|
110
|
+
wfi_arg[:description] = ''
|
111
|
+
wfi_arg[:display_units] = '' # should be haystack compatible unit strings
|
112
|
+
wfi_arg[:units] = '' # should be haystack compatible unit strings
|
113
|
+
|
114
|
+
new_wfi[:arguments] << wfi_arg
|
115
|
+
end
|
116
|
+
|
117
|
+
wf[:variables]&.each do |arg|
|
118
|
+
wfi_var = {}
|
119
|
+
wfi_var[:display_name] = arg[:argument][:display_name] if arg[:argument][:display_name]
|
120
|
+
wfi_var[:display_name_short] = arg[:argument][:display_name_short] if arg[:argument][:display_name_short]
|
121
|
+
wfi_var[:name] = arg[:argument][:name] if arg[:argument][:name]
|
122
|
+
wfi_var[:default_value] = nil
|
123
|
+
wfi_var[:data_type] = arg[:argument][:value_type] if arg[:argument][:value_type]
|
124
|
+
wfi_var[:description] = ''
|
125
|
+
wfi_var[:display_units] = arg[:units] if arg[:units]
|
126
|
+
wfi_var[:units] = '' # should be haystack compatible unit strings
|
127
|
+
new_wfi[:arguments] << wfi_var
|
128
|
+
end
|
129
|
+
|
130
|
+
measure_metadata << new_wfi
|
131
|
+
end
|
132
|
+
else
|
133
|
+
raise 'No workflow found in the analysis.json'
|
134
|
+
end
|
135
|
+
|
136
|
+
dencity_hash[:analysis] = provenance
|
137
|
+
dencity_hash[:measure_definitions] = measure_metadata
|
138
|
+
else
|
139
|
+
raise 'No problem found in the analysis.json'
|
140
|
+
end
|
141
|
+
return dencity_hash
|
142
|
+
end
|
143
|
+
end
|
144
|
+
end
|
@@ -1,10 +1,10 @@
|
|
1
|
-
# *******************************************************************************
|
2
|
-
# OpenStudio(R), Copyright (c) Alliance for Sustainable Energy, LLC.
|
3
|
-
# See also https://openstudio.net/license
|
4
|
-
# *******************************************************************************
|
5
|
-
|
6
|
-
class Hash
|
7
|
-
def deep_find(key)
|
8
|
-
key?(key) ? self[key] : values.reduce(nil) { |memo, v| memo ||= v.deep_find(key) if v.respond_to?(:deep_find) }
|
9
|
-
end
|
10
|
-
end
|
1
|
+
# *******************************************************************************
|
2
|
+
# OpenStudio(R), Copyright (c) Alliance for Sustainable Energy, LLC.
|
3
|
+
# See also https://openstudio.net/license
|
4
|
+
# *******************************************************************************
|
5
|
+
|
6
|
+
class Hash
|
7
|
+
def deep_find(key)
|
8
|
+
key?(key) ? self[key] : values.reduce(nil) { |memo, v| memo ||= v.deep_find(key) if v.respond_to?(:deep_find) }
|
9
|
+
end
|
10
|
+
end
|
@@ -1,36 +1,36 @@
|
|
1
|
-
# *******************************************************************************
|
2
|
-
# OpenStudio(R), Copyright (c) Alliance for Sustainable Energy, LLC.
|
3
|
-
# See also https://openstudio.net/license
|
4
|
-
# *******************************************************************************
|
5
|
-
|
6
|
-
# Typecast Variable Values by a string.
|
7
|
-
def typecast_value(variable_type, value, inspect_string = false)
|
8
|
-
out_value = nil
|
9
|
-
unless value.nil?
|
10
|
-
case variable_type.downcase
|
11
|
-
when 'double'
|
12
|
-
out_value = value.to_f
|
13
|
-
when 'integer'
|
14
|
-
out_value = value.to_i
|
15
|
-
when 'string', 'choice'
|
16
|
-
out_value = inspect_string ? value.inspect : value.to_s
|
17
|
-
when 'bool', 'boolean'
|
18
|
-
# Check if the value is already a boolean
|
19
|
-
if !!value == value
|
20
|
-
out_value = value
|
21
|
-
else
|
22
|
-
if value.casecmp('true').zero?
|
23
|
-
out_value = true
|
24
|
-
elsif value.casecmp('false').zero?
|
25
|
-
out_value = false
|
26
|
-
else
|
27
|
-
raise "Can't cast to a bool from a value of '#{value}' of class '#{value.class}'"
|
28
|
-
end
|
29
|
-
end
|
30
|
-
else
|
31
|
-
raise "Unknown variable type of '#{@variable['type']}'"
|
32
|
-
end
|
33
|
-
end
|
34
|
-
|
35
|
-
out_value
|
36
|
-
end
|
1
|
+
# *******************************************************************************
|
2
|
+
# OpenStudio(R), Copyright (c) Alliance for Sustainable Energy, LLC.
|
3
|
+
# See also https://openstudio.net/license
|
4
|
+
# *******************************************************************************
|
5
|
+
|
6
|
+
# Typecast Variable Values by a string.
|
7
|
+
def typecast_value(variable_type, value, inspect_string = false)
|
8
|
+
out_value = nil
|
9
|
+
unless value.nil?
|
10
|
+
case variable_type.downcase
|
11
|
+
when 'double'
|
12
|
+
out_value = value.to_f
|
13
|
+
when 'integer'
|
14
|
+
out_value = value.to_i
|
15
|
+
when 'string', 'choice'
|
16
|
+
out_value = inspect_string ? value.inspect : value.to_s
|
17
|
+
when 'bool', 'boolean'
|
18
|
+
# Check if the value is already a boolean
|
19
|
+
if !!value == value
|
20
|
+
out_value = value
|
21
|
+
else
|
22
|
+
if value.casecmp('true').zero?
|
23
|
+
out_value = true
|
24
|
+
elsif value.casecmp('false').zero?
|
25
|
+
out_value = false
|
26
|
+
else
|
27
|
+
raise "Can't cast to a bool from a value of '#{value}' of class '#{value.class}'"
|
28
|
+
end
|
29
|
+
end
|
30
|
+
else
|
31
|
+
raise "Unknown variable type of '#{@variable['type']}'"
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
out_value
|
36
|
+
end
|
@@ -1,36 +1,36 @@
|
|
1
|
-
# *******************************************************************************
|
2
|
-
# OpenStudio(R), Copyright (c) Alliance for Sustainable Energy, LLC.
|
3
|
-
# See also https://openstudio.net/license
|
4
|
-
# *******************************************************************************
|
5
|
-
|
6
|
-
require 'rexml/document'
|
7
|
-
|
8
|
-
def parse_measure_xml(measure_xml_filename)
|
9
|
-
measure_hash = {}
|
10
|
-
xml_to_parse = File.open(measure_xml_filename)
|
11
|
-
xml_root = REXML::Document.new(xml_to_parse).root
|
12
|
-
|
13
|
-
# pull out some information
|
14
|
-
measure_hash[:classname] = xml_root.elements['//measure/class_name'].text
|
15
|
-
measure_hash[:name] = xml_root.elements['//measure/name'].text
|
16
|
-
measure_hash[:display_name] = xml_root.elements['//measure/display_name'].text
|
17
|
-
measure_hash[:display_name_titleized] = measure_hash[:name].titleize
|
18
|
-
measure_hash[:measure_type] = xml_root.elements['//measure/attributes/attribute[name="Measure Type"]/value'].text
|
19
|
-
measure_hash[:description] = xml_root.elements['//measure/description'].text
|
20
|
-
measure_hash[:modeler_description] = xml_root.elements['//measure/modeler_description'].text
|
21
|
-
measure_hash[:uid] = xml_root.elements['//measure/uid'].text
|
22
|
-
measure_hash[:version_id] = xml_root.elements['//measure/version_id'].text
|
23
|
-
measure_hash[:arguments] = []
|
24
|
-
|
25
|
-
REXML::XPath.each(xml_root, '//measure/arguments/argument') do |arg|
|
26
|
-
measure_hash[:arguments] << {
|
27
|
-
name: arg.elements['name']&.text,
|
28
|
-
display_name: arg.elements['display_name']&.text,
|
29
|
-
variable_type: arg.elements['type']&.text.downcase,
|
30
|
-
default_value: arg.elements['default_value']&.text,
|
31
|
-
units: arg.elements['units']&.text || ''
|
32
|
-
}
|
33
|
-
end
|
34
|
-
|
35
|
-
measure_hash
|
36
|
-
end
|
1
|
+
# *******************************************************************************
|
2
|
+
# OpenStudio(R), Copyright (c) Alliance for Sustainable Energy, LLC.
|
3
|
+
# See also https://openstudio.net/license
|
4
|
+
# *******************************************************************************
|
5
|
+
|
6
|
+
require 'rexml/document'
|
7
|
+
|
8
|
+
def parse_measure_xml(measure_xml_filename)
|
9
|
+
measure_hash = {}
|
10
|
+
xml_to_parse = File.open(measure_xml_filename)
|
11
|
+
xml_root = REXML::Document.new(xml_to_parse).root
|
12
|
+
|
13
|
+
# pull out some information
|
14
|
+
measure_hash[:classname] = xml_root.elements['//measure/class_name'].text
|
15
|
+
measure_hash[:name] = xml_root.elements['//measure/name'].text
|
16
|
+
measure_hash[:display_name] = xml_root.elements['//measure/display_name'].text
|
17
|
+
measure_hash[:display_name_titleized] = measure_hash[:name].titleize
|
18
|
+
measure_hash[:measure_type] = xml_root.elements['//measure/attributes/attribute[name="Measure Type"]/value'].text
|
19
|
+
measure_hash[:description] = xml_root.elements['//measure/description'].text
|
20
|
+
measure_hash[:modeler_description] = xml_root.elements['//measure/modeler_description'].text
|
21
|
+
measure_hash[:uid] = xml_root.elements['//measure/uid'].text
|
22
|
+
measure_hash[:version_id] = xml_root.elements['//measure/version_id'].text
|
23
|
+
measure_hash[:arguments] = []
|
24
|
+
|
25
|
+
REXML::XPath.each(xml_root, '//measure/arguments/argument') do |arg|
|
26
|
+
measure_hash[:arguments] << {
|
27
|
+
name: arg.elements['name']&.text,
|
28
|
+
display_name: arg.elements['display_name']&.text,
|
29
|
+
variable_type: arg.elements['type']&.text.downcase,
|
30
|
+
default_value: arg.elements['default_value']&.text,
|
31
|
+
units: arg.elements['units']&.text || ''
|
32
|
+
}
|
33
|
+
end
|
34
|
+
|
35
|
+
measure_hash
|
36
|
+
end
|