Class: NcsNavigator::Mdes::Variable

Inherits:
Object
  • Object
show all
Defined in:
lib/ncs_navigator/mdes/variable.rb

Overview

A single field in the MDES. A relational model might also call this a column, but "variable" is what it's called in the MDES.

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(name) ⇒ Variable

Returns a new instance of Variable.



110
111
112
# File 'lib/ncs_navigator/mdes/variable.rb', line 110

def initialize(name)
  @name = name
end

Instance Attribute Details

#nameString (readonly)

Returns the name of the variable.

Returns:

  • (String)

    the name of the variable



10
11
12
# File 'lib/ncs_navigator/mdes/variable.rb', line 10

def name
  @name
end

#nillableBoolean Also known as: nillable?

May the variable be submitted as a null value?

Returns:

  • (Boolean)


45
46
47
# File 'lib/ncs_navigator/mdes/variable.rb', line 45

def nillable
  @nillable
end

#omittableBoolean Also known as: omittable?

If the variable does not have a value, should it be completely omitted when submitting to the VDR?

Returns:

  • (Boolean)


38
39
40
# File 'lib/ncs_navigator/mdes/variable.rb', line 38

def omittable
  @omittable
end

#piiBoolean, ...

Returns the PII category for the variable. true if it is definitely PII, false if it definitely is not, :possible if it was marked in the MDES as requiring manual review, :unknown if the MDES does not specify, or a string if the parsed value was not mappable to one of the above. Note that this value will always be truthy unless the MDES explicitly says that the variable is not PII.

Returns:

  • (Boolean, :possible, :unknown, String)

    the PII category for the variable. true if it is definitely PII, false if it definitely is not, :possible if it was marked in the MDES as requiring manual review, :unknown if the MDES does not specify, or a string if the parsed value was not mappable to one of the above. Note that this value will always be truthy unless the MDES explicitly says that the variable is not PII.



20
21
22
# File 'lib/ncs_navigator/mdes/variable.rb', line 20

def pii
  @pii
end

#required=(value) ⇒ Boolean? (writeonly)

Allows for an override of the default logic. Mostly intended for testing. Set to nil to restore default logic.

Returns:

  • (Boolean, nil)


53
54
55
# File 'lib/ncs_navigator/mdes/variable.rb', line 53

def required=(value)
  @required = value
end

#status:active, ...

Returns the status of the variable in this version of the MDES. A String is returned if the source value doesn't match any of the expected values in the MDES.

Returns:

  • (:active, :new, :modified, :retired, String)

    the status of the variable in this version of the MDES. A String is returned if the source value doesn't match any of the expected values in the MDES.



27
28
29
# File 'lib/ncs_navigator/mdes/variable.rb', line 27

def status
  @status
end

#table_referenceTransmissionTable?

If this variable is a foreign key, this is the table to which it refers.

Returns:



60
61
62
# File 'lib/ncs_navigator/mdes/variable.rb', line 60

def table_reference
  @table_reference
end

#typeVariableType

Returns the type of this variable.

Returns:



31
32
33
# File 'lib/ncs_navigator/mdes/variable.rb', line 31

def type
  @type
end

Class Method Details

.from_element(element, options = {}) ⇒ Variable

Examines the given parsed element and creates a new variable. The resulting variable has all the attributes set which can be set without reference to any other parts of the MDES outside of this one variable definition.

Parameters:

  • element (Nokogiri::Element)

    the source xs:element

Returns:

  • (Variable)

    a new variable instance



71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
# File 'lib/ncs_navigator/mdes/variable.rb', line 71

