test-patient-generator 1.0.2 → 1.1.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.
- data/Gemfile +6 -8
- data/lib/test-patient-generator.rb +1 -6
- data/lib/tpg/ext/coded.rb +9 -3
- data/lib/tpg/ext/data_criteria.rb +150 -142
- data/lib/tpg/ext/range.rb +2 -132
- data/lib/tpg/ext/value.rb +21 -82
- data/lib/tpg/generation/exporter.rb +14 -32
- data/lib/tpg/generation/generator.rb +158 -84
- data/lib/tpg/generation/randomizer.rb +17 -30
- metadata +83 -9
- data/lib/tpg/ext/conjunction.rb +0 -23
- data/lib/tpg/ext/derivation_operator.rb +0 -49
- data/lib/tpg/ext/population_criteria.rb +0 -12
- data/lib/tpg/ext/precondition.rb +0 -23
- data/lib/tpg/ext/subset_operator.rb +0 -7
- data/lib/tpg/ext/temporal_reference.rb +0 -66
data/Gemfile
CHANGED
@@ -1,15 +1,13 @@
|
|
1
1
|
source "http://rubygems.org"
|
2
2
|
|
3
|
-
|
4
|
-
gem 'hquery-patient-api', '~> 0.3.0'
|
5
|
-
gem 'hqmf2js', '~> 1.0.1'
|
6
|
-
gem 'health-data-standards', '~> 2.1.4'
|
3
|
+
gemspec
|
7
4
|
|
8
5
|
gem 'rake'
|
9
|
-
gem 'pry'
|
10
|
-
gem 'pry-nav'
|
11
|
-
gem 'bson_ext'
|
12
6
|
|
13
7
|
group :test do
|
14
8
|
gem 'simplecov'
|
15
|
-
|
9
|
+
gem 'turn'
|
10
|
+
gem 'pry'
|
11
|
+
gem 'pry-nav'
|
12
|
+
gem 'pry-stack_explorer'
|
13
|
+
end
|
@@ -1,16 +1,11 @@
|
|
1
1
|
require 'hqmf-parser'
|
2
2
|
require 'health-data-standards'
|
3
|
+
require 'qrda_generator'
|
3
4
|
|
4
5
|
require_relative 'tpg/ext/coded'
|
5
|
-
require_relative 'tpg/ext/conjunction'
|
6
6
|
require_relative 'tpg/ext/data_criteria'
|
7
|
-
require_relative 'tpg/ext/derivation_operator'
|
8
|
-
require_relative 'tpg/ext/population_criteria'
|
9
|
-
require_relative 'tpg/ext/precondition'
|
10
7
|
require_relative 'tpg/ext/range'
|
11
8
|
require_relative 'tpg/ext/record'
|
12
|
-
require_relative 'tpg/ext/subset_operator'
|
13
|
-
require_relative 'tpg/ext/temporal_reference'
|
14
9
|
require_relative 'tpg/ext/value'
|
15
10
|
|
16
11
|
require_relative 'tpg/generation/generator'
|
data/lib/tpg/ext/coded.rb
CHANGED
@@ -15,6 +15,11 @@ module HQMF
|
|
15
15
|
code_sets
|
16
16
|
end
|
17
17
|
|
18
|
+
# Filter through a list of value sets and choose only the ones marked with a given OID.
|
19
|
+
#
|
20
|
+
# @param [String] oid The OID being used for filtering.
|
21
|
+
# @param [Array] value_sets A pool of available value sets
|
22
|
+
# @return The value set from the list with the requested OID.
|
18
23
|
def self.select_value_sets(oid, value_sets)
|
19
24
|
# Pick the value set for this DataCriteria. If it can't be found, it is an error from the value set source. We'll add the entry without codes for now.
|
20
25
|
index = value_sets.index{|value_set| value_set["oid"] == oid}
|
@@ -30,10 +35,11 @@ module HQMF
|
|
30
35
|
# @return A Hash including a code and code system containing one randomly selected code.
|
31
36
|
def self.select_code(oid, value_sets)
|
32
37
|
codes = select_codes(oid, value_sets)
|
33
|
-
|
38
|
+
code_system = codes.keys()[0]
|
39
|
+
return nil if code_system.nil?
|
34
40
|
{
|
35
|
-
'
|
36
|
-
'code' => codes[
|
41
|
+
'code_system' => code_system,
|
42
|
+
'code' => codes[code_system][0]
|
37
43
|
}
|
38
44
|
end
|
39
45
|
end
|
@@ -1,163 +1,171 @@
|
|
1
1
|
module HQMF
|
2
2
|
class DataCriteria
|
3
|
-
attr_accessor :
|
4
|
-
|
5
|
-
#
|
6
|
-
#
|
7
|
-
#
|
8
|
-
# @param [
|
9
|
-
# @
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
3
|
+
attr_accessor :values
|
4
|
+
|
5
|
+
# Modify a Record with this data criteria.
|
6
|
+
#
|
7
|
+
# @param [Record] patient The Record that is being modified.
|
8
|
+
# @param [Range] time The period of time during which the data criteria happens.
|
9
|
+
# @param [Hash] value_sets The value sets that this data criteria references.
|
10
|
+
# @return The modified patient.
|
11
|
+
def modify_patient(patient, time, value_sets)
|
12
|
+
# Modify the patient with a characteristic if this data criteria defines one
|
13
|
+
modify_patient_with_characteristic(patient, time, value_sets)
|
14
|
+
|
15
|
+
# Otherwise we're dealing with a data criteria that describes a coded entry, so we create it and add it to the patient
|
16
|
+
entry = derive_entry(time, value_sets)
|
17
|
+
modify_entry_with_values(entry, value_sets)
|
18
|
+
modify_entry_with_negation(entry, value_sets)
|
19
|
+
modify_entry_with_fields(entry, value_sets)
|
20
|
+
modify_patient_with_entry(patient, entry)
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
# Modify a Record with a data criteria that describes a patient characteristic.
|
26
|
+
#
|
27
|
+
# @param [Record] patient The Record that is being modified.
|
28
|
+
# @param [Range] time The period of time during which the data criteria happens.
|
29
|
+
# @param [Hash] value_sets The value sets that this data criteria references.
|
30
|
+
# @return The modified patient.
|
31
|
+
def modify_patient_with_characteristic(patient, time, value_sets)
|
32
|
+
return nil unless characteristic?
|
33
|
+
|
34
|
+
if property == :birthtime
|
35
|
+
patient.birthdate = time.low.to_seconds
|
36
|
+
elsif property == :gender
|
37
|
+
gender = value.code
|
38
|
+
patient.gender = gender
|
39
|
+
patient.first = Randomizer.randomize_first_name(gender)
|
40
|
+
elsif property == :clinicalTrialParticipant
|
41
|
+
patient.clinicalTrialParticipant = true
|
42
|
+
elsif property == :expired
|
43
|
+
patient.expired = true
|
44
|
+
patient.deathdate = time.high.to_seconds
|
33
45
|
end
|
34
|
-
|
35
|
-
# Set the acceptable ranges for this data criteria so any parents can read it
|
36
|
-
@generation_range = acceptable_times
|
46
|
+
end
|
37
47
|
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
+
# Determine the apporpriate coded entry type from this data criteria and create one to match.
|
49
|
+
#
|
50
|
+
# @param [Range] time The period of time during which the entry happens.
|
51
|
+
# @param [Hash] value_sets The value sets that this data criteria references.
|
52
|
+
# @return A coded entry with basic data defined by this data criteria.
|
53
|
+
def derive_entry(time, value_sets)
|
54
|
+
return nil if characteristic?
|
55
|
+
|
56
|
+
entry_type = Generator.classify_entry(patient_api_function)
|
57
|
+
entry = entry_type.classify.constantize.new
|
58
|
+
entry.description = "#{description} (Code List: #{code_list_id})"
|
59
|
+
entry.start_time = time.low.to_seconds if time.low
|
60
|
+
entry.end_time = time.high.to_seconds if time.high
|
61
|
+
entry.status = status
|
62
|
+
entry.codes = Coded.select_codes(code_list_id, value_sets)
|
63
|
+
entry.oid = HQMF::DataCriteria.template_id_for_definition(definition, status, negation)
|
64
|
+
entry
|
65
|
+
end
|
66
|
+
|
67
|
+
# Add any value related data to a coded entry from this data criteria.
|
68
|
+
#
|
69
|
+
# @param [Entry] entry The coded entry that this data criteria is defining.
|
70
|
+
# @param [Hash] value_sets The value sets that this data criteria references.
|
71
|
+
# @return The modified coded entry.
|
72
|
+
def modify_entry_with_values(entry, value_sets)
|
73
|
+
return nil unless entry.present? && values.present?
|
74
|
+
|
75
|
+
# If the value itself has a code, it will be a Coded type. Otherwise, it's just a regular value with a unit.
|
76
|
+
entry.values ||= []
|
77
|
+
values.each do |value|
|
78
|
+
if value.type == "CD"
|
79
|
+
entry.values << CodedResultValue.new({codes: Coded.select_codes(value.code_list_id, value_sets), description: HQMF::Coded.select_value_sets(value.code_list_id, value_sets)["concept"]})
|
80
|
+
else
|
81
|
+
entry.values << PhysicalQuantityResultValue.new(value.format)
|
48
82
|
end
|
49
83
|
end
|
50
|
-
|
51
|
-
base_patients
|
52
84
|
end
|
53
|
-
|
54
|
-
#
|
85
|
+
|
86
|
+
# Mark a coded entry as negated if this data criteria describes it as such.
|
55
87
|
#
|
56
|
-
# @param [
|
57
|
-
# @param [
|
58
|
-
|
88
|
+
# @param [Entry] entry The coded entry that this data criteria is potentially negating.
|
89
|
+
# @param [Hash] value_sets The value sets that this data criteria references.
|
90
|
+
# @return The modified coded entry.
|
91
|
+
def modify_entry_with_negation(entry, value_sets)
|
92
|
+
return nil unless entry.present? && negation && negation_code_list_id.present?
|
59
93
|
|
94
|
+
entry.negation_ind = true
|
95
|
+
entry.negation_reason = Coded.select_code(negation_code_list_id, value_sets)
|
60
96
|
end
|
61
|
-
|
62
|
-
#
|
97
|
+
|
98
|
+
# Add this data criteria's field related data to a coded entry.
|
63
99
|
#
|
64
|
-
# @param [
|
65
|
-
# @param [Range] time An acceptable range of times for the coded entry being put on this patient.
|
100
|
+
# @param [Entry] entry The coded entry that this data criteria is modifying.
|
66
101
|
# @param [Hash] value_sets The value sets that this data criteria references.
|
67
|
-
# @return The modified
|
68
|
-
def
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
if
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
else
|
81
|
-
# Otherwise this is a regular coded entry. Start by choosing the correct type and assigning basic metadata.
|
82
|
-
entry_type = Generator.classify_entry(patient_api_function)
|
83
|
-
|
84
|
-
# HACK -- this is here to deal with types that have not been mapped yet and blow things up
|
85
|
-
return patient if entry_type.nil? || entry_type == ""
|
86
|
-
entry = entry_type.classify.constantize.new
|
87
|
-
|
88
|
-
entry.description = "#{description} (Code List: #{code_list_id})"
|
89
|
-
entry.start_time = time.low.to_seconds if time.low
|
90
|
-
entry.end_time = time.high.to_seconds if time.high
|
91
|
-
entry.status = status
|
92
|
-
entry.codes = Coded.select_codes(code_list_id, value_sets)
|
93
|
-
entry.oid = HQMF::DataCriteria.template_id_for_definition(definition, status, negation)
|
94
|
-
|
95
|
-
# If the value itself has a code, it will be a Coded type. Otherwise, it's just a regular value with a unit.
|
96
|
-
if value.present? && !value.is_a?(AnyValue)
|
97
|
-
entry.values ||= []
|
98
|
-
if value.type == "CD"
|
99
|
-
entry.values << CodedResultValue.new({codes: Coded.select_codes(value.code_list_id, value_sets)})
|
100
|
-
else
|
101
|
-
entry.values << PhysicalQuantityResultValue.new(value.format)
|
102
|
-
end
|
103
|
-
end
|
104
|
-
|
105
|
-
if values.present?
|
106
|
-
entry.values ||= []
|
107
|
-
values.each do |value|
|
108
|
-
if value.type == "CD"
|
109
|
-
entry.values << CodedResultValue.new({codes: Coded.select_codes(value.code_list_id, value_sets), description: Coded.select_value_sets(value.code_list_id, value_sets)['description']})
|
110
|
-
else
|
111
|
-
entry.values << PhysicalQuantityResultValue.new(value.format)
|
112
|
-
end
|
113
|
-
end
|
102
|
+
# @return The modified coded entry.
|
103
|
+
def modify_entry_with_fields(entry, value_sets)
|
104
|
+
return nil unless entry.present? && field_values.present?
|
105
|
+
|
106
|
+
field_values.each do |name, field|
|
107
|
+
next if field.nil?
|
108
|
+
|
109
|
+
# Format the field to be stored in a Record.
|
110
|
+
if field.type == "CD"
|
111
|
+
field_value = Coded.select_code(field.code_list_id, value_sets)
|
112
|
+
field_value["title"] = HQMF::Coded.select_value_sets(field.code_list_id, value_sets)["concept"]
|
113
|
+
else
|
114
|
+
field_value = field.format
|
114
115
|
end
|
115
116
|
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
117
|
+
field_accessor = nil
|
118
|
+
# Facilities are a special case where we store a whole object on the entry in Record. Create or augment the existing facility with this piece of data.
|
119
|
+
if name.include? "FACILITY"
|
120
|
+
facility = entry.facility
|
121
|
+
facility ||= Facility.new
|
122
|
+
facility_map = {"FACILITY_LOCATION" => :code, "FACILITY_LOCATION_ARRIVAL_DATETIME" => :start_time, "FACILITY_LOCATION_DEPARTURE_DATETIME" => :end_time}
|
123
|
+
|
124
|
+
facility.name = field.title if type == "CD"
|
125
|
+
facility_accessor = facility_map[name]
|
126
|
+
facility.send("#{facility_accessor}=", field_value)
|
127
|
+
|
128
|
+
field_accessor = :facility
|
129
|
+
field_value = facility
|
120
130
|
end
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
value = field.format
|
132
|
-
end
|
133
|
-
|
134
|
-
case name
|
135
|
-
when "ORDINAL"
|
136
|
-
entry.ordinality_code = codes
|
137
|
-
when "FACILITY_LOCATION"
|
138
|
-
entry.facility = Facility.new("name" => field.title, "codes" => codes)
|
139
|
-
when "CUMULATIVE_MEDICATION_DURATION"
|
140
|
-
entry.cumulative_medication_duration = value
|
141
|
-
when "SEVERITY"
|
142
|
-
entry.severity = codes
|
143
|
-
when "REASON"
|
144
|
-
|
145
|
-
when "SOURCE"
|
146
|
-
|
147
|
-
end
|
131
|
+
|
132
|
+
begin
|
133
|
+
field_accessor ||= HQMF::DataCriteria::FIELDS[name][:coded_entry_method]
|
134
|
+
entry.send("#{field_accessor}=", field_value)
|
135
|
+
rescue
|
136
|
+
# Give some feedback if we hit an unexpected error. Some fields have no action expected, so we'll suppress those messages.
|
137
|
+
noop_fields = ["LENGTH_OF_STAY", "START_DATETIME", "STOP_DATETIME"]
|
138
|
+
unless noop_fields.include? name
|
139
|
+
field_accessor = HQMF::DataCriteria::FIELDS[name][:coded_entry_method]
|
140
|
+
puts "Unknown field #{name} was unable to be added via #{field_accessor} to the patient"
|
148
141
|
end
|
149
142
|
end
|
150
|
-
|
151
|
-
# Figure out which section this entry will be added to. Some entry names don't map prettily to section names.
|
152
|
-
section_map = { "lab_results" => "results" }
|
153
|
-
section_name = section_map[entry_type]
|
154
|
-
section_name ||= entry_type
|
155
|
-
# Add the updated section to this patient.
|
156
|
-
section = patient.send(section_name)
|
157
|
-
section.push(entry)
|
158
|
-
|
159
|
-
patient
|
160
143
|
end
|
161
144
|
end
|
145
|
+
|
146
|
+
# Add a coded entry to a patient.
|
147
|
+
#
|
148
|
+
# @param [Record] patient The coded entry that this data criteria is potentially negating.
|
149
|
+
# @param [Entry] entry The value sets that this data criteria references.
|
150
|
+
# @return The modified patient.
|
151
|
+
def modify_patient_with_entry(patient, entry)
|
152
|
+
return patient if entry.nil?
|
153
|
+
|
154
|
+
# Figure out which section this entry will be added to. Some entry names don't map prettily to section names.
|
155
|
+
entry_type = Generator.classify_entry(patient_api_function)
|
156
|
+
section_map = { "lab_results" => "results" }
|
157
|
+
section_name = section_map[entry_type]
|
158
|
+
section_name ||= entry_type
|
159
|
+
|
160
|
+
# Add the updated section to this patient.
|
161
|
+
section = patient.send(section_name)
|
162
|
+
section.push(entry)
|
163
|
+
|
164
|
+
patient
|
165
|
+
end
|
166
|
+
|
167
|
+
def characteristic?
|
168
|
+
type == :characteristic && patient_api_function.nil? ? true : false
|
169
|
+
end
|
162
170
|
end
|
163
171
|
end
|
data/lib/tpg/ext/range.rb
CHANGED
@@ -1,144 +1,14 @@
|
|
1
1
|
module HQMF
|
2
2
|
class Range
|
3
|
-
#
|
4
|
-
#
|
5
|
-
# @return A deep copy of this Range.
|
6
|
-
def clone
|
7
|
-
Range.new(type.try(:clone), low.try(:clone), high.try(:clone), width.try(:clone))
|
8
|
-
end
|
9
|
-
|
3
|
+
# Form an HQMF Range object into a shape that HealthDataStandards understands.
|
10
4
|
#
|
5
|
+
# @return A Range formatted for storing a HealthDataStandards Record.
|
11
6
|
def format
|
12
7
|
if low
|
13
8
|
low.format
|
14
9
|
elsif high
|
15
10
|
high.format
|
16
|
-
else
|
17
|
-
{}
|
18
|
-
end
|
19
|
-
end
|
20
|
-
|
21
|
-
# Perform an intersection between this Range and the passed in Range.
|
22
|
-
# There are three potential situations that can happen: disjoint, equivalent, or overlapping.
|
23
|
-
#
|
24
|
-
# @param [Range] range The other Range intersecting this. If it is nil it implies all times are ok (i.e. no restrictions).
|
25
|
-
# @return A new Range that represents the shared amount of time between these two Ranges. nil means there is no common time.
|
26
|
-
def intersection(range)
|
27
|
-
# Return self if nil (the other range has no restrictions) or if it matches the other range (they are equivalent)
|
28
|
-
return self.clone if range.nil?
|
29
|
-
return self.clone if eql?(range)
|
30
|
-
|
31
|
-
# Figure out which range starts later (the more restrictive one)
|
32
|
-
if low <= range.low
|
33
|
-
earlier_start = self
|
34
|
-
later_start = range
|
35
|
-
else
|
36
|
-
earlier_start = range
|
37
|
-
later_start = self
|
38
|
-
end
|
39
|
-
|
40
|
-
# Return nil if there is no common time (the two ranges are entirely disjoint)
|
41
|
-
return nil unless later_start.contains?(earlier_start.high)
|
42
|
-
|
43
|
-
# Figure out which ranges ends earlier (the more restrictive one)
|
44
|
-
if high >= range.high
|
45
|
-
earlier_end = self
|
46
|
-
later_end = range
|
47
|
-
else
|
48
|
-
earlier_end = range
|
49
|
-
later_end = self
|
50
|
-
end
|
51
|
-
|
52
|
-
Range.new("TS", later_start.low.clone, earlier_end.high.clone, nil)
|
53
|
-
end
|
54
|
-
|
55
|
-
# Perform a union between this Range and the passed in Range.
|
56
|
-
# There are three potential situations that can happen: disjoint, equivalent, or overlapping.
|
57
|
-
#
|
58
|
-
# @param [Range] range The other Range unioning this.
|
59
|
-
# @return An array of Ranges. One element if the two ranges are overlapping and can be expressed as one new Range
|
60
|
-
# or two Ranges if the times are disjoint.
|
61
|
-
def union(range)
|
62
|
-
# Return self if nil (nothing new to add) or if it matches the other range (they are equivalent)
|
63
|
-
return self.clone if range.nil?
|
64
|
-
return self.clone if eql?(range)
|
65
|
-
|
66
|
-
# Figure out which range starts earlier (to capture the most time)
|
67
|
-
if low <= range.low
|
68
|
-
earlier_start = self
|
69
|
-
later_start = range
|
70
|
-
else
|
71
|
-
earlier_start = range
|
72
|
-
later_start = self
|
73
|
-
end
|
74
|
-
|
75
|
-
# Figure out which ranges ends earlier (the more restrictive one)
|
76
|
-
if high >= range.high
|
77
|
-
earlier_end = self
|
78
|
-
later_end = range
|
79
|
-
else
|
80
|
-
earlier_end = range
|
81
|
-
later_end = self
|
82
11
|
end
|
83
|
-
|
84
|
-
result = []
|
85
|
-
# We have continuous Ranges so we can return one Range to encapsulate both
|
86
|
-
if earlier_start.contains?(later_start.low)
|
87
|
-
result << Range.new("TS", earlier_start.low.clone, later_end.high.clone, nil)
|
88
|
-
else
|
89
|
-
# The Ranges are disjoint, so we'll need to return two arrays to capture all of the potential times
|
90
|
-
result << Range.new("TS", earlier_start.low.clone, earlier_start.high.clone, nil)
|
91
|
-
result << Range.new("TS", later_start.low.clone, later_start.high.clone, nil)
|
92
|
-
end
|
93
|
-
end
|
94
|
-
|
95
|
-
#
|
96
|
-
#
|
97
|
-
# @param [Range] ivl_pq
|
98
|
-
# @return
|
99
|
-
def apply_pq(ivl_pq)
|
100
|
-
|
101
|
-
end
|
102
|
-
|
103
|
-
#
|
104
|
-
#
|
105
|
-
# @param [Range] range1
|
106
|
-
# @param [Range] range2
|
107
|
-
# @return
|
108
|
-
def self.merge_ranges(range1, range2)
|
109
|
-
return nil if range1.nil? && range2.nil?
|
110
|
-
return range1 if range2.nil?
|
111
|
-
return range2 if range1.nil?
|
112
|
-
|
113
|
-
type = range1.type == "PQ" && range2.type == "PQ" ? "IVL_PQ" : "IVL_TS"
|
114
|
-
low = Value.merge_values(range1.low, range2.low)
|
115
|
-
high = Value.merge_values(range1.high, range2.high)
|
116
|
-
width = nil
|
117
|
-
|
118
|
-
Range.new(type, low, high, width)
|
119
|
-
end
|
120
|
-
|
121
|
-
# Check to see if a given value falls within this Range's high and low.
|
122
|
-
#
|
123
|
-
# @param [Value] value The value that may or may not fall within the range.
|
124
|
-
# @return True if the value is contained. Otherwise, false.
|
125
|
-
def contains?(value)
|
126
|
-
start_time = low.to_time_object
|
127
|
-
end_time = high.to_time_object
|
128
|
-
time = value.to_time_object
|
129
|
-
|
130
|
-
time.between?(start_time, end_time)
|
131
|
-
end
|
132
|
-
|
133
|
-
# Check to see if a given Range's low and high matches this' low and high.
|
134
|
-
#
|
135
|
-
# @param [Range] range The Range to which we're comparing.
|
136
|
-
# @return True if the given range starts and ends at the same time as this. Otherwise, false.
|
137
|
-
def eql?(range)
|
138
|
-
return false if range.nil? || low.nil? || range.low.nil? || high.nil? || range.high.nil?
|
139
|
-
|
140
|
-
return low.value == range.low.value && low.inclusive? == range.low.inclusive? &&
|
141
|
-
high.value == range.high.value && high.inclusive? == range.high.inclusive?
|
142
12
|
end
|
143
13
|
end
|
144
14
|
end
|