Class: Etna::Clients::Magma::ModelsOdmXml::Exporter
- Inherits:
-
Object
- Object
- Etna::Clients::Magma::ModelsOdmXml::Exporter
- Includes:
- Prettify
- Defined in:
- lib/etna/clients/magma/formatting/models_odm_xml.rb
Instance Attribute Summary collapse
-
#models ⇒ Object
readonly
Returns the value of attribute models.
-
#project_name ⇒ Object
readonly
Returns the value of attribute project_name.
Instance Method Summary collapse
- #clinical_dictionaries ⇒ Object
- #data_type_map ⇒ Object
- #global_variables(xml) ⇒ Object
-
#initialize(project_name:, models:) ⇒ Exporter
constructor
A new instance of Exporter.
- #metadata(xml) ⇒ Object
- #odm_headers ⇒ Object
- #redcap_field_type_map ⇒ Object
- #redcap_text_validation_map ⇒ Object
- #repeating_attribute_types ⇒ Object
- #repeating_instruments(xml) ⇒ Object
- #write_code_list(xml, dictionary) ⇒ Object
- #write_form_def(xml, dictionary) ⇒ Object
- #write_item_def(xml, dictionary) ⇒ Object
- #write_item_group_def(xml, dictionary) ⇒ Object
- #write_models(output_io: nil, filename: nil) ⇒ Object
- #write_repeating_instrument_xml(xml, instrument) ⇒ Object
Methods included from Prettify
Constructor Details
#initialize(project_name:, models:) ⇒ Exporter
Returns a new instance of Exporter.
31 32 33 34 |
# File 'lib/etna/clients/magma/formatting/models_odm_xml.rb', line 31 def initialize(project_name:, models:) @project_name = project_name @models = models end |
Instance Attribute Details
#models ⇒ Object (readonly)
Returns the value of attribute models.
29 30 31 |
# File 'lib/etna/clients/magma/formatting/models_odm_xml.rb', line 29 def models @models end |
#project_name ⇒ Object (readonly)
Returns the value of attribute project_name.
29 30 31 |
# File 'lib/etna/clients/magma/formatting/models_odm_xml.rb', line 29 def project_name @project_name end |
Instance Method Details
#clinical_dictionaries ⇒ Object
145 146 147 148 149 150 151 152 153 |
# File 'lib/etna/clients/magma/formatting/models_odm_xml.rb', line 145 def clinical_dictionaries # Our indicator for if something needs a REDCap form will be any # model with a dictionary. models.all.select do |model| model.template.raw['dictionary'] end.map do |model| model.template.dictionary end end |
#data_type_map ⇒ Object
36 37 38 39 40 41 42 43 44 45 46 47 |
# File 'lib/etna/clients/magma/formatting/models_odm_xml.rb', line 36 def data_type_map @data_type_map ||= begin map = {} map[Etna::Clients::Magma::AttributeType::STRING] = 'text' map[Etna::Clients::Magma::AttributeType::DATE_TIME] = 'date' map[Etna::Clients::Magma::AttributeType::BOOLEAN] = 'text' map[Etna::Clients::Magma::AttributeType::FLOAT] = 'float' map[Etna::Clients::Magma::AttributeType::INTEGER] = 'integer' map end end |
#global_variables(xml) ⇒ Object
104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 |
# File 'lib/etna/clients/magma/formatting/models_odm_xml.rb', line 104 def global_variables(xml) # Includes general metadata about the project, as well as # declarations of all repeating instruments, # which seem like Timepoints to me. # NOTE: # <redcap:Purpose>0</redcap:Purpose> # 0 = Practice / just for fun # 1 = Operational Support # 2 = Research # 3 = Quality Improvement # 4 = Other xml.GlobalVariables do xml.StudyName "#{project_name}" xml.StudyDescription "#{project_name} - Data Library integration project" xml.ProtocolName "#{project_name}" xml.send('redcap:RecordAutonumberingEnabled', 1) xml.send('redcap:CustomRecordLabel') xml.send('redcap:SecondaryUniqueField') xml.send('redcap:SchedulingEnabled', 0) xml.send('redcap:SurveysEnabled', 0) xml.send('redcap:SurveyInvitationEmailField') xml.send('redcap:Purpose', 2) # 2 == research xml.send('redcap:PurposeOther') xml.send('redcap:ProjectNotes', "Used to easily ingest clinical data for #{project_name} into the Data Library.") xml.send('redcap:MissingDataCodes') repeating_instruments(xml) end end |
#metadata(xml) ⇒ Object
176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 |
# File 'lib/etna/clients/magma/formatting/models_odm_xml.rb', line 176 def (xml) # Includes form and field definitions xml.MetaDataVersion( OID: "Metadata.#{shorten(project_name)}_#{DateTime.now}", Name: project_name, 'redcap:RecordIdField': 'record_id' ) do clinical_dictionaries.map do |dictionary| # Each Magma dictionary needs a FormDef, with # ItemGroupRef children for each form page (?). # Each ItemGroupRef requires a corresponding ItemGroupDef # with ItemRef children for each input (?). # Each ItemRef requires a correspdonding ItemDef # that defines the label and type, and includes # <Question> as a label (?). # Option validations are present as a CodeList (with # CodeListItem children). write_form_def(xml, dictionary) write_item_group_def(xml, dictionary) write_item_def(xml, dictionary) write_code_list(xml, dictionary) end end end |
#odm_headers ⇒ Object
86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 |
# File 'lib/etna/clients/magma/formatting/models_odm_xml.rb', line 86 def odm_headers { xmlns: "http://www.cdisc.org/ns/odm/v1.3", 'xmlns:ds': "http://www.w3.org/2000/09/xmldsig#", 'xmlns:xsi': "http://www.w3.org/2001/XMLSchema-instance", 'xmlns:redcap': "https://projectredcap.org", 'xsi:schemaLocation': "http://www.cdisc.org/ns/odm/v1.3 schema/odm/ODM1-3-1.xsd", ODMVersion: "1.3.2", FileOID: "000-00-0000", FileType: "Snapshot", Description: project_name, AsOfDateTime: DateTime.now, CreationDateTime: DateTime.now, SourceSystem: "Magma", SourceSystemVersion: DateTime.now } end |
#redcap_field_type_map ⇒ Object
49 50 51 52 53 54 55 56 57 58 59 60 |
# File 'lib/etna/clients/magma/formatting/models_odm_xml.rb', line 49 def redcap_field_type_map @redcap_field_type_map ||= begin map = {} map[Etna::Clients::Magma::AttributeType::STRING] = 'textarea' map[Etna::Clients::Magma::AttributeType::DATE_TIME] = 'text' map[Etna::Clients::Magma::AttributeType::BOOLEAN] = 'radio' map[Etna::Clients::Magma::AttributeType::FLOAT] = 'text' map[Etna::Clients::Magma::AttributeType::INTEGER] = 'text' map end end |
#redcap_text_validation_map ⇒ Object
62 63 64 65 66 67 68 69 70 71 |
# File 'lib/etna/clients/magma/formatting/models_odm_xml.rb', line 62 def redcap_text_validation_map @redcap_text_validation_map ||= begin map = {} map[Etna::Clients::Magma::AttributeType::DATE_TIME] = 'date_mdy' map[Etna::Clients::Magma::AttributeType::FLOAT] = 'float' map[Etna::Clients::Magma::AttributeType::INTEGER] = 'int' map end end |
#repeating_attribute_types ⇒ Object
135 136 137 138 139 140 141 142 143 |
# File 'lib/etna/clients/magma/formatting/models_odm_xml.rb', line 135 def repeating_attribute_types # We don't have a good indicator for what is a repeating # attribute for REDCap... # Will this work for models without timepoint, that go # straight from subject -> sample? models.model('subject').template.attributes.all.select do |attribute| Etna::Clients::Magma::AttributeType::COLLECTION == attribute.attribute_type end end |
#repeating_instruments(xml) ⇒ Object
155 156 157 158 159 160 161 162 163 164 165 |
# File 'lib/etna/clients/magma/formatting/models_odm_xml.rb', line 155 def repeating_instruments(xml) # Now we get into repeating instruments and events. # From a Magma model perspective, this should be # Timepoint that hangs off of # a Subject model. xml.send('redcap:RepeatingInstrumentsAndEvents') do repeating_attribute_types.map do |repeating_attribute| write_repeating_instrument_xml(xml, repeating_attribute) end end end |
#write_code_list(xml, dictionary) ⇒ Object
265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 |
# File 'lib/etna/clients/magma/formatting/models_odm_xml.rb', line 265 def write_code_list(xml, dictionary) model_attributes = models.model(dictionary.model_name).template.attributes dictionary.attributes.keys.map do |attribute_name| attribute = model_attributes.attribute(attribute_name) if attribute.validation && Etna::Clients::Magma::AttributeValidationType::ARRAY == attribute.validation['type'] xml.CodeList( OID: "#{dictionary.model_name}.#{attribute_name}.choices", Name: "#{attribute_name}", DataType: "text", 'redcap:Variable': attribute_name ) do attribute.validation['value'].map do |option| xml.CodeListItem( CodedValue: option ) do xml.Decode() do xml.send('TranslatedText', option) end end end end end end end |
#write_form_def(xml, dictionary) ⇒ Object
201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 |
# File 'lib/etna/clients/magma/formatting/models_odm_xml.rb', line 201 def write_form_def(xml, dictionary) xml.FormDef( OID: "Form.#{dictionary.model_name}", Name: dictionary.model_name.capitalize, Repeating: "No", 'redcap:FormName': dictionary.model_name ) do # Assume a single item group xml.ItemGroupRef( ItemGroupOID: "#{dictionary.model_name}.attributes", Mandatory: "No" ) do end end end |
#write_item_def(xml, dictionary) ⇒ Object
234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 |
# File 'lib/etna/clients/magma/formatting/models_odm_xml.rb', line 234 def write_item_def(xml, dictionary) model_attributes = models.model(dictionary.model_name).template.attributes dictionary.attributes.keys.map do |attribute_name| attribute = model_attributes.attribute(attribute_name) attribute_type = attribute.attribute_type params = { OID: "#{dictionary.model_name}.#{attribute_name}", # Does this need to be unique across all items? Name: attribute_name, DataType: data_type_map[attribute_type] || 'text', 'redcap:Variable': attribute_name, 'redcap:FieldType': redcap_field_type_map[attribute_type] || 'text', Length: '999' # How could we infer shorter values? } params['redcap:TextValidationType'] = redcap_text_validation_map[attribute_type] if redcap_text_validation_map[attribute_type] params['redcap:FieldNote'] = attribute.desc if attribute.desc xml.ItemDef(params) do xml.Question do xml.send('TranslatedText', attribute_name.capitalize) end if attribute.validation && Etna::Clients::Magma::AttributeValidationType::ARRAY == attribute.validation['type'] xml.CodeListRef( CodeListOID: "#{dictionary.model_name}.#{attribute_name}.choices" ) do end end end end end |
#write_item_group_def(xml, dictionary) ⇒ Object
217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 |
# File 'lib/etna/clients/magma/formatting/models_odm_xml.rb', line 217 def write_item_group_def(xml, dictionary) xml.ItemGroupDef( OID: "#{dictionary.model_name}.attributes", Name: "#{dictionary.model_name.capitalize} Attributes", Repeating: "No" ) do dictionary.attributes.keys.map do |attribute_name| xml.ItemRef( ItemOID: "#{dictionary.model_name}.#{attribute_name}", # Does this need to be unique across all items? Mandatory: "No", 'redcap:Variable': attribute_name # Does this need to be unique? ) do end end end end |
#write_models(output_io: nil, filename: nil) ⇒ Object
73 74 75 76 77 78 79 80 81 82 83 84 |
# File 'lib/etna/clients/magma/formatting/models_odm_xml.rb', line 73 def write_models(output_io: nil, filename: nil) @document = Nokogiri::XML::Builder.new(encoding: 'UTF-8') do |xml| xml.ODM(odm_headers) do xml.Study(OID: "Project.#{shorten(project_name)}") do end global_variables(xml) (xml) end end @document.to_xml end |
#write_repeating_instrument_xml(xml, instrument) ⇒ Object
167 168 169 170 171 172 173 174 |
# File 'lib/etna/clients/magma/formatting/models_odm_xml.rb', line 167 def write_repeating_instrument_xml(xml, instrument) node = xml.send('redcap:RepeatingInstrument') node['redcap:UniqueEventName'] = 'event_1_arm_1' node['redcap:RepeatInstrument'] = instrument.attribute_name node['redcap:CustomLabel'] = instrument.display_name || instrument.attribute_name.capitalize node end |