def from_element(element, options={})
  log = options[:log] || NcsNavigator::Mdes.default_logger

  new(element['name']).tap do |var|
    var.nillable = element['nillable'] == 'true'
    var.omittable = element['minOccurs'] == '0'
    var.pii =
      case element['pii']
      when 'Y'; true;
      when 'P'; :possible;
      when nil; :unknown;
      when '';  false;
      else element['pii'];
      end
    var.status =
      case element['status']
      when '1'; :active;
      when '2'; :new;
      when '3'; :modified;
      when '4'; :retired;
      else element['status'];
      end
    var.type =
      if element['type']
        if element['type'] =~ /^xs:/
          VariableType.xml_schema_type(element['type'].sub(/^xs:/, ''))
        else
          VariableType.reference(element['type'])
        end
      elsif element.elements.collect { |e| e.name } == %w(simpleType)
        VariableType.from_xsd_simple_type(element.elements.first, options)
      else
        log.warn("Could not determine a type for variable #{var.name.inspect} on line #{element.line}")
        nil
      end
  end
end

Instance Method Details

#constraintsObject



114
115
116
# File 'lib/ncs_navigator/mdes/variable.rb', line 114

def constraints
  @constraints ||= []
end

#required?Boolean Also known as: required

Is a value for the variable mandatory for a valid submission?

Returns:

  • (Boolean)


122
123
124
125
126
127
128
# File 'lib/ncs_navigator/mdes/variable.rb', line 122

def required?
  if @required.nil?
    !(omittable? || nillable?)
  else
    @required
  end
end

#resolve_foreign_key!(tables, override_name = nil, options = {})

This method returns an undefined value.

Attempts to resolve this variable as a reference to another table. There are two mechanisms for performing the resolution:

  1. If an override_name is provided, that table will be looked up in the provided table list. If it exists, it will be used, otherwise nothing will be set.
  2. If the type of this variable is one of the NCS FK types and there exists exactly one table in tables whose primary key has the same name as this variable, that table will be used.

Alternatively, to suppress the heuristics without providing a replacement, pass false as the override_name

Parameters:

  • tables (Array<TransmissionTable>)

    the tables to search for a parent.

  • override_name (String, nil) (defaults to: nil)

    the name of a table to use as the parent. Supplying a value in this parameter bypasses the search heuristic.



176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
# File 'lib/ncs_navigator/mdes/variable.rb', line 176

def resolve_foreign_key!(tables, override_name=nil, options={})
  log = options[:log] || NcsNavigator::Mdes.default_logger
  source_table = options[:in_table] ? options[:in_table].name : '[unspecified table]'

  case override_name
  when String
    self.table_reference = tables.detect { |t| t.name == override_name }
    unless table_reference
      log.warn("Foreign key #{name.inspect} in #{source_table} explicitly mapped " <<
        "to unknown table #{override_name.inspect}.")
    end
  when nil
    return unless (self.type && self.type.name =~ /^foreignKey/)

    candidates = tables.select do |t|
      t.variables.detect { |v| (v.name == name) && (v.type && (v.type.name =~ /^primaryKey/)) }
    end

    case candidates.size
    when 0
      log.warn("Foreign key in #{source_table} not resolvable: " <<
        "no tables have a primary key named #{name.inspect}.")
    when 1
      self.table_reference = candidates.first
    else
      log.warn(
        "#{candidates.size} possible parent tables found for foreign key #{name.inspect} " <<
        "in #{source_table}: #{candidates.collect { |c| c.name.inspect }.join(', ')}. " <<
        "None used due to ambiguity.")
    end
  end
end

#resolve_type!(types, options = {})

This method returns an undefined value.

If the #type of this instance is a reference to an NCS type, attempts to replace it with the full version from the given list of types.

Parameters:



138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
# File 'lib/ncs_navigator/mdes/variable.rb', line 138

def resolve_type!(types, options={})
  log = options[:log] || NcsNavigator::Mdes.default_logger

  return unless type && type.reference?
  unless type.name =~ /^ncs:/
    log.warn("Unknown reference namespace in type #{type.name.inspect} for #{name}")
  end

  ncs_type_name = type.name.sub(/^ncs:/, '')
  match = types.find { |t| t.name == ncs_type_name }
  if match
    self.type = match
  else
    log.warn("Undefined type #{type.name} for #{name}.") if log
  end
end