yahl7 0.1.0 → 0.3.2

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.
Files changed (39) hide show
  1. checksums.yaml +4 -4
  2. data/.github/ISSUE_TEMPLATE/bug_report.md +47 -0
  3. data/.github/ISSUE_TEMPLATE/feature_request.md +27 -0
  4. data/.github/dependabot.yml +7 -0
  5. data/CHANGELOG.md +64 -0
  6. data/CODE_OF_CONDUCT.md +74 -25
  7. data/CONTRIBUTING.md +47 -0
  8. data/README.md +19 -3
  9. data/lib/yahl7/v2/{segment_field_names.rb → alias_field_names.rb} +14 -7
  10. data/lib/yahl7/v2/alias_person_name.rb +65 -0
  11. data/lib/yahl7/v2/data_type/cnn.rb +29 -0
  12. data/lib/yahl7/v2/data_type/dt.rb +28 -0
  13. data/lib/yahl7/v2/data_type/ft.rb +26 -0
  14. data/lib/yahl7/v2/data_type/ndl.rb +30 -0
  15. data/lib/yahl7/v2/data_type/ts.rb +24 -0
  16. data/lib/yahl7/v2/data_type/xad.rb +31 -0
  17. data/lib/yahl7/v2/data_type/xpn.rb +40 -0
  18. data/lib/yahl7/v2/data_type/xtn.rb +29 -0
  19. data/lib/yahl7/v2/data_type.rb +20 -0
  20. data/lib/yahl7/v2/date_time.rb +1 -1
  21. data/lib/yahl7/v2/error/invalid_format_error.rb +12 -0
  22. data/lib/yahl7/v2/message/adt.rb +2 -0
  23. data/lib/yahl7/v2/message/oru.rb +1 -0
  24. data/lib/yahl7/v2/message.rb +10 -0
  25. data/lib/yahl7/v2/segment/al1.rb +21 -0
  26. data/lib/yahl7/v2/segment/dg1.rb +36 -0
  27. data/lib/yahl7/v2/segment/evn.rb +23 -0
  28. data/lib/yahl7/v2/segment/in1.rb +68 -0
  29. data/lib/yahl7/v2/segment/msh.rb +4 -2
  30. data/lib/yahl7/v2/segment/nte.rb +3 -2
  31. data/lib/yahl7/v2/segment/obr.rb +13 -12
  32. data/lib/yahl7/v2/segment/obx.rb +11 -5
  33. data/lib/yahl7/v2/segment/orc.rb +8 -7
  34. data/lib/yahl7/v2/segment/pd1.rb +36 -0
  35. data/lib/yahl7/v2/segment/pid.rb +11 -10
  36. data/lib/yahl7/v2/segment/pv1.rb +7 -6
  37. data/lib/yahl7/v2.rb +6 -1
  38. data/lib/yahl7/version.rb +1 -1
  39. metadata +23 -3
