bcl 0.6.0 → 0.6.1
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/.rubocop.yml +1 -2
- data/CHANGELOG.md +6 -0
- data/Rakefile +1 -1
- data/lib/bcl.rb +0 -2
- data/lib/bcl/component.rb +1 -1
- data/lib/bcl/component_from_spreadsheet.rb +6 -8
- data/lib/bcl/component_methods.rb +8 -8
- data/lib/bcl/version.rb +1 -1
- metadata +2 -4
- data/lib/bcl/component_spreadsheet.rb +0 -287
- data/lib/bcl/master_taxonomy.rb +0 -528
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 889eac96a388f104d76ee80dc7406ec047b535e106498425418d7e121b94416d
|
4
|
+
data.tar.gz: ae5eba1617aabbe3245975a03d0733afccb5381182071e4a146780b26ad77196
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 71b0d4004fc2a0dfc20fff6e912adf194262bba8c2b6ba517d264d6700744c25142a036220131de1f19636e8c5fd4702d55a5fd641b8877843aa124178101c68
|
7
|
+
data.tar.gz: 4e4e7e94b3851f5a5be2a6dfbcd32c929149ce6e8c5251cfeef143d30546073d093f996d32af4b5949bae48523c87ea1f91b701f9eebf4b8af1e109408d31300
|
data/.rubocop.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,11 @@
|
|
1
1
|
# Change Log
|
2
2
|
|
3
|
+
## Version 0.6.1
|
4
|
+
|
5
|
+
* Remove dependency for winole (`require 'win32ole'`). This affects the reading of the component spreadsheets and the
|
6
|
+
the master taxomony.
|
7
|
+
* Use new rubocop (v3) from s3 openstudio-resources
|
8
|
+
|
3
9
|
## Version 0.6.0
|
4
10
|
|
5
11
|
* Support Ruby > 2.5
|
data/Rakefile
CHANGED
@@ -250,7 +250,7 @@ namespace :bcl do
|
|
250
250
|
|
251
251
|
paths << file.to_s
|
252
252
|
if file.to_s =~ /^.{0,2}component.xml$/ || file.to_s =~ /^.{0,2}measure.xml$/
|
253
|
-
if file.to_s
|
253
|
+
if file.to_s.match?(/^.{0,2}component.xml$/)
|
254
254
|
content_type = 'component'
|
255
255
|
end
|
256
256
|
# extract uuid and vid
|
data/lib/bcl.rb
CHANGED
@@ -27,12 +27,10 @@ require 'spreadsheet'
|
|
27
27
|
|
28
28
|
require 'bcl/core_ext'
|
29
29
|
require 'bcl/base_xml'
|
30
|
-
require 'bcl/component_spreadsheet'
|
31
30
|
require 'bcl/component_from_spreadsheet'
|
32
31
|
require 'bcl/component'
|
33
32
|
require 'bcl/component_methods'
|
34
33
|
require 'bcl/tar_ball'
|
35
|
-
require 'bcl/master_taxonomy'
|
36
34
|
require 'bcl/version'
|
37
35
|
|
38
36
|
# Some global structures
|
data/lib/bcl/component.rb
CHANGED
@@ -30,8 +30,6 @@ module BCL
|
|
30
30
|
class ComponentFromSpreadsheet
|
31
31
|
@@changed = false
|
32
32
|
|
33
|
-
public
|
34
|
-
|
35
33
|
# initialize with Excel spreadsheet to read
|
36
34
|
# seems to only be working with xls spreadsheets
|
37
35
|
def initialize(xlsx_path, worksheet_names = ['all'])
|
@@ -80,14 +78,14 @@ module BCL
|
|
80
78
|
|
81
79
|
puts " headers: #{component.headers}"
|
82
80
|
component.headers.each do |header|
|
83
|
-
if /description/i.match(header.name)
|
81
|
+
if /description/i.match?(header.name)
|
84
82
|
name = values.delete_at(0) # name, uid already processed
|
85
83
|
uid = values.delete_at(0)
|
86
84
|
component_xml.comp_version_id = values.delete_at(0)
|
87
85
|
description = values.delete_at(0)
|
88
86
|
component_xml.modeler_description = values.delete_at(0)
|
89
87
|
component_xml.description = description
|
90
|
-
elsif /provenance/i.match(header.name)
|
88
|
+
elsif /provenance/i.match?(header.name)
|
91
89
|
author = values.delete_at(0)
|
92
90
|
datetime = values.delete_at(0)
|
93
91
|
if datetime.nil?
|
@@ -97,10 +95,10 @@ module BCL
|
|
97
95
|
|
98
96
|
comment = values.delete_at(0)
|
99
97
|
component_xml.add_provenance(author.to_s, datetime.strftime('%Y-%m-%d'), comment.to_s)
|
100
|
-
elsif /tag/i.match(header.name)
|
98
|
+
elsif /tag/i.match?(header.name)
|
101
99
|
value = values.delete_at(0)
|
102
100
|
component_xml.add_tag(value)
|
103
|
-
elsif /attribute/i.match(header.name)
|
101
|
+
elsif /attribute/i.match?(header.name)
|
104
102
|
value = values.delete_at(0)
|
105
103
|
name = header.children[0]
|
106
104
|
units = ''
|
@@ -109,7 +107,7 @@ module BCL
|
|
109
107
|
units = match_data[2].strip
|
110
108
|
end
|
111
109
|
component_xml.add_attribute(name, value, units)
|
112
|
-
elsif /source/i.match(header.name)
|
110
|
+
elsif /source/i.match?(header.name)
|
113
111
|
manufacturer = values.delete_at(0)
|
114
112
|
model = values.delete_at(0)
|
115
113
|
serial_no = values.delete_at(0)
|
@@ -120,7 +118,7 @@ module BCL
|
|
120
118
|
component_xml.source_serial_no = serial_no
|
121
119
|
component_xml.source_year = year
|
122
120
|
component_xml.source_url = url
|
123
|
-
elsif /file/i.match(header.name)
|
121
|
+
elsif /file/i.match?(header.name)
|
124
122
|
software_program = values.delete_at(0)
|
125
123
|
version = values.delete_at(0)
|
126
124
|
filename = values.delete_at(0)
|
@@ -93,13 +93,13 @@ module BCL
|
|
93
93
|
bni = ''
|
94
94
|
junkout = res['set-cookie'].split(';')
|
95
95
|
junkout.each do |line|
|
96
|
-
if line
|
96
|
+
if line.match?(/BNES_SESS/)
|
97
97
|
bnes = line.match(/(BNES_SESS.*)/)[0]
|
98
98
|
end
|
99
99
|
end
|
100
100
|
|
101
101
|
junkout.each do |line|
|
102
|
-
if line
|
102
|
+
if line.match?(/BNI/)
|
103
103
|
bni = line.match(/(BNI.*)/)[0]
|
104
104
|
end
|
105
105
|
end
|
@@ -293,13 +293,13 @@ module BCL
|
|
293
293
|
version_id = nil
|
294
294
|
if uuid.nil?
|
295
295
|
puts File.extname(filename_and_path).downcase
|
296
|
-
if filename_and_path
|
296
|
+
if filename_and_path.match?(/^.*.tar.gz$/i)
|
297
297
|
uuid, version_id = uuid_vid_from_tarball(filename_and_path)
|
298
298
|
puts "Parsed uuid out of tar.gz file with value #{uuid}"
|
299
299
|
end
|
300
300
|
else
|
301
301
|
# verify the uuid via regex
|
302
|
-
unless uuid
|
302
|
+
unless uuid.match?(/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/)
|
303
303
|
raise "uuid of #{uuid} is invalid"
|
304
304
|
end
|
305
305
|
end
|
@@ -362,7 +362,7 @@ module BCL
|
|
362
362
|
xml_file = REXML::Document.new entry.read
|
363
363
|
|
364
364
|
# pull out some information
|
365
|
-
if entry.name
|
365
|
+
if entry.name.match?(/component/)
|
366
366
|
u = xml_file.elements['component/uid']
|
367
367
|
v = xml_file.elements['component/version_id']
|
368
368
|
else
|
@@ -392,7 +392,7 @@ module BCL
|
|
392
392
|
xml_to_parse = File.new(path_to_xml)
|
393
393
|
xml_file = REXML::Document.new xml_to_parse
|
394
394
|
|
395
|
-
if path_to_xml.to_s.split('/').last
|
395
|
+
if path_to_xml.to_s.split('/').last.match?(/component.xml/)
|
396
396
|
u = xml_file.elements['component/uid']
|
397
397
|
v = xml_file.elements['component/version_id']
|
398
398
|
else
|
@@ -619,7 +619,7 @@ module BCL
|
|
619
619
|
|
620
620
|
settings
|
621
621
|
end
|
622
|
-
end
|
622
|
+
end
|
623
623
|
|
624
624
|
# TODO: make this extend the component_xml class (or create a super class around components)
|
625
625
|
|
@@ -681,4 +681,4 @@ module BCL
|
|
681
681
|
|
682
682
|
Dir.chdir(current_dir)
|
683
683
|
end
|
684
|
-
end
|
684
|
+
end
|
data/lib/bcl/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: bcl
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.6.
|
4
|
+
version: 0.6.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Daniel Macumber
|
@@ -11,7 +11,7 @@ authors:
|
|
11
11
|
autorequire:
|
12
12
|
bindir: exe
|
13
13
|
cert_chain: []
|
14
|
-
date: 2020-
|
14
|
+
date: 2020-05-09 00:00:00.000000000 Z
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
17
17
|
name: builder
|
@@ -174,11 +174,9 @@ files:
|
|
174
174
|
- lib/bcl/component.rb
|
175
175
|
- lib/bcl/component_from_spreadsheet.rb
|
176
176
|
- lib/bcl/component_methods.rb
|
177
|
-
- lib/bcl/component_spreadsheet.rb
|
178
177
|
- lib/bcl/core_ext.rb
|
179
178
|
- lib/bcl/current_taxonomy.json
|
180
179
|
- lib/bcl/current_taxonomy.xml
|
181
|
-
- lib/bcl/master_taxonomy.rb
|
182
180
|
- lib/bcl/tar_ball.rb
|
183
181
|
- lib/bcl/version.rb
|
184
182
|
- lib/files/Components.xls
|
@@ -1,287 +0,0 @@
|
|
1
|
-
######################################################################
|
2
|
-
# Copyright (c) 2008-2019, Alliance for Sustainable Energy.
|
3
|
-
# All rights reserved.
|
4
|
-
#
|
5
|
-
# This library is free software; you can redistribute it and/or
|
6
|
-
# modify it under the terms of the GNU Lesser General Public
|
7
|
-
# License as published by the Free Software Foundation; either
|
8
|
-
# version 2.1 of the License, or (at your option) any later version.
|
9
|
-
#
|
10
|
-
# This library is distributed in the hope that it will be useful,
|
11
|
-
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
12
|
-
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
13
|
-
# Lesser General Public License for more details.
|
14
|
-
#
|
15
|
-
# You should have received a copy of the GNU Lesser General Public
|
16
|
-
# License along with this library; if not, write to the Free Software
|
17
|
-
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
18
|
-
######################################################################
|
19
|
-
|
20
|
-
# Converts a custom Excel spreadsheet format to BCL components for upload
|
21
|
-
# Format of the Excel spreadsheet is documented in /doc/ComponentSpreadsheet.docx
|
22
|
-
|
23
|
-
if RUBY_PLATFORM =~ /mswin|mingw|cygwin/
|
24
|
-
begin
|
25
|
-
# apparently this is not a gem (todo: need to remove and replace with roo)
|
26
|
-
require 'win32ole'
|
27
|
-
mod = WIN32OLE
|
28
|
-
$have_win32ole = true
|
29
|
-
rescue NameError
|
30
|
-
# do not have win32ole
|
31
|
-
end
|
32
|
-
end
|
33
|
-
|
34
|
-
module BCL
|
35
|
-
class ComponentSpreadsheet
|
36
|
-
public
|
37
|
-
|
38
|
-
# WINDOWS ONLY SECTION BECAUSE THIS USES WIN32OLE
|
39
|
-
if $have_win32ole
|
40
|
-
|
41
|
-
# initialize with Excel spreadsheet to read
|
42
|
-
def initialize(xlsx_path, worksheet_names = ['all'])
|
43
|
-
@xlsx_path = Pathname.new(xlsx_path).realpath.to_s
|
44
|
-
@worksheets = []
|
45
|
-
|
46
|
-
begin
|
47
|
-
excel = WIN32OLE.new('Excel.Application')
|
48
|
-
|
49
|
-
xlsx = excel.Workbooks.Open(@xlsx_path)
|
50
|
-
|
51
|
-
# by default, operate on all worksheets
|
52
|
-
if worksheet_names == ['all']
|
53
|
-
xlsx.Worksheets.each do |xlsx_worksheet|
|
54
|
-
parse_xlsx_worksheet(xlsx_worksheet)
|
55
|
-
end
|
56
|
-
else # if specific worksheets are specified, operate on them
|
57
|
-
worksheet_names.each do |worksheet_name|
|
58
|
-
parse_xlsx_worksheet(xlsx.Worksheets(worksheet_name))
|
59
|
-
end
|
60
|
-
end
|
61
|
-
|
62
|
-
# save spreadsheet if changes have been made
|
63
|
-
if xlsx.saved == true
|
64
|
-
# puts "[ComponentSpreadsheet] Spreadsheet unchanged; not saving"
|
65
|
-
else
|
66
|
-
xlsx.Save
|
67
|
-
puts '[ComponentSpreadsheet] Spreadsheet changes saved'
|
68
|
-
end
|
69
|
-
ensure
|
70
|
-
excel.Quit
|
71
|
-
WIN32OLE.ole_free(excel)
|
72
|
-
excel.ole_free
|
73
|
-
xlsx = nil
|
74
|
-
excel = nil
|
75
|
-
GC.start
|
76
|
-
end
|
77
|
-
end
|
78
|
-
|
79
|
-
else # if $have_win32ole
|
80
|
-
|
81
|
-
# parse the master taxonomy document
|
82
|
-
def initialize(_xlsx_path)
|
83
|
-
puts "ComponentSpreadsheet class requires 'win32ole' to parse the component spreadsheet."
|
84
|
-
puts 'ComponentSpreadsheet may also be stored and loaded from JSON if your platform does not support win32ole.'
|
85
|
-
end
|
86
|
-
|
87
|
-
end # if $have_win32ole
|
88
|
-
|
89
|
-
def save(save_path, chunk_size = 1000, delete_old_gather = false)
|
90
|
-
# load master taxonomy to validate components
|
91
|
-
taxonomy = BCL::MasterTaxonomy.new
|
92
|
-
|
93
|
-
# FileUtils.rm_rf(save_path) if File.exists?(save_path) and File.directory?(save_path)
|
94
|
-
|
95
|
-
@worksheets.each do |worksheet|
|
96
|
-
worksheet.components.each do |component|
|
97
|
-
component_xml = Component.new("#{save_path}/components")
|
98
|
-
component_xml.name = component.name
|
99
|
-
component_xml.uid = component.uid
|
100
|
-
component_xml.comp_version_id = component.version_id
|
101
|
-
|
102
|
-
# this tag is how we know where this goes in the taxonomy
|
103
|
-
component_xml.add_tag(worksheet.name)
|
104
|
-
|
105
|
-
values = component.values[0]
|
106
|
-
component.headers.each do |header|
|
107
|
-
if /description/i.match(header.name)
|
108
|
-
|
109
|
-
name = values.delete_at(0)
|
110
|
-
uid = values.delete_at(0)
|
111
|
-
version_id = values.delete_at(0)
|
112
|
-
description = values.delete_at(0)
|
113
|
-
fidelity_level = values.delete_at(0).to_int
|
114
|
-
# name, uid, and version_id already processed
|
115
|
-
component_xml.description = description
|
116
|
-
component_xml.fidelity_level = fidelity_level
|
117
|
-
|
118
|
-
elsif /provenance/i.match(header.name)
|
119
|
-
|
120
|
-
author = values.delete_at(0)
|
121
|
-
datetime = values.delete_at(0)
|
122
|
-
if datetime.nil?
|
123
|
-
# puts "[ComponentSpreadsheet] WARNING missing the date in the datetime column in the spreadsheet - assuming today"
|
124
|
-
datetime = DateTime.new
|
125
|
-
else
|
126
|
-
datetime = DateTime.parse(datetime)
|
127
|
-
end
|
128
|
-
|
129
|
-
comment = values.delete_at(0)
|
130
|
-
component_xml.add_provenance(author.to_s, datetime.to_s, comment.to_s)
|
131
|
-
|
132
|
-
elsif /tag/i.match(header.name)
|
133
|
-
|
134
|
-
value = values.delete_at(0)
|
135
|
-
component_xml.add_tag(value)
|
136
|
-
|
137
|
-
elsif /attribute/i.match(header.name)
|
138
|
-
|
139
|
-
value = values.delete_at(0)
|
140
|
-
name = header.children[0]
|
141
|
-
units = ''
|
142
|
-
if match_data = /(.*)\((.*)\)/.match(name)
|
143
|
-
name = match_data[1].strip
|
144
|
-
units = match_data[2].strip
|
145
|
-
end
|
146
|
-
component_xml.add_attribute(name, value, units)
|
147
|
-
|
148
|
-
elsif /source/i.match(header.name)
|
149
|
-
|
150
|
-
manufacturer = values.delete_at(0)
|
151
|
-
model = values.delete_at(0)
|
152
|
-
serial_no = values.delete_at(0)
|
153
|
-
year = values.delete_at(0)
|
154
|
-
url = values.delete_at(0)
|
155
|
-
component_xml.source_manufacturer = manufacturer
|
156
|
-
component_xml.source_model = model
|
157
|
-
component_xml.source_serial_no = serial_no
|
158
|
-
component_xml.source_year = year
|
159
|
-
component_xml.source_url = url
|
160
|
-
|
161
|
-
elsif /file/i.match(header.name)
|
162
|
-
|
163
|
-
software_program = values.delete_at(0)
|
164
|
-
version = values.delete_at(0)
|
165
|
-
filename = values.delete_at(0)
|
166
|
-
filetype = values.delete_at(0)
|
167
|
-
filepath = values.delete_at(0)
|
168
|
-
# not all components(rows) have all files; skip if filename "" or nil
|
169
|
-
next if filename == '' || filename.nil?
|
170
|
-
|
171
|
-
# skip the file if it doesn't exist at the specified location
|
172
|
-
unless File.exist?(filepath)
|
173
|
-
puts "[ComponentSpreadsheet] ERROR #{filepath} -> File does not exist, will not be included in component xml"
|
174
|
-
next # go to the next file
|
175
|
-
end
|
176
|
-
component_xml.add_file(software_program, version, filepath, filename, filetype)
|
177
|
-
|
178
|
-
else
|
179
|
-
raise "Unknown section #{header.name}"
|
180
|
-
|
181
|
-
end
|
182
|
-
end
|
183
|
-
|
184
|
-
taxonomy.check_component(component_xml)
|
185
|
-
|
186
|
-
component_xml.save_tar_gz(false)
|
187
|
-
end
|
188
|
-
end
|
189
|
-
|
190
|
-
BCL.gather_components(save_path, chunk_size, delete_old_gather)
|
191
|
-
end
|
192
|
-
|
193
|
-
private
|
194
|
-
|
195
|
-
def parse_xlsx_worksheet(xlsx_worksheet)
|
196
|
-
worksheet = WorksheetStruct.new
|
197
|
-
worksheet.name = xlsx_worksheet.Range('A1').Value
|
198
|
-
worksheet.components = []
|
199
|
-
puts "[ComponentSpreadsheet] Starting parsing components of type #{worksheet.name}"
|
200
|
-
|
201
|
-
# find number of rows, first column should be name, should not be empty
|
202
|
-
num_rows = 1
|
203
|
-
loop do
|
204
|
-
test = xlsx_worksheet.Range("A#{num_rows}").Value
|
205
|
-
if test.nil? || test.empty?
|
206
|
-
num_rows -= 1
|
207
|
-
break
|
208
|
-
end
|
209
|
-
num_rows += 1
|
210
|
-
end
|
211
|
-
|
212
|
-
# scan number of columns
|
213
|
-
headers = []
|
214
|
-
header = nil
|
215
|
-
max_col = nil
|
216
|
-
xlsx_worksheet.Columns.each do |col|
|
217
|
-
value1 = col.Rows('1').Value
|
218
|
-
value2 = col.Rows('2').Value
|
219
|
-
|
220
|
-
if !value1.nil? && !value1.empty?
|
221
|
-
unless header.nil?
|
222
|
-
headers << header
|
223
|
-
end
|
224
|
-
header = HeaderStruct.new
|
225
|
-
header.name = value1
|
226
|
-
header.children = []
|
227
|
-
end
|
228
|
-
|
229
|
-
if !value2.nil? && !value2.empty?
|
230
|
-
unless header.nil?
|
231
|
-
header.children << value2
|
232
|
-
end
|
233
|
-
end
|
234
|
-
|
235
|
-
if (value1.nil? || value1.empty?) && (value2.nil? || value2.empty?)
|
236
|
-
break
|
237
|
-
end
|
238
|
-
|
239
|
-
matchdata = /^\$(.+):/.match(col.Address)
|
240
|
-
max_col = matchdata[1]
|
241
|
-
end
|
242
|
-
|
243
|
-
unless header.nil?
|
244
|
-
headers << header
|
245
|
-
end
|
246
|
-
|
247
|
-
unless headers.empty?
|
248
|
-
headers[0].name = 'description'
|
249
|
-
end
|
250
|
-
|
251
|
-
puts " Found #{num_rows - 2} components"
|
252
|
-
|
253
|
-
components = []
|
254
|
-
for i in 3..num_rows do
|
255
|
-
component = ComponentStruct.new
|
256
|
-
component.row = i
|
257
|
-
|
258
|
-
# get name
|
259
|
-
component.name = xlsx_worksheet.Range("A#{i}").value
|
260
|
-
|
261
|
-
# get uid, if empty set it
|
262
|
-
component.uid = xlsx_worksheet.Range("B#{i}").value
|
263
|
-
if component.uid.nil? || component.uid.empty?
|
264
|
-
component.uid = UUID.new.generate
|
265
|
-
puts "#{component.name} uid missing; creating new one"
|
266
|
-
xlsx_worksheet.Range("B#{i}").value = component.uid
|
267
|
-
end
|
268
|
-
|
269
|
-
# get version_id, if empty set it
|
270
|
-
component.version_id = xlsx_worksheet.Range("C#{i}").value
|
271
|
-
if component.version_id.nil? || component.version_id.empty?
|
272
|
-
component.version_id = UUID.new.generate
|
273
|
-
puts "#{component.name} version id missing; creating new one"
|
274
|
-
xlsx_worksheet.Range("C#{i}").value = component.version_id
|
275
|
-
end
|
276
|
-
|
277
|
-
component.headers = headers
|
278
|
-
component.values = xlsx_worksheet.Range("A#{i}:#{max_col}#{i}").value
|
279
|
-
worksheet.components << component
|
280
|
-
end
|
281
|
-
|
282
|
-
@worksheets << worksheet
|
283
|
-
|
284
|
-
puts "[ComponentSpreadsheet] Finished parsing components of type #{worksheet.name}"
|
285
|
-
end
|
286
|
-
end
|
287
|
-
end # module BCL
|
data/lib/bcl/master_taxonomy.rb
DELETED
@@ -1,528 +0,0 @@
|
|
1
|
-
######################################################################
|
2
|
-
# Copyright (c) 2008-2019, Alliance for Sustainable Energy.
|
3
|
-
# All rights reserved.
|
4
|
-
#
|
5
|
-
# This library is free software; you can redistribute it and/or
|
6
|
-
# modify it under the terms of the GNU Lesser General Public
|
7
|
-
# License as published by the Free Software Foundation; either
|
8
|
-
# version 2.1 of the License, or (at your option) any later version.
|
9
|
-
#
|
10
|
-
# This library is distributed in the hope that it will be useful,
|
11
|
-
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
12
|
-
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
13
|
-
# Lesser General Public License for more details.
|
14
|
-
#
|
15
|
-
# You should have received a copy of the GNU Lesser General Public
|
16
|
-
# License along with this library; if not, write to the Free Software
|
17
|
-
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
18
|
-
######################################################################
|
19
|
-
|
20
|
-
$have_win32ole = false
|
21
|
-
|
22
|
-
if RUBY_PLATFORM =~ /mswin|mingw|cygwin/
|
23
|
-
begin
|
24
|
-
# apparently this is not a gem
|
25
|
-
require 'win32ole'
|
26
|
-
mod = WIN32OLE
|
27
|
-
$have_win32ole = true
|
28
|
-
rescue NameError
|
29
|
-
# do not have win32ole
|
30
|
-
end
|
31
|
-
end
|
32
|
-
|
33
|
-
module BCL
|
34
|
-
# each TagStruct represents a node in the taxonomy tree
|
35
|
-
TagStruct = Struct.new(:level_hierarchy, :name, :description, :parent_tag, :child_tags, :terms)
|
36
|
-
|
37
|
-
# each TermStruct represents a row in the master taxonomy
|
38
|
-
TermStruct = Struct.new(:first_level, :second_level, :third_level, :level_hierarchy, :name, :description,
|
39
|
-
:abbr, :data_type, :enums, :ip_written, :ip_symbol, :ip_mask, :si_written, :si_symbol, :si_mask,
|
40
|
-
:unit_conversion, :default_val, :min_val, :max_val, :allow_multiple, :row, :tp_include,
|
41
|
-
:tp_required, :tp_use_in_search, :tp_use_in_facets, :tp_show_data_to_data_users, :tp_third_party_testing,
|
42
|
-
:tp_additional_web_dev_info, :tp_additional_data_user_info, :tp_additional_data_submitter_info)
|
43
|
-
|
44
|
-
# class for parsing, validating, and querying the master taxonomy document
|
45
|
-
class MasterTaxonomy
|
46
|
-
# parse the master taxonomy document
|
47
|
-
def initialize(xlsx_path = nil, sort_alpha = false)
|
48
|
-
@sort_alphabetical = sort_alpha
|
49
|
-
|
50
|
-
# hash of level_taxonomy to tag
|
51
|
-
@tag_hash = {}
|
52
|
-
|
53
|
-
if xlsx_path.nil?
|
54
|
-
# load from the current taxonomy
|
55
|
-
path = current_taxonomy_path
|
56
|
-
puts "Loading current taxonomy from #{path}"
|
57
|
-
File.open(path, 'r') do |file|
|
58
|
-
@tag_hash = Marshal.load(file)
|
59
|
-
end
|
60
|
-
else
|
61
|
-
xlsx_path = Pathname.new(xlsx_path).realpath.to_s
|
62
|
-
puts "Loading taxonomy file #{xlsx_path}"
|
63
|
-
|
64
|
-
# WINDOWS ONLY SECTION BECAUSE THIS USES WIN32OLE
|
65
|
-
if $have_win32ole
|
66
|
-
begin
|
67
|
-
excel = WIN32OLE.new('Excel.Application')
|
68
|
-
xlsx = excel.Workbooks.Open(xlsx_path)
|
69
|
-
terms_worksheet = xlsx.Worksheets('Terms')
|
70
|
-
parse_terms(terms_worksheet)
|
71
|
-
ensure
|
72
|
-
# not really saving just pretending so don't get prompted on quit
|
73
|
-
xlsx.saved = true
|
74
|
-
excel.Quit
|
75
|
-
WIN32OLE.ole_free(excel)
|
76
|
-
excel.ole_free
|
77
|
-
xlsx = nil
|
78
|
-
excel = nil
|
79
|
-
GC.start
|
80
|
-
end
|
81
|
-
else # if $have_win32ole
|
82
|
-
puts "MasterTaxonomy class requires 'win32ole' to parse master taxonomy document."
|
83
|
-
puts 'MasterTaxonomy may also be stored and loaded from JSON if your platform does not support win32ole.'
|
84
|
-
end # if $have_win32ole
|
85
|
-
end
|
86
|
-
end
|
87
|
-
|
88
|
-
# save the current taxonomy
|
89
|
-
def save_as_current_taxonomy(path = nil)
|
90
|
-
path ||= current_taxonomy_path
|
91
|
-
puts "Saving current taxonomy to #{path}"
|
92
|
-
# this is really not JSON... it is a persisted format of ruby
|
93
|
-
File.open(path, 'w') do |file|
|
94
|
-
Marshal.dump(@tag_hash, file)
|
95
|
-
end
|
96
|
-
end
|
97
|
-
|
98
|
-
# write taxonomy to xml
|
99
|
-
def write_xml(path, output_type = 'tpex')
|
100
|
-
root_tag = @tag_hash['']
|
101
|
-
|
102
|
-
if root_tag.nil?
|
103
|
-
puts 'Cannot find root tag'
|
104
|
-
return false
|
105
|
-
end
|
106
|
-
|
107
|
-
File.open(path, 'w') do |file|
|
108
|
-
xml = Builder::XmlMarkup.new(target: file, indent: 2)
|
109
|
-
|
110
|
-
# setup the xml file
|
111
|
-
xml.instruct!(:xml, version: '1.0', encoding: 'UTF-8')
|
112
|
-
xml.schema('xmlns:xsi' => 'http://www.w3.org/2001/XMLSchema-instance') do
|
113
|
-
write_tag_to_xml(root_tag, 0, xml, output_type)
|
114
|
-
end
|
115
|
-
end
|
116
|
-
end
|
117
|
-
|
118
|
-
# get all terms for a given tag
|
119
|
-
# this includes terms that are inherited from parent levels
|
120
|
-
# e.g. master_taxonomy.get_terms("Space Use.Lighting.Lamp Ballast")
|
121
|
-
def get_terms(tag)
|
122
|
-
terms = tag.terms
|
123
|
-
|
124
|
-
parent_tag = tag.parent_tag
|
125
|
-
until parent_tag.nil?
|
126
|
-
terms.concat(parent_tag.terms)
|
127
|
-
parent_tag = parent_tag.parent_tag
|
128
|
-
end
|
129
|
-
|
130
|
-
# sort the terms as they come out
|
131
|
-
result = terms.uniq
|
132
|
-
if !@sort_alphabetical
|
133
|
-
result = result.sort_by(&:row)
|
134
|
-
else
|
135
|
-
result = result.sort_by(&:name)
|
136
|
-
end
|
137
|
-
|
138
|
-
result
|
139
|
-
end
|
140
|
-
|
141
|
-
# check that the given component is conforms with the master taxonomy
|
142
|
-
def check_component(component)
|
143
|
-
valid = true
|
144
|
-
tag = nil
|
145
|
-
|
146
|
-
# see if we can find the component's tag in the taxonomy
|
147
|
-
tags = component.tags
|
148
|
-
if tags.empty?
|
149
|
-
puts '[Check Component ERROR] Component does not have any tags'
|
150
|
-
valid = false
|
151
|
-
elsif tags.size > 1
|
152
|
-
puts '[Check Component ERROR] Component has multiple tags'
|
153
|
-
valid = false
|
154
|
-
else
|
155
|
-
tag = @tag_hash[tags[0].descriptor]
|
156
|
-
unless tag
|
157
|
-
puts "[Check Component ERROR] Cannot find #{tags[0].descriptor} in the master taxonomy"
|
158
|
-
valid = false
|
159
|
-
end
|
160
|
-
end
|
161
|
-
|
162
|
-
unless tag
|
163
|
-
return false
|
164
|
-
end
|
165
|
-
|
166
|
-
terms = get_terms(tag)
|
167
|
-
|
168
|
-
# TODO: check for all required attributes
|
169
|
-
terms.each do |_term|
|
170
|
-
# if term.required
|
171
|
-
# make sure we find attribute
|
172
|
-
# end
|
173
|
-
end
|
174
|
-
|
175
|
-
# check that all attributes are allowed
|
176
|
-
component.attributes.each do |attribute|
|
177
|
-
term = nil
|
178
|
-
terms.each do |t|
|
179
|
-
if t.name == attribute.name
|
180
|
-
term = t
|
181
|
-
break
|
182
|
-
end
|
183
|
-
end
|
184
|
-
|
185
|
-
unless term
|
186
|
-
puts "[Check Component ERROR] Cannot find term for #{attribute.name} in #{tag.level_hierarchy}"
|
187
|
-
valid = false
|
188
|
-
next
|
189
|
-
end
|
190
|
-
|
191
|
-
# TODO: validate value, datatype, units
|
192
|
-
end
|
193
|
-
|
194
|
-
valid
|
195
|
-
end
|
196
|
-
|
197
|
-
private
|
198
|
-
|
199
|
-
def current_taxonomy_path
|
200
|
-
File.dirname(__FILE__) + '/current_taxonomy.json'
|
201
|
-
end
|
202
|
-
|
203
|
-
def parse_terms(terms_worksheet)
|
204
|
-
# check header
|
205
|
-
header_error = validate_terms_header(terms_worksheet)
|
206
|
-
if header_error
|
207
|
-
raise 'Header Error on Terms Worksheet'
|
208
|
-
end
|
209
|
-
|
210
|
-
# add root tag
|
211
|
-
root_terms = []
|
212
|
-
root_terms << TermStruct.new('', '', '', '', 'OpenStudio Type', 'Type of OpenStudio Object')
|
213
|
-
root_terms[0].row = 0
|
214
|
-
# root_terms << TermStruct.new()
|
215
|
-
root_tag = TagStruct.new('', 'root', 'Root of the taxonomy', nil, [], root_terms)
|
216
|
-
@tag_hash[''] = root_tag
|
217
|
-
|
218
|
-
### puts "**** tag hash: #{@tag_hash}"
|
219
|
-
|
220
|
-
# find number of rows by parsing until hit empty value in first column
|
221
|
-
row_num = 3
|
222
|
-
loop do
|
223
|
-
term = parse_term(terms_worksheet, row_num)
|
224
|
-
if term.nil?
|
225
|
-
break
|
226
|
-
end
|
227
|
-
|
228
|
-
add_term(term)
|
229
|
-
|
230
|
-
row_num += 1
|
231
|
-
end
|
232
|
-
|
233
|
-
# sort the tag tree
|
234
|
-
sort_tag(root_tag)
|
235
|
-
|
236
|
-
# check the tag tree
|
237
|
-
check_tag(root_tag)
|
238
|
-
end
|
239
|
-
|
240
|
-
def validate_terms_header(terms_worksheet)
|
241
|
-
test_arr = []
|
242
|
-
test_arr << { 'name' => 'First Level', 'strict' => true }
|
243
|
-
test_arr << { 'name' => 'Second Level', 'strict' => true }
|
244
|
-
test_arr << { 'name' => 'Third Level', 'strict' => true }
|
245
|
-
test_arr << { 'name' => 'Level Hierarchy', 'strict' => true }
|
246
|
-
test_arr << { 'name' => 'Term', 'strict' => true }
|
247
|
-
test_arr << { 'name' => 'Abbr', 'strict' => true }
|
248
|
-
test_arr << { 'name' => 'Description', 'strict' => true }
|
249
|
-
test_arr << { 'name' => 'Data Type', 'strict' => true }
|
250
|
-
test_arr << { 'name' => 'Allow Multiple', 'strict' => true }
|
251
|
-
test_arr << { 'name' => 'Enumerations', 'strict' => true }
|
252
|
-
test_arr << { 'name' => 'IP Units Written Out', 'strict' => true }
|
253
|
-
test_arr << { 'name' => 'IP Units Symbol', 'strict' => true }
|
254
|
-
test_arr << { 'name' => 'IP Display Mask', 'strict' => true }
|
255
|
-
test_arr << { 'name' => 'SI Units Written Out', 'strict' => true }
|
256
|
-
test_arr << { 'name' => 'SI Units Symbol', 'strict' => true }
|
257
|
-
test_arr << { 'name' => 'SI Display Mask', 'strict' => true }
|
258
|
-
test_arr << { 'name' => 'Unit Conversion', 'strict' => true }
|
259
|
-
test_arr << { 'name' => 'Default', 'strict' => true }
|
260
|
-
test_arr << { 'name' => 'Min', 'strict' => true }
|
261
|
-
test_arr << { 'name' => 'Max', 'strict' => true }
|
262
|
-
test_arr << { 'name' => 'Source', 'strict' => true }
|
263
|
-
test_arr << { 'name' => 'Review State', 'strict' => true }
|
264
|
-
test_arr << { 'name' => 'General Comments', 'strict' => true }
|
265
|
-
test_arr << { 'name' => 'Requested By / Project', 'strict' => true }
|
266
|
-
test_arr << { 'name' => 'Include in TPE', 'strict' => false }
|
267
|
-
test_arr << { 'name' => 'Required for Adding a New Product', 'strict' => false }
|
268
|
-
test_arr << { 'name' => 'Use as a Column Header in Search Results', 'strict' => false }
|
269
|
-
test_arr << { 'name' => 'Allow Users to Filter with this Facet', 'strict' => false }
|
270
|
-
test_arr << { 'name' => 'Show Data to Data Users', 'strict' => false }
|
271
|
-
test_arr << { 'name' => 'Additional Instructions for Web Developers', 'strict' => false }
|
272
|
-
test_arr << { 'name' => 'Related Third Party Testing Standards', 'strict' => false }
|
273
|
-
test_arr << { 'name' => 'Additional Guidance to Data Submitters', 'strict' => false }
|
274
|
-
test_arr << { 'name' => 'Additional Guidance to Data Users', 'strict' => false }
|
275
|
-
|
276
|
-
parse = true
|
277
|
-
col = 1
|
278
|
-
while parse
|
279
|
-
if terms_worksheet.Columns(col).Rows(2).Value.nil? || col > test_arr.size
|
280
|
-
parse = false
|
281
|
-
else
|
282
|
-
unless terms_worksheet.Columns(col).Rows(2).Value == test_arr[col - 1]['name']
|
283
|
-
if test_arr[col - 1]['strict']
|
284
|
-
raise "[ERROR] Header does not match: #{col}: '#{terms_worksheet.Columns(col).Rows(2).Value} <> #{test_arr[col - 1]['name']}'"
|
285
|
-
else
|
286
|
-
puts "[WARNING] Header does not match: #{col}: '#{terms_worksheet.Columns(col).Rows(2).Value} <> #{test_arr[col - 1]['name']}'"
|
287
|
-
end
|
288
|
-
end
|
289
|
-
end
|
290
|
-
col += 1
|
291
|
-
end
|
292
|
-
end
|
293
|
-
|
294
|
-
def parse_term(terms_worksheet, row)
|
295
|
-
term = TermStruct.new
|
296
|
-
term.row = row
|
297
|
-
term.first_level = terms_worksheet.Columns(1).Rows(row).Value
|
298
|
-
term.second_level = terms_worksheet.Columns(2).Rows(row).Value
|
299
|
-
term.third_level = terms_worksheet.Columns(3).Rows(row).Value
|
300
|
-
term.level_hierarchy = terms_worksheet.Columns(4).Rows(row).Value
|
301
|
-
term.name = terms_worksheet.Columns(5).Rows(row).Value
|
302
|
-
term.abbr = terms_worksheet.Columns(6).Rows(row).Value
|
303
|
-
term.description = terms_worksheet.Columns(7).Rows(row).Value
|
304
|
-
term.data_type = terms_worksheet.Columns(8).Rows(row).Value
|
305
|
-
term.allow_multiple = terms_worksheet.Columns(9).Rows(row).Value
|
306
|
-
term.enums = terms_worksheet.Columns(10).Rows(row).Value
|
307
|
-
term.ip_written = terms_worksheet.Columns(11).Rows(row).Value
|
308
|
-
term.ip_symbol = terms_worksheet.Columns(12).Rows(row).Value
|
309
|
-
term.ip_mask = terms_worksheet.Columns(13).Rows(row).Value
|
310
|
-
term.si_written = terms_worksheet.Columns(14).Rows(row).Value
|
311
|
-
term.si_symbol = terms_worksheet.Columns(15).Rows(row).Value
|
312
|
-
term.si_mask = terms_worksheet.Columns(16).Rows(row).Value
|
313
|
-
term.unit_conversion = terms_worksheet.Columns(17).Rows(row).Value
|
314
|
-
term.default_val = terms_worksheet.Columns(18).Rows(row).Value
|
315
|
-
term.min_val = terms_worksheet.Columns(19).Rows(row).Value
|
316
|
-
term.max_val = terms_worksheet.Columns(20).Rows(row).Value
|
317
|
-
|
318
|
-
# custom TPex Columns
|
319
|
-
term.tp_include = terms_worksheet.Columns(25).Rows(row).Value
|
320
|
-
term.tp_required = terms_worksheet.Columns(26).Rows(row).Value
|
321
|
-
term.tp_use_in_search = terms_worksheet.Columns(27).Rows(row).Value
|
322
|
-
term.tp_use_in_facets = terms_worksheet.Columns(28).Rows(row).Value
|
323
|
-
term.tp_show_data_to_data_users = terms_worksheet.Columns(29).Rows(row).Value
|
324
|
-
term.tp_additional_web_dev_info = terms_worksheet.Columns(30).Rows(row).Value
|
325
|
-
term.tp_third_party_testing = terms_worksheet.Columns(31).Rows(row).Value
|
326
|
-
term.tp_additional_data_submitter_info = terms_worksheet.Columns(32).Rows(row).Value
|
327
|
-
term.tp_additional_data_user_info = terms_worksheet.Columns(33).Rows(row).Value
|
328
|
-
|
329
|
-
# trigger to quit parsing the xcel doc
|
330
|
-
if term.first_level.nil? || term.first_level.empty?
|
331
|
-
return nil
|
332
|
-
end
|
333
|
-
|
334
|
-
term
|
335
|
-
end
|
336
|
-
|
337
|
-
def add_term(term)
|
338
|
-
level_hierarchy = term.level_hierarchy
|
339
|
-
|
340
|
-
# create the tag
|
341
|
-
tag = @tag_hash[level_hierarchy]
|
342
|
-
|
343
|
-
if tag.nil?
|
344
|
-
tag = create_tag(level_hierarchy, term.description)
|
345
|
-
end
|
346
|
-
|
347
|
-
if term.name.nil? || term.name.strip.empty?
|
348
|
-
# this row is really about the tag
|
349
|
-
tag.description = term.description
|
350
|
-
|
351
|
-
else
|
352
|
-
# this row is about a term
|
353
|
-
unless validate_term(term)
|
354
|
-
return nil
|
355
|
-
end
|
356
|
-
|
357
|
-
tag.terms = [] if tag.terms.nil?
|
358
|
-
tag.terms << term
|
359
|
-
end
|
360
|
-
end
|
361
|
-
|
362
|
-
def create_tag(level_hierarchy, tag_description = '')
|
363
|
-
# puts "create_tag called for #{level_hierarchy}"
|
364
|
-
|
365
|
-
parts = level_hierarchy.split('.')
|
366
|
-
|
367
|
-
name = parts[-1]
|
368
|
-
parent_level = parts[0..-2].join('.')
|
369
|
-
|
370
|
-
parent_tag = @tag_hash[parent_level]
|
371
|
-
if parent_tag.nil?
|
372
|
-
parent_tag = create_tag(parent_level)
|
373
|
-
end
|
374
|
-
|
375
|
-
description = tag_description
|
376
|
-
child_tags = []
|
377
|
-
terms = []
|
378
|
-
tag = TagStruct.new(level_hierarchy, name, description, parent_tag, child_tags, terms)
|
379
|
-
|
380
|
-
parent_tag.child_tags << tag
|
381
|
-
|
382
|
-
@tag_hash[level_hierarchy] = tag
|
383
|
-
|
384
|
-
tag
|
385
|
-
end
|
386
|
-
|
387
|
-
def sort_tag(tag)
|
388
|
-
# tag.terms = tag.terms.sort {|x, y| x.level_hierarchy <=> y.level_hierarchy}
|
389
|
-
tag.child_tags = tag.child_tags.sort_by(&:level_hierarchy)
|
390
|
-
tag.child_tags.each { |child_tag| sort_tag(child_tag) }
|
391
|
-
|
392
|
-
# tag.terms = tag.terms.sort {|x, y| x.name <=> y.name}
|
393
|
-
# tag.child_tags = tag.child_tags.sort {|x, y| x.name <=> y.name}
|
394
|
-
# tag.child_tags.each {|child_tag| sort_tag(child_tag) }
|
395
|
-
end
|
396
|
-
|
397
|
-
def check_tag(tag)
|
398
|
-
if tag.description.nil? || tag.description.empty?
|
399
|
-
puts "[check_tag] tag '#{tag.level_hierarchy}' has no description"
|
400
|
-
end
|
401
|
-
|
402
|
-
tag.terms.each { |term| check_term(term) }
|
403
|
-
tag.child_tags.each { |child_tag| check_tag(child_tag) }
|
404
|
-
end
|
405
|
-
|
406
|
-
def validate_term(term)
|
407
|
-
valid = true
|
408
|
-
|
409
|
-
parts = term.level_hierarchy.split('.')
|
410
|
-
|
411
|
-
if parts.empty?
|
412
|
-
puts "Hierarchy parts empty, #{term.level_hierarchy}"
|
413
|
-
valid = false
|
414
|
-
end
|
415
|
-
|
416
|
-
if parts.size >= 1 && !term.first_level == parts[0]
|
417
|
-
puts "First level '#{term.first_level}' does not match level hierarchy '#{term.level_hierarchy}', skipping term"
|
418
|
-
valid = false
|
419
|
-
end
|
420
|
-
|
421
|
-
if parts.size >= 2 && !term.second_level == parts[1]
|
422
|
-
puts "Second level '#{term.second_level}' does not match level hierarchy '#{term.level_hierarchy}', skipping term"
|
423
|
-
valid = false
|
424
|
-
end
|
425
|
-
|
426
|
-
if parts.size >= 3 && !term.third_level == parts[2]
|
427
|
-
puts "Third level '#{term.third_level}' does not match level hierarchy '#{term.level_hierarchy}', skipping term"
|
428
|
-
valid = false
|
429
|
-
end
|
430
|
-
|
431
|
-
if parts.size > 3
|
432
|
-
puts "Hierarchy cannot have more than 3 parts '#{term.level_hierarchy}', skipping term"
|
433
|
-
valid = false
|
434
|
-
end
|
435
|
-
|
436
|
-
unless term.data_type.nil?
|
437
|
-
valid_types = ['double', 'integer', 'enum', 'file', 'string', 'autocomplete']
|
438
|
-
if (term.data_type.downcase != term.data_type) || !valid_types.include?(term.data_type)
|
439
|
-
puts "[ERROR] Term '#{term.name}' does not have a valid data type with '#{term.data_type}'"
|
440
|
-
end
|
441
|
-
|
442
|
-
if term.data_type.casecmp('enum').zero?
|
443
|
-
if term.enums.nil? || term.enums == '' || term.enums.casecmp('no enum found').zero?
|
444
|
-
puts "[ERROR] Term '#{term.name}' does not have valid enumerations"
|
445
|
-
end
|
446
|
-
end
|
447
|
-
end
|
448
|
-
|
449
|
-
valid
|
450
|
-
end
|
451
|
-
|
452
|
-
def check_term(term)
|
453
|
-
if term.description.nil? || term.description.empty?
|
454
|
-
# puts "[check_term] term '#{term.level_hierarchy}.#{term.name}' has no description"
|
455
|
-
end
|
456
|
-
end
|
457
|
-
|
458
|
-
# write term to xml
|
459
|
-
def write_terms_to_xml(tag, xml, output_type)
|
460
|
-
terms = get_terms(tag)
|
461
|
-
unless terms.empty?
|
462
|
-
terms.each do |term|
|
463
|
-
xml.term do
|
464
|
-
xml.name term.name
|
465
|
-
xml.abbr term.abbr unless term.abbr.nil?
|
466
|
-
xml.description term.description unless term.description.nil?
|
467
|
-
xml.data_type term.data_type unless term.data_type.nil?
|
468
|
-
xml.allow_multiple term.allow_multiple unless term.allow_multiple.nil?
|
469
|
-
|
470
|
-
if !term.enums.nil? && term.enums != ''
|
471
|
-
xml.enumerations do
|
472
|
-
out = term.enums.split('|')
|
473
|
-
out.sort! if @sort_alphabetical
|
474
|
-
out.each do |enum|
|
475
|
-
xml.enumeration enum
|
476
|
-
end
|
477
|
-
end
|
478
|
-
end
|
479
|
-
xml.ip_written term.ip_written unless term.ip_written.nil?
|
480
|
-
xml.ip_symbol term.ip_symbol unless term.ip_symbol.nil?
|
481
|
-
xml.ip_mask term.ip_mask unless term.ip_mask.nil?
|
482
|
-
xml.si_written term.si_written unless term.si_written.nil?
|
483
|
-
xml.si_symbol term.si_symbol unless term.si_symbol.nil?
|
484
|
-
xml.si_mask term.si_mask unless term.si_mask.nil?
|
485
|
-
xml.row term.row unless term.row.nil?
|
486
|
-
xml.unit_conversion term.unit_conversion unless term.unit_conversion.nil?
|
487
|
-
xml.default_val term.default_val unless term.default_val.nil?
|
488
|
-
xml.min_val term.min_val unless term.min_val.nil?
|
489
|
-
xml.max_val term.max_val unless term.max_val.nil?
|
490
|
-
|
491
|
-
if output_type == 'tpex'
|
492
|
-
xml.tp_include term.tp_include unless term.tp_include.nil?
|
493
|
-
xml.tp_required term.tp_required unless term.tp_required.nil?
|
494
|
-
xml.tp_use_in_search term.tp_use_in_search unless term.tp_use_in_search.nil?
|
495
|
-
xml.tp_use_in_facets term.tp_use_in_facets unless term.tp_use_in_facets.nil?
|
496
|
-
xml.tp_show_data_to_data_users term.tp_show_data_to_data_users unless term.tp_show_data_to_data_users.nil?
|
497
|
-
xml.tp_third_party_testing term.tp_third_party_testing unless term.tp_third_party_testing.nil?
|
498
|
-
xml.tp_additional_web_dev_info term.tp_additional_web_dev_info unless term.tp_additional_web_dev_info.nil?
|
499
|
-
xml.tp_additional_data_user_info term.tp_additional_data_user_info unless term.tp_additional_data_user_info.nil?
|
500
|
-
xml.tp_additional_data_submitter_info term.tp_additional_data_submitter_info unless term.tp_additional_data_submitter_info.nil?
|
501
|
-
end
|
502
|
-
end
|
503
|
-
end
|
504
|
-
end
|
505
|
-
end
|
506
|
-
|
507
|
-
# write a tag to xml
|
508
|
-
def write_tag_to_xml(tag, level, xml, output_type)
|
509
|
-
level_string = "level_#{level}"
|
510
|
-
xml.tag!(level_string) do
|
511
|
-
s_temp = tag.name
|
512
|
-
xml.name s_temp
|
513
|
-
xml.description tag.description
|
514
|
-
|
515
|
-
level += 1
|
516
|
-
|
517
|
-
if tag.child_tags.empty?
|
518
|
-
write_terms_to_xml(tag, xml, output_type)
|
519
|
-
end
|
520
|
-
|
521
|
-
child_tags = tag.child_tags
|
522
|
-
child_tags.each do |child_tag|
|
523
|
-
write_tag_to_xml(child_tag, level, xml, output_type)
|
524
|
-
end
|
525
|
-
end
|
526
|
-
end
|
527
|
-
end
|
528
|
-
end # module BCL
|