knartform 0.6.0
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 +7 -0
- data/.gitignore +1 -0
- data/Gemfile +2 -0
- data/Gemfile.lock +40 -0
- data/bin/audit_manifest +58 -0
- data/bin/batch_validation +128 -0
- data/bin/composite_graphs +47 -0
- data/bin/composite_to_dot +34 -0
- data/bin/knartform +26 -0
- data/bin/manifest_to_cds_connect +175 -0
- data/bin/spot_check +134 -0
- data/bin/update_manifest +147 -0
- data/knartform.gemspec +23 -0
- data/lib/common.rb +264 -0
- data/lib/knartform.rb +5 -0
- data/lib/knartform/action_group.rb +17 -0
- data/lib/knartform/knart.rb +71 -0
- data/lib/metadata.slim +12 -0
- data/lib/spot_check.slim +324 -0
- data/lib/views/action_group.slim +90 -0
- data/lib/views/documentation_template.slim +152 -0
- data/lib/views/dummy_add_button.slim +4 -0
- data/lib/views/dummy_drag_control.slim +3 -0
- data/lib/views/dummy_edit_and_delete.slim +5 -0
- data/lib/views/dummy_edit_button.slim +4 -0
- data/lib/views/unsupported.slim +4 -0
- metadata +159 -0
data/bin/spot_check
ADDED
@@ -0,0 +1,134 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'json'
|
4
|
+
require 'pp'
|
5
|
+
require 'byebug'
|
6
|
+
require 'nokogiri'
|
7
|
+
require 'slim'
|
8
|
+
|
9
|
+
require_relative "../lib/common"
|
10
|
+
include Repository
|
11
|
+
|
12
|
+
HELP = <<EOF
|
13
|
+
|
14
|
+
Renders a number of validation metrics for every KNART XML document references in a provided manifest.json.
|
15
|
+
|
16
|
+
USAGE: #{__FILE__} <manifest.json> <output.html>
|
17
|
+
|
18
|
+
EXAMPLE:
|
19
|
+
#{__FILE__} manifest.json output.html
|
20
|
+
|
21
|
+
EOF
|
22
|
+
|
23
|
+
def report(good, bad)
|
24
|
+
puts "\nGood file references: #{good.length}"
|
25
|
+
puts "Bad file references: #{bad.length}"
|
26
|
+
bad.each do |n| puts "\t#{[n['path'],n['url']].join(' ')}" end
|
27
|
+
puts "\n"
|
28
|
+
end
|
29
|
+
|
30
|
+
def extract_metadata(doc)
|
31
|
+
return {
|
32
|
+
identifiers: doc.xpath("///xmlns:metadata/xmlns:identifiers/xmlns:identifier/@identifierName").count, #collect{|n| n.to_s},
|
33
|
+
relatedResources: doc.xpath("//xmlns:relatedResource//xmlns:resource").count,
|
34
|
+
supportingEvidence: doc.xpath("//xmlns:supportingEvidence//xmlns:resource").count,
|
35
|
+
applicability: doc.xpath("//xmlns:applicability/xmlns:coverage").count,
|
36
|
+
eventHistory: doc.xpath("//xmlns:eventHistory/xmlns:artifactLifeCycleEvent").count,
|
37
|
+
contributions: doc.xpath("//xmlns:contributions//xmlns:contributor").count,
|
38
|
+
publishers: doc.xpath("//xmlns:publishers//xmlns:publisher").count,
|
39
|
+
}
|
40
|
+
end
|
41
|
+
|
42
|
+
def knart_validations(doc)
|
43
|
+
# We'll cover the basics first.
|
44
|
+
report = {
|
45
|
+
doc: doc,
|
46
|
+
title: doc.xpath("//xmlns:title/@value").first.to_s,
|
47
|
+
artifactType: doc.xpath("//xmlns:artifactType/@value").first.to_s,
|
48
|
+
metadata: extract_metadata(doc)
|
49
|
+
}
|
50
|
+
# Global ELM stuff.
|
51
|
+
exps = doc.xpath("/xmlns:knowledgeDocument/xmlns:expressions/xmlns:def")
|
52
|
+
|
53
|
+
report[:expressions] = exps.collect{|e| {
|
54
|
+
name: e.xpath("@name").to_s,
|
55
|
+
type: e.xpath('elm:expression/@xsi:type').to_s
|
56
|
+
}}
|
57
|
+
# puts report
|
58
|
+
report
|
59
|
+
end
|
60
|
+
|
61
|
+
def composite_validations(doc)
|
62
|
+
report = {
|
63
|
+
doc: doc,
|
64
|
+
title: doc.xpath("//xmlns:title/@value").first.to_s,
|
65
|
+
artifactType: doc.xpath("//xmlns:artifactType/@value").first.to_s,
|
66
|
+
metadata: extract_metadata(doc),
|
67
|
+
|
68
|
+
}
|
69
|
+
# report[:artifacts] =
|
70
|
+
xml = doc.xpath('//xmlns:containedArtifacts').to_s
|
71
|
+
# byebug
|
72
|
+
# puts xml
|
73
|
+
report[:artifacts] = Hash.from_xml(xml)[:containedArtifacts][:artifact]
|
74
|
+
# puts report
|
75
|
+
report
|
76
|
+
end
|
77
|
+
|
78
|
+
|
79
|
+
def static_manifest_validations(root, manifest)
|
80
|
+
knarts = {}
|
81
|
+
composites = {}
|
82
|
+
manifest['groups'].each do |group|
|
83
|
+
group['items'].each do |item|
|
84
|
+
path = "#{root}/#{item['path']}"
|
85
|
+
# puts "#{path}"
|
86
|
+
if KNART_MIME_TYPES.include? item['mimeType']
|
87
|
+
doc = Nokogiri::XML(File.open(path))
|
88
|
+
begin
|
89
|
+
knarts[item['path']] = knart_validations(doc)
|
90
|
+
# puts knarts[item['path']][:metadata]
|
91
|
+
rescue
|
92
|
+
knarts[item['path']] = {
|
93
|
+
error: "Could not be validated"
|
94
|
+
}
|
95
|
+
end
|
96
|
+
elsif COMPOSITE_MIME_TYPES.include? item['mimeType']
|
97
|
+
doc = Nokogiri::XML(File.open(path))
|
98
|
+
begin
|
99
|
+
composites[item['path']] = composite_validations(doc)
|
100
|
+
# puts composites[item['path']][:metadata]
|
101
|
+
rescue
|
102
|
+
composites[item['path']] = {
|
103
|
+
error: "Could not be validated"
|
104
|
+
}
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
[knarts, composites]
|
110
|
+
end
|
111
|
+
|
112
|
+
|
113
|
+
|
114
|
+
def render_results(manifest, root, knarts, composites, out)
|
115
|
+
html = render_partial('spot_check.slim', {root: '..', manifest: manifest, knarts: knarts, composites: composites})
|
116
|
+
# html = Jade.compile File.read(template), locals: {results: results}
|
117
|
+
# puts html
|
118
|
+
file = File.open(out, 'w')
|
119
|
+
file.write html
|
120
|
+
file.close
|
121
|
+
end
|
122
|
+
|
123
|
+
if(ARGV.length != 2)
|
124
|
+
puts HELP
|
125
|
+
exit 1
|
126
|
+
else
|
127
|
+
file = ARGV[0]
|
128
|
+
manifest = JSON.parse(File.read(file))
|
129
|
+
root = File.dirname(File.expand_path(file))
|
130
|
+
knarts, composites = static_manifest_validations(root, manifest)
|
131
|
+
Slim::Engine.set_options pretty: true
|
132
|
+
render_results(manifest, root, knarts, composites, ARGV[1])
|
133
|
+
exit 0
|
134
|
+
end
|
data/bin/update_manifest
ADDED
@@ -0,0 +1,147 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'json'
|
4
|
+
require 'pp'
|
5
|
+
require 'byebug'
|
6
|
+
|
7
|
+
require_relative '../lib/common'
|
8
|
+
include Repository
|
9
|
+
HELP = <<EOF.freeze
|
10
|
+
|
11
|
+
Updates an existing repository manifest.json file by merging in any additional files found in the root directory. If the existing and new manifest files are the same, the existing file will be *overwriten* in place. Be sure you have a backup handy if you're doing this!
|
12
|
+
|
13
|
+
USAGE: #{__FILE__} <content_root_directory> <existing_manifest.json> <new_manifest.json>
|
14
|
+
|
15
|
+
EXAMPLE:
|
16
|
+
#{__FILE__} . manifest.json manifest-new.json
|
17
|
+
|
18
|
+
EOF
|
19
|
+
|
20
|
+
def improveify_name!(item)
|
21
|
+
case item['path']
|
22
|
+
when /CCWP_/
|
23
|
+
item['name'] = 'Clinical Content White Paper'
|
24
|
+
when /HIMKWP_/
|
25
|
+
item['name'] = 'Harmonize and Integrate Member KNARTs White Paper'
|
26
|
+
when /ECA_/
|
27
|
+
item['name'] = 'ECA'
|
28
|
+
when /DT_/
|
29
|
+
item['name'] = 'Documentation Template'
|
30
|
+
when /OS_/
|
31
|
+
item['name'] = 'Order Set'
|
32
|
+
when /CRCK_/
|
33
|
+
item['name'] = 'Composite Artifact'
|
34
|
+
else
|
35
|
+
# Keep the existing name
|
36
|
+
end
|
37
|
+
|
38
|
+
case item['path']
|
39
|
+
when /KVRpt_/
|
40
|
+
item['name'] += ' Validation Report'
|
41
|
+
when /CSD_/
|
42
|
+
item['name'] += ' Conceptual Structure Document'
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def existing_manifest_item_for(item, existing)
|
47
|
+
existing_item = nil
|
48
|
+
existing['groups'].each do |group, _i|
|
49
|
+
# puts "NAME: #{group['name']}"
|
50
|
+
# puts group
|
51
|
+
group['items'].each do |n|
|
52
|
+
if n['path'] == item['path']
|
53
|
+
existing_item = n
|
54
|
+
break
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
existing_item
|
59
|
+
end
|
60
|
+
|
61
|
+
def existing_manifest_group_for(name, existing)
|
62
|
+
existing_group = nil
|
63
|
+
existing['groups'].each do |group, _i|
|
64
|
+
# puts "#{name} #{group['name']}"
|
65
|
+
if group['name'].casecmp(name).zero?
|
66
|
+
existing_group = group
|
67
|
+
break
|
68
|
+
end
|
69
|
+
end
|
70
|
+
existing_group
|
71
|
+
end
|
72
|
+
|
73
|
+
# Forces keys to strings.
|
74
|
+
def rekey(hash)
|
75
|
+
hash.collect { |k, v| [k.to_s, v] }.to_h
|
76
|
+
end
|
77
|
+
|
78
|
+
# If the item path is already present *somewhere* in the manifest it will not be merged in, regardless of any differences in the generated and existing item summary. This is intentional to prevent manual changes from being overwritten. Merged in items will be grouped into a group name matching the item name; if an existing group cannot be identified, they will be put into a special placeholder group.
|
79
|
+
def merge_items_into(items, existing)
|
80
|
+
updated = []
|
81
|
+
placed = []
|
82
|
+
# placed_into_placeholder_group = []
|
83
|
+
|
84
|
+
items.each do |item|
|
85
|
+
placeholder_group = nil
|
86
|
+
if placeholder_group = existing_manifest_group_for(item['name'], existing)
|
87
|
+
# It already exists. Great.
|
88
|
+
elsif placeholder_group = existing_manifest_group_for(item['name'], existing)
|
89
|
+
# The placeholder group has already been created. Yay.
|
90
|
+
else
|
91
|
+
placeholder_group = rekey(
|
92
|
+
'name': item['name'],
|
93
|
+
'status': 'generated',
|
94
|
+
'items': []
|
95
|
+
)
|
96
|
+
puts "Adding placeholder group to manifest: #{placeholder_group}"
|
97
|
+
existing['groups'] << placeholder_group
|
98
|
+
end
|
99
|
+
|
100
|
+
if existing_item = existing_manifest_item_for(item, existing)
|
101
|
+
# Updated security object only
|
102
|
+
# byebug
|
103
|
+
existing_item['security'] = item['security']
|
104
|
+
updated << existing_item
|
105
|
+
else
|
106
|
+
existing_group = existing_manifest_group_for(item['name'], existing)
|
107
|
+
# Just drop the item into the existing group.
|
108
|
+
improveify_name!(item)
|
109
|
+
# puts "#{item['name']} (#{item['path']})"
|
110
|
+
existing_group['items'] << item
|
111
|
+
placed << item
|
112
|
+
# else
|
113
|
+
# # No group in the existing manifest appears to be a fit, so put the item into a placeholder group.
|
114
|
+
# placeholder_group['items'] << item
|
115
|
+
# placed_into_placeholder_group << item
|
116
|
+
end
|
117
|
+
end
|
118
|
+
[updated, placed]
|
119
|
+
end
|
120
|
+
|
121
|
+
def report(updated, placed)
|
122
|
+
puts "\nFiles updated as already present in the manifest: #{updated.length}"
|
123
|
+
# updated.each do |n| puts "\t#{n['path']} (#{n['name']})" end
|
124
|
+
puts "Placed into a group: #{placed.length}"
|
125
|
+
placed.each { |n| puts "\t#{[n['path'], n['url']].join(' ')}" }
|
126
|
+
# puts "\nPut into a placeholder group:#{placed_into_placeholder_group.length}"
|
127
|
+
# placed_into_placeholder_group.each do |n| puts "\t#{n['path']}" end
|
128
|
+
end
|
129
|
+
|
130
|
+
def write_to_file(path, existing)
|
131
|
+
file = File.open(path, 'w')
|
132
|
+
file.write(JSON.pretty_generate(existing))
|
133
|
+
file.close
|
134
|
+
end
|
135
|
+
|
136
|
+
if ARGV.length != 3
|
137
|
+
puts HELP
|
138
|
+
exit 1
|
139
|
+
else
|
140
|
+
file = File.read(ARGV[1])
|
141
|
+
existing = JSON.parse(file)
|
142
|
+
items = content_directory_to_item_tree(ARGV[0])
|
143
|
+
updated, placed = merge_items_into(items, existing)
|
144
|
+
report(updated, placed)
|
145
|
+
write_to_file(ARGV[2], existing)
|
146
|
+
exit 0
|
147
|
+
end
|
data/knartform.gemspec
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
Gem::Specification.new do |s|
|
2
|
+
s.name = 'knartform'
|
3
|
+
s.version = '0.6.0'
|
4
|
+
s.summary = "HL7 CDS Knowledge Artifacts"
|
5
|
+
s.description = "Tools form working with HL7 CDS Knowledge Artifacts."
|
6
|
+
s.authors = ["Preston Lee"]
|
7
|
+
s.email = 'preston.lee@prestonlee.com'
|
8
|
+
s.homepage = 'https://github.com/preston/knartform'
|
9
|
+
s.license = 'MIT'
|
10
|
+
|
11
|
+
s.files = `git ls-files`.split("\n")
|
12
|
+
s.executables = s.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
13
|
+
s.test_files = s.files.grep(%r{^(test|spec|features)/})
|
14
|
+
s.require_paths = ['lib']
|
15
|
+
|
16
|
+
s.add_dependency 'nokogiri'
|
17
|
+
s.add_dependency 'httparty'
|
18
|
+
s.add_dependency 'slim'
|
19
|
+
|
20
|
+
s.add_development_dependency 'bundler'
|
21
|
+
s.add_development_dependency 'rake'
|
22
|
+
s.add_development_dependency 'minitest'
|
23
|
+
end
|
data/lib/common.rb
ADDED
@@ -0,0 +1,264 @@
|
|
1
|
+
# require 'xml/libxml'
|
2
|
+
require 'digest'
|
3
|
+
|
4
|
+
module Repository
|
5
|
+
SUPPORTED_MIME_TYPES = {
|
6
|
+
"application/pdf": {name: "PDF", expression: /\.pdf$/i},
|
7
|
+
"text/html": {name: "HTML", expression: /\.html?$/i},
|
8
|
+
"application/vnd.openxmlformats-officedocument.wordprocessingml.document":
|
9
|
+
{name: "Word", expression: /\.docx?$/i},
|
10
|
+
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet":
|
11
|
+
{name: "Excel", expression: /\.xlsx?$/i},
|
12
|
+
"application/hl7-cds-knowledge-artifact-1.3+xml": {name: 'HL7 KNART v1.3', expression: /KRprt(?!_CRCK).*\.xml$/i},
|
13
|
+
"application/docbook": {name: 'DocBook', expression: /(HIMKWP|KVRpt|CSD).*\.xml$/i},
|
14
|
+
'application/hl7-cds-knowledge-artifact-composite+xml': {name: 'Composite Artifact', expression: /CRCK_.*\.xml$/i},
|
15
|
+
'image/svg+xml': {name: "SVG Image", expression: /\.svg$/i}
|
16
|
+
}
|
17
|
+
|
18
|
+
KNART_MIME_TYPES = [
|
19
|
+
"application/hl7-cds-knowledge-artifact-1.3+xml"
|
20
|
+
]
|
21
|
+
|
22
|
+
COMPOSITE_MIME_TYPES = [
|
23
|
+
'application/hl7-cds-knowledge-artifact-composite+xml'
|
24
|
+
]
|
25
|
+
|
26
|
+
|
27
|
+
DIGRAPH_TEMPLATE = <<TEMPLATE
|
28
|
+
digraph {
|
29
|
+
<% artifacts.each do |a| %>
|
30
|
+
artifact_<%= a[:hash] %>[label="<%= a[:name] %>\n<%= a[:file] %>", shape=rounded, style=filled, fillcolor=lightblue]<% end %>
|
31
|
+
|
32
|
+
<% events.each do |k, v| %>
|
33
|
+
event_<%= v %>[label="<%= k %>", style=filled, fillcolor=yellow]<% end %>
|
34
|
+
|
35
|
+
<% artifacts.each do |a| %><% a[:emits].each do |e| %>
|
36
|
+
artifact_<%= a[:hash] %> -> event_<%= events[e[:name]] %>[fontsize=8, label="emits\n<%= e[:conditions] %>"]<% end %><% end %>
|
37
|
+
<% artifacts.each do |a| %><% a[:triggers].each do |t| %>
|
38
|
+
event_<%= events[t] %> -> artifact_<%= a[:hash] %>[label="triggers"]<% end %><% end %>
|
39
|
+
}
|
40
|
+
TEMPLATE
|
41
|
+
|
42
|
+
def generate_dot(doc)
|
43
|
+
artifacts = []
|
44
|
+
events = {}
|
45
|
+
doc.xpath('//xmlns:containedArtifacts/xmlns:artifact').each do |a|
|
46
|
+
name = a.xpath('./xmlns:name/@value').to_s
|
47
|
+
file = a.xpath('./xmlns:reference/xmlns:url/@address').to_s
|
48
|
+
file = '(embedded)' if file.empty?
|
49
|
+
triggers = []
|
50
|
+
emits = []
|
51
|
+
tmp = {
|
52
|
+
name: name,
|
53
|
+
hash: Digest::SHA1.hexdigest(name),
|
54
|
+
file: file,
|
55
|
+
triggers: triggers,
|
56
|
+
emits: emits
|
57
|
+
}
|
58
|
+
artifacts << tmp
|
59
|
+
|
60
|
+
# Search for triggers
|
61
|
+
# puts a
|
62
|
+
a.xpath('.//xmlns:triggers/xmlns:trigger/@onEventName').each do |t|
|
63
|
+
value = t.to_s
|
64
|
+
triggers << value
|
65
|
+
events[value] = Digest::SHA1.hexdigest(value)
|
66
|
+
end
|
67
|
+
|
68
|
+
# Emmitted events within embedded KNARTs.
|
69
|
+
a.xpath('./xmlns:knowledgeDocument//xmlns:simpleAction[@xsi:type="FireEventAction"]').each do |action|
|
70
|
+
conditions = action.xpath('./xmlns:conditions').to_s.gsub('"', '\"')
|
71
|
+
# puts conditions
|
72
|
+
action.xpath('.//elm:element[@name="EventName"]/elm:value/@value').each do |n|
|
73
|
+
value = n.to_s
|
74
|
+
emits << {
|
75
|
+
name: value,
|
76
|
+
conditions: conditions
|
77
|
+
}
|
78
|
+
events[value] = Digest::SHA1.hexdigest(value)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
# Emmitted events for referencesd KNARTs.
|
83
|
+
a.xpath('./xmlns:onCompletion//xmlns:eventName/@name').each do |n|
|
84
|
+
value = n.to_s
|
85
|
+
emits << {
|
86
|
+
name: value,
|
87
|
+
conditions: '(always)'
|
88
|
+
}
|
89
|
+
events[value] = Digest::SHA1.hexdigest(value)
|
90
|
+
end
|
91
|
+
|
92
|
+
|
93
|
+
end
|
94
|
+
# puts artifacts
|
95
|
+
# puts events
|
96
|
+
renderer = ERB.new(DIGRAPH_TEMPLATE)
|
97
|
+
renderer.result(binding)
|
98
|
+
end
|
99
|
+
|
100
|
+
# Forces keys to strings.
|
101
|
+
def rekey(hash)
|
102
|
+
hash.collect{|k,v| [k.to_s, v]}.to_h
|
103
|
+
end
|
104
|
+
|
105
|
+
def mimeTypeForFile(path)
|
106
|
+
mimeType = nil
|
107
|
+
SUPPORTED_MIME_TYPES.each do |k,v|
|
108
|
+
if v[:expression].match?(path)
|
109
|
+
mimeType = k
|
110
|
+
break
|
111
|
+
end
|
112
|
+
end
|
113
|
+
# puts mimeType || path
|
114
|
+
mimeType
|
115
|
+
end
|
116
|
+
|
117
|
+
def content_directory_to_item_tree(root)
|
118
|
+
content = []
|
119
|
+
list = Dir["#{root}/**/**"]
|
120
|
+
list.each do |n|
|
121
|
+
# puts n
|
122
|
+
if(File.file?(n))
|
123
|
+
# ext = File.extname(n).downcase[1..-1]
|
124
|
+
mimeType = mimeTypeForFile(n)
|
125
|
+
name = n.split('/')[1] #.split['.'][0]
|
126
|
+
name = name.split('_').collect(&:capitalize).join(' ')
|
127
|
+
tags = n.split('/').select{|d| d.length <= 4}
|
128
|
+
# Add subdirectory names to the tag list
|
129
|
+
subs = Dir.glob(File.dirname(n) + '/*').select{ |t|
|
130
|
+
puts t
|
131
|
+
# puts File.directory?(t)
|
132
|
+
# puts File.dirname(n) != t
|
133
|
+
# byebug
|
134
|
+
File.directory?(t) && n != t
|
135
|
+
}.collect{ |t| File.basename(t)}
|
136
|
+
puts "#{n} SUBS: #{subs}"
|
137
|
+
tags |= subs
|
138
|
+
if mimeType # it's a supported piece of content
|
139
|
+
item = {
|
140
|
+
'name': name,
|
141
|
+
'path': n,
|
142
|
+
'mimeType': mimeType,
|
143
|
+
'tags': tags
|
144
|
+
}
|
145
|
+
update_security(item)
|
146
|
+
item = rekey(item)
|
147
|
+
# Any directory name of 4 characters or less will be treated as a tag automatically
|
148
|
+
content << item
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|
152
|
+
content
|
153
|
+
end
|
154
|
+
|
155
|
+
def update_security(item)
|
156
|
+
# byebug
|
157
|
+
content = File.read(item[:path])
|
158
|
+
item['security'] = rekey({
|
159
|
+
sha1: Digest::SHA1.hexdigest(content),
|
160
|
+
sha256: Digest::SHA256.hexdigest(content),
|
161
|
+
md5: Digest::MD5.hexdigest(content)
|
162
|
+
})
|
163
|
+
puts item
|
164
|
+
end
|
165
|
+
|
166
|
+
def audit_content_directory(root, manifest)
|
167
|
+
good = []
|
168
|
+
bad = []
|
169
|
+
manifest['groups'].each do |group|
|
170
|
+
group['items'].each do |item|
|
171
|
+
if item['path']
|
172
|
+
path = "#{root}/#{item['path']}"
|
173
|
+
if File.exist? path
|
174
|
+
good << item
|
175
|
+
else
|
176
|
+
bad << item
|
177
|
+
end
|
178
|
+
end
|
179
|
+
begin
|
180
|
+
if item['url']
|
181
|
+
response = HTTParty.head(item['url'])
|
182
|
+
if(response.code >= 400)
|
183
|
+
bad << item
|
184
|
+
else
|
185
|
+
good << item
|
186
|
+
end
|
187
|
+
end
|
188
|
+
rescue SocketError => e
|
189
|
+
# Probably a bad DNS or protocol name.
|
190
|
+
bad << item
|
191
|
+
end
|
192
|
+
end
|
193
|
+
end
|
194
|
+
return [good, bad]
|
195
|
+
|
196
|
+
end
|
197
|
+
|
198
|
+
def render_partial(name, stuff)
|
199
|
+
template = File.join(File.dirname(File.expand_path(__FILE__)), name)
|
200
|
+
Slim::Template.new(template).render(self, stuff)
|
201
|
+
end
|
202
|
+
|
203
|
+
end
|
204
|
+
|
205
|
+
# USAGE: Hash.from_xml(YOUR_XML_STRING)require 'rubygems'
|
206
|
+
require 'nokogiri'
|
207
|
+
# modified from http://stackoverflow.com/questions/1230741/convert-a-nokogiri-document-to-a-ruby-hash/1231297#1231297
|
208
|
+
|
209
|
+
class Hash
|
210
|
+
class << self
|
211
|
+
def from_xml(xml_io)
|
212
|
+
begin
|
213
|
+
result = Nokogiri::XML(xml_io)
|
214
|
+
return { result.root.name.to_sym => xml_node_to_hash(result.root)}
|
215
|
+
rescue Exception => e
|
216
|
+
# raise your custom exception here
|
217
|
+
end
|
218
|
+
end
|
219
|
+
|
220
|
+
def xml_node_to_hash(node)
|
221
|
+
# If we are at the root of the document, start the hash
|
222
|
+
if node.element?
|
223
|
+
result_hash = {}
|
224
|
+
if node.attributes != {}
|
225
|
+
attributes = {}
|
226
|
+
node.attributes.keys.each do |key|
|
227
|
+
attributes[node.attributes[key].name.to_sym] = node.attributes[key].value
|
228
|
+
end
|
229
|
+
end
|
230
|
+
if node.children.size > 0
|
231
|
+
node.children.each do |child|
|
232
|
+
result = xml_node_to_hash(child)
|
233
|
+
|
234
|
+
if child.name == "text"
|
235
|
+
unless child.next_sibling || child.previous_sibling
|
236
|
+
return result unless attributes
|
237
|
+
result_hash[child.name.to_sym] = result
|
238
|
+
end
|
239
|
+
elsif result_hash[child.name.to_sym]
|
240
|
+
|
241
|
+
if result_hash[child.name.to_sym].is_a?(Object::Array)
|
242
|
+
result_hash[child.name.to_sym] << result
|
243
|
+
else
|
244
|
+
result_hash[child.name.to_sym] = [result_hash[child.name.to_sym]] << result
|
245
|
+
end
|
246
|
+
else
|
247
|
+
result_hash[child.name.to_sym] = result
|
248
|
+
end
|
249
|
+
end
|
250
|
+
if attributes
|
251
|
+
#add code to remove non-data attributes e.g. xml schema, namespace here
|
252
|
+
#if there is a collision then node content supersets attributes
|
253
|
+
result_hash = attributes.merge(result_hash)
|
254
|
+
end
|
255
|
+
return result_hash
|
256
|
+
else
|
257
|
+
return attributes
|
258
|
+
end
|
259
|
+
else
|
260
|
+
return node.content.to_s
|
261
|
+
end
|
262
|
+
end
|
263
|
+
end
|
264
|
+
end
|