@@ -0,0 +1,65 @@
1
+ # frozen_string_literal: true
2
+
3
+ module YAHL7
4
+ module V2
5
+ # This module can be included into a class of a data type that includes the
6
+ # name components in order to add an `#assemble_name_family_first` method
7
+ # and an `#assemble_name_given_first` method.
8
+ module AliasPersonName
9
+ # This is the method the builds the "bare" name (i.e., without prefixes
10
+ # and/or suffixes) with the family name first.
11
+ def bare_name_family_first
12
+ buf = family_name.nil? || family_name == '' ? '' : "#{family_name}, "
13
+ buf += "#{given_name} " unless given_name.nil? || given_name == ''
14
+ buf += middle_name unless middle_name.nil? || middle_name == ''
15
+
16
+ buf.strip
17
+ end
18
+
19
+ # This is the method the builds the "bare" name (i.e., without prefixes
20
+ # and/or suffixes) with the given name first.
21
+ def bare_name_given_first
22
+ [given_name, middle_name, family_name]
23
+ .reject { |p| p.nil? || p == '' }
24
+ .join(' ')
25
+ end
26
+
27
+ # This is the method that builds the full name (i.e., with prefixes and/or
28
+ # suffixes) with the family name first.
29
+ def assemble_name_family_first
30
+ buf = prefix.nil? || prefix == '' ? '' : "#{prefix} "
31
+ buf += bare_name_family_first
32
+
33
+ s = suffixes
34
+ buf += ", #{s}" unless s == ''
35
+
36
+ buf
37
+ end
38
+
39
+ # We have two locations for suffix information on a name:
40
+ #
41
+ # 1. The suffix, which is meant to house information like Jr, II, etc.
42
+ # 2. The degree, which is meant to house information like MD, PhD, etc.
43
+ #
44
+ # This method is used to combine those into a single value to make name
45
+ # assembly easier.
46
+ def suffixes
47
+ [suffix, degree]
48
+ .reject { |p| p.nil? || p == '' }
49
+ .join(', ')
50
+ end
51
+
52
+ # This is the method that builds the full name (i.e., with prefixes and/or
53
+ # suffixes) with the given name first.
54
+ def assemble_name_given_first
55
+ buf = prefix.nil? || prefix == '' ? '' : "#{prefix} "
56
+ buf += bare_name_given_first
57
+
58
+ s = suffixes
59
+ buf += ", #{s}" unless s == ''
60
+
61
+ buf
62
+ end
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'date'
4
+
5
+ module YAHL7
6
+ module V2
7
+ class DataType
8
+ # This is the HL7 data type for a composite name and ID number.
9
+ class CNN < YAHL7::V2::DataType
10
+ include YAHL7::V2::AliasPersonName
11
+ include YAHL7::V2::AliasFieldNames
12
+
13
+ define_field_names({
14
+ id_number: 0,
15
+ family_name: 1,
16
+ given_name: 2,
17
+ middle_name: 3,
18
+ suffix: 4,
19
+ prefix: 5,
20
+ degree: 6,
21
+ source_table: 7,
22
+ assigning_authority_namespace_id: 8,
23
+ assigning_authority_universal_id: 9,
24
+ assigning_authority_universal_id_type: 10
25
+ })
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'date'
4
+
5
+ module YAHL7
6
+ module V2
7
+ class DataType
8
+ # This is the HL7 data type for a single date. This should be in the
9
+ # format of YYYY[MM[DD]]
10
+ class DT < YAHL7::V2::DataType
11
+ def date
12
+ @date ||= parse_date
13
+ end
14
+
15
+ private
16
+
17
+ def parse_date
18
+ case @value.length
19
+ when 4 then Date.parse("#{@value}0101")
20
+ when 6 then Date.parse("#{@value}01")
21
+ when 8 then Date.parse(@value)
22
+ else raise YAHL7::V2::Error::InvalidFormatError, 'Unknown date format'
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'date'
4
+
5
+ module YAHL7
6
+ module V2
7
+ class DataType
8
+ # This is the HL7 data type for formatted text
9
+ class FT < YAHL7::V2::DataType
10
+ def formatted
11
+ @formatted ||= parse_value
12
+ end
13
+
14
+ private
15
+
16
+ def parse_value
17
+ value.is_a?(Array) ? value.map { |v| parse_body(v) }.join("\n") : parse_body(value)
18
+ end
19
+
20
+ def parse_body(body)
21
+ YAHL7::V2::Formatter.format(body)
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'date'
4
+
5
+ require_relative 'ts'
6
+
7
+ module YAHL7
8
+ module V2
9
+ class DataType
10
+ # This is the HL7 data type for a name with a date and location.
11
+ class NDL < YAHL7::V2::DataType
12
+ include YAHL7::V2::AliasFieldNames
13
+
14
+ define_field_names({
15
+ name: { index: 0, class: YAHL7::V2::DataType::CNN },
16
+ start_datetime: { index: 1, class: YAHL7::V2::DataType::TS },
17
+ end_datetime: { index: 2, class: YAHL7::V2::DataType::TS },
18
+ point_of_care: 3,
19
+ room: 4,
20
+ bed: 5,
21
+ facility: 6,
22
+ location_status: 7,
23
+ patient_location_type: 8,
24
+ building: 9,
25
+ floor: 10
26
+ })
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'date'
4
+
5
+ module YAHL7
6
+ module V2
7
+ class DataType
8
+ # This is the HL7 data type for a timestamp with a format of
9
+ # YYYY[MM[DD[HH[MM[SS[.S[S[S[S]]]]]]]]][+/-ZZZZ]
10
+ class TS < YAHL7::V2::DataType
11
+ def timestamp
12
+ @timestamp ||= parse_timestamp
13
+ end
14
+
15
+ private
16
+
17
+ def parse_timestamp
18
+ timestamp = @value.is_a?(Array) ? @value.first : @value
19
+ YAHL7::V2::DateTime.parse(timestamp)
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'date'
4
+
5
+ module YAHL7
6
+ module V2
7
+ class DataType
8
+ # This is the HL7 data type for an extended address.
9
+ class XAD < YAHL7::V2::DataType
10
+ include YAHL7::V2::AliasFieldNames
11
+
12
+ define_field_names({
13
+ street_address: 0,
14
+ other_designation: 1,
15
+ city: 2,
16
+ state: 3,
17
+ zip: 4,
18
+ country: 5,
19
+ address_type: 6,
20
+ other_geographic_designation: 7,
21
+ county_code: 8,
22
+ census_tract: 9,
23
+ address_representation_code: 10,
24
+ address_validity_range: 11,
25
+ effective_date: { index: 12, class: YAHL7::V2::DataType::TS },
26
+ expiration_date: { index: 13, class: YAHL7::V2::DataType::TS }
27
+ })
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'date'
4
+
5
+ module YAHL7
6
+ module V2
7
+ class DataType
8
+ # This is the HL7 data type for an extended person name. This is the data
9
+ # type used for patient names, etc.
10
+ class XPN < YAHL7::V2::DataType
11
+ include YAHL7::V2::AliasPersonName
12
+ include YAHL7::V2::AliasFieldNames
13
+
14
+ define_field_names({
15
+ family_name: 0,
16
+ given_name: 1,
17
+ middle_name: 2,
18
+ suffix: 3,
19
+ prefix: 4,
20
+ degree: 5,
21
+ name_type_code: 6,
22
+ name_representation_code: 7,
23
+ name_context: 8,
24
+ name_validity_range: 9,
25
+ name_assembly_order: 10,
26
+ effective_date: 11,
27
+ expiration_date: 12,
28
+ professional_suffix: 13
29
+ })
30
+
31
+ def full_name
32
+ case name_assembly_order&.downcase
33
+ when 'f' then assemble_name_family_first
34
+ else assemble_name_given_first
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'date'
4
+
5
+ module YAHL7
6
+ module V2
7
+ class DataType
8
+ # This is the HL7 data type for an extended telephone number.
9
+ class XTN < YAHL7::V2::DataType
10
+ include YAHL7::V2::AliasFieldNames
11
+
12
+ define_field_names({
13
+ telephone_number: 0,
14
+ telephone_use_code: 1,
15
+ telephone_equipment_type: 2,
16
+ email_address: 3,
17
+ country_code: 4,
18
+ area_city_code: 5,
19
+ local_number: 6,
20
+ extension: 7,
21
+ any_text: 8,
22
+ extension_prefix: 9,
23
+ speed_dial_code: 10,
24
+ unformatted_telephone_number: 11
25
+ })
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ Dir[File.join(__dir__, 'data_type', '*.rb')].sort.each { |f| require f }
4
+
5
+ module YAHL7
6
+ module V2
7
+ # This is the base data type class for custom HL7 data types.
8
+ class DataType
9
+ attr_accessor :value
10
+
11
+ def initialize(value)
12
+ @value = value
13
+ end
14
+
15
+ def [](index)
16
+ value[index]
17
+ end
18
+ end
19
+ end
20
+ end
@@ -21,7 +21,7 @@ module YAHL7
21
21
  timezone = parts[1]
22
22
 
23
23
  format = timestamp_format(timestamp)
24
- raise 'Unknown timestamp format' if format.nil?
24
+ raise YAHL7::V2::Error::InvalidFormatError, 'Unknown timestamp format' if format.nil?
25
25
 
26
26
  format += '%z' unless timezone.nil?
27
27
  ::DateTime.strptime(value, format)
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ module YAHL7
4
+ module V2
5
+ module Error
6
+ # This error is raised when the input for a given data type is implausible
7
+ # or otherwise invalid.
8
+ class InvalidFormatError < StandardError
9
+ end
10
+ end
11
+ end
12
+ end
@@ -3,6 +3,8 @@
3
3
  module YAHL7
4
4
  module V2
5
5
  class Message
6
+ # ADT messages contain admit, discharge, and transfer information about
7
+ # patients.
6
8
  class ADT < YAHL7::V2::Message
7
9
  end
8
10
  end
@@ -3,6 +3,7 @@
3
3
  module YAHL7
4
4
  module V2
5
5
  class Message
6
+ # ORU messages contain unsolicited observation results about a patient.
6
7
  class ORU < YAHL7::V2::Message
7
8
  end
8
9
  end
@@ -17,6 +17,10 @@ module YAHL7
17
17
  .map { |s| Segment.parse(s, parse_options) }
18
18
  end
19
19
 
20
+ def to_s
21
+ @to_s ||= segments.join(parse_options.segment_sep)
22
+ end
23
+
20
24
  def [](index)
21
25
  case index
22
26
  when Integer then segments[index]
@@ -41,9 +45,15 @@ module YAHL7
41
45
  # information, as this method simply finds the type code and then hands it
42
46
  # off to `get_message_class` to find the class to use.
43
47
  def self.message_type(body, parse_options = nil)
48
+ return self if body.length < 8
49
+
44
50
  parse_options ||= ParseOptions.from_body(body)
45
51
  head = body.split(parse_options.segment_sep)[0]
52
+ return self if head.nil?
53
+
46
54
  type = head.split(parse_options.repetition_sep)[8]
55
+ return self if type.nil?
56
+
47
57
  code = type.split(parse_options.component_sep)[0]
48
58
  get_message_class(code)
49
59
  end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module YAHL7
4
+ module V2
5
+ class Segment
6
+ # AL1 segments contain patient allergy information.
7
+ class AL1 < YAHL7::V2::Segment
8
+ include YAHL7::V2::AliasFieldNames
9
+
10
+ define_field_names({
11
+ set_id: 1,
12
+ allergen_type_code: 2,
13
+ allergen_code: 3,
14
+ allergen_severity_code: 4,
15
+ allergen_reaction_code: 5,
16
+ identification_date: { index: 6, class: YAHL7::V2::DataType::DT }
17
+ })
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ module YAHL7
4
+ module V2
5
+ class Segment
6
+ # DG1 segments contain patient diagnosis information.
7
+ class DG1 < YAHL7::V2::Segment
8
+ include YAHL7::V2::AliasFieldNames
9
+
10
+ define_field_names({
11
+ set_id: 1,
12
+ diagnosis_code_method: 2,
13
+ diagnosis_code: 3,
14
+ diagnosis_description: 4,
15
+ diagnosis_datetime: { index: 5, class: YAHL7::V2::DataType::TS },
16
+ diagnosis_type: 6,
17
+ major_diagnosis_category: 7,
18
+ diagnostic_related_group: 8,
19
+ drg_approval_indicator: 9,
20
+ drg_grouper_review_code: 10,
21
+ outlier_type: 11,
22
+ outlier_days: 12,
23
+ outlier_cost: 13,
24
+ grouper_version_and_type: 14,
25
+ diagnostic_priority: 15,
26
+ diagnosing_clinician: 16,
27
+ diagnosis_classification: 17,
28
+ confidential_indicator: 18,
29
+ attestation_datetime: { index: 19, class: YAHL7::V2::DataType::TS },
30
+ diagnosis_identifier: 20,
31
+ diagnosis_action_code: 21
32
+ })
33
+ end
34
+ end
35
+ end
36
+ end