rtp-connect 1.6 → 1.11
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/{CHANGELOG.rdoc → CHANGELOG.md} +137 -90
- data/COPYING +674 -674
- data/Gemfile +2 -2
- data/Gemfile.lock +31 -21
- data/README.md +161 -0
- data/lib/rtp-connect.rb +1 -0
- data/lib/rtp-connect/constants.rb +58 -57
- data/lib/rtp-connect/control_point.rb +158 -118
- data/lib/rtp-connect/dose_tracking.rb +37 -54
- data/lib/rtp-connect/extended_field.rb +36 -69
- data/lib/rtp-connect/extended_plan.rb +127 -0
- data/lib/rtp-connect/field.rb +158 -143
- data/lib/rtp-connect/methods.rb +85 -62
- data/lib/rtp-connect/plan.rb +645 -636
- data/lib/rtp-connect/plan_to_dcm.rb +668 -694
- data/lib/rtp-connect/prescription.rb +57 -74
- data/lib/rtp-connect/record.rb +225 -57
- data/lib/rtp-connect/ruby_extensions.rb +34 -3
- data/lib/rtp-connect/simulation_field.rb +606 -701
- data/lib/rtp-connect/site_setup.rb +112 -80
- data/lib/rtp-connect/version.rb +5 -5
- data/rakefile.rb +0 -1
- data/rtp-connect.gemspec +27 -27
- metadata +67 -58
- data/README.rdoc +0 -136
data/lib/rtp-connect/methods.rb
CHANGED
@@ -1,63 +1,86 @@
|
|
1
|
-
module RTP
|
2
|
-
|
3
|
-
class << self
|
4
|
-
|
5
|
-
#--
|
6
|
-
# Module methods:
|
7
|
-
#++
|
8
|
-
|
9
|
-
# Gives an array of MLC leaf position boundaries for a given type of MLC,
|
10
|
-
# specified by its number of leaves at one side.
|
11
|
-
#
|
12
|
-
# @param [Fixnum] nr_leaves the number of leaves (in one leaf bank)
|
13
|
-
# @return [Array<Fixnum>] the leaf boundary positions
|
14
|
-
# @raise [ArgumentError] if an unsupported MLC (nr of leaves) is given
|
15
|
-
#
|
16
|
-
def leaf_boundaries(nr_leaves)
|
17
|
-
case nr_leaves
|
18
|
-
when 29
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
when
|
23
|
-
|
24
|
-
when
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
#
|
44
|
-
#
|
45
|
-
#
|
46
|
-
# @
|
47
|
-
# @
|
48
|
-
#
|
49
|
-
def
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
1
|
+
module RTP
|
2
|
+
|
3
|
+
class << self
|
4
|
+
|
5
|
+
#--
|
6
|
+
# Module methods:
|
7
|
+
#++
|
8
|
+
|
9
|
+
# Gives an array of MLC leaf position boundaries for a given type of MLC,
|
10
|
+
# specified by its number of leaves at one side.
|
11
|
+
#
|
12
|
+
# @param [Fixnum] nr_leaves the number of leaves (in one leaf bank)
|
13
|
+
# @return [Array<Fixnum>] the leaf boundary positions
|
14
|
+
# @raise [ArgumentError] if an unsupported MLC (nr of leaves) is given
|
15
|
+
#
|
16
|
+
def leaf_boundaries(nr_leaves)
|
17
|
+
case nr_leaves
|
18
|
+
when 29
|
19
|
+
leaf_boundaries_odd(29)
|
20
|
+
when 40
|
21
|
+
leaf_boundaries_even(40)
|
22
|
+
when 41
|
23
|
+
leaf_boundaries_odd(41)
|
24
|
+
when 60
|
25
|
+
leaf_boundaries_varian_60
|
26
|
+
when 80
|
27
|
+
leaf_boundaries_even(80)
|
28
|
+
else
|
29
|
+
raise ArgumentError, "Unsupported number of leaves: #{nr_leaves}"
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
# Gives an array of MLC leaf position boundaries for ordinary even numbered
|
34
|
+
# multi leaf collimators.
|
35
|
+
#
|
36
|
+
# @param [Fixnum] nr_leaves the number of leaves (in one leaf bank)
|
37
|
+
# @return [Array<Fixnum>] the leaf boundary positions
|
38
|
+
#
|
39
|
+
def leaf_boundaries_even(nr_leaves)
|
40
|
+
Array.new(nr_leaves+1) {|i| (i * 400 / nr_leaves.to_f - 200).to_i}
|
41
|
+
end
|
42
|
+
|
43
|
+
# Gives an array of MLC leaf position boundaries for ordinary odd numbered
|
44
|
+
# multi leaf collimators.
|
45
|
+
#
|
46
|
+
# @param [Fixnum] nr_leaves the number of leaves (in one leaf bank)
|
47
|
+
# @return [Array<Fixnum>] the leaf boundary positions
|
48
|
+
#
|
49
|
+
def leaf_boundaries_odd(nr_leaves)
|
50
|
+
Array.new(nr_leaves-1) {|i| (10 * (i - (0.5 * nr_leaves - 1))).to_i}.unshift(-200).push(200)
|
51
|
+
end
|
52
|
+
|
53
|
+
# Gives an array of MLC leaf position boundaries for the Varian 120 leaf MLC (60 leaves on each bank).
|
54
|
+
#
|
55
|
+
# @return [Array<Fixnum>] the leaf boundary positions
|
56
|
+
#
|
57
|
+
def leaf_boundaries_varian_60
|
58
|
+
Array.new(10) {|i| (i * 10 - 200).to_i}
|
59
|
+
.concat(Array.new(41) {|i| (i * 5 - 100).to_i})
|
60
|
+
.concat(Array.new(10) {|i| (i * 10 + 110).to_i})
|
61
|
+
end
|
62
|
+
|
63
|
+
# Computes the CRC checksum of the given line and verifies that
|
64
|
+
# this value corresponds with the checksum given at the end of the line.
|
65
|
+
#
|
66
|
+
# @param [String] line a single line string from an RTPConnect ascii file
|
67
|
+
# @param [Hash] options the options to use for verifying the RTP record
|
68
|
+
# @option options [Boolean] :ignore_crc if true, the verification method will return true even if the checksum is invalid
|
69
|
+
# @return [Boolean] true
|
70
|
+
# @raise [ArgumentError] if an invalid line/record is given or the string contains an invalid checksum
|
71
|
+
#
|
72
|
+
def verify(line, options={})
|
73
|
+
last_comma_pos = line.rindex(',')
|
74
|
+
raise ArgumentError, "Invalid line encountered; No comma present in the string: #{line}" unless last_comma_pos
|
75
|
+
string_to_check = line[0..last_comma_pos]
|
76
|
+
string_remaining = line[(last_comma_pos+1)..-1]
|
77
|
+
raise ArgumentError, "Invalid line encountered; Valid checksum missing at end of string: #{string_remaining}" unless string_remaining.length >= 3
|
78
|
+
checksum_extracted = string_remaining.value.to_i
|
79
|
+
checksum_computed = string_to_check.checksum
|
80
|
+
raise ArgumentError, "Invalid line encountered: Specified checksum #{checksum_extracted} deviates from the computed checksum #{checksum_computed}." if checksum_extracted != checksum_computed && !options[:ignore_crc]
|
81
|
+
return true
|
82
|
+
end
|
83
|
+
|
84
|
+
end
|
85
|
+
|
63
86
|
end
|
data/lib/rtp-connect/plan.rb
CHANGED
@@ -1,637 +1,646 @@
|
|
1
|
-
# Copyright 2011-
|
2
|
-
#
|
3
|
-
# This program is free software: you can redistribute it and/or modify
|
4
|
-
# it under the terms of the GNU General Public License as published by
|
5
|
-
# the Free Software Foundation, either version 3 of the License, or
|
6
|
-
# (at your option) any later version.
|
7
|
-
#
|
8
|
-
# This program is distributed in the hope that it will be useful,
|
9
|
-
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
10
|
-
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
11
|
-
# GNU General Public License for more details.
|
12
|
-
#
|
13
|
-
# You should have received a copy of the GNU General Public License
|
14
|
-
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
15
|
-
#
|
16
|
-
module RTP
|
17
|
-
|
18
|
-
# The Plan class is the highest level Record in the RTPConnect records hierarchy,
|
19
|
-
# and the one the user will interact with to read, modify and write files.
|
20
|
-
#
|
21
|
-
# @note Relations:
|
22
|
-
# * Parent: nil
|
23
|
-
# * Children: Prescription, DoseTracking
|
24
|
-
#
|
25
|
-
class Plan < Record
|
26
|
-
include Logging
|
27
|
-
|
28
|
-
# The Record which this instance belongs to (nil by definition).
|
29
|
-
attr_reader :parent
|
30
|
-
# An array of Prescription records (if any) that belongs to this Plan.
|
31
|
-
attr_reader :prescriptions
|
32
|
-
#
|
33
|
-
attr_reader :
|
34
|
-
|
35
|
-
attr_reader :
|
36
|
-
attr_reader :
|
37
|
-
attr_reader :
|
38
|
-
attr_reader :
|
39
|
-
attr_reader :
|
40
|
-
attr_reader :
|
41
|
-
attr_reader :
|
42
|
-
attr_reader :
|
43
|
-
attr_reader :
|
44
|
-
attr_reader :
|
45
|
-
attr_reader :
|
46
|
-
attr_reader :
|
47
|
-
attr_reader :
|
48
|
-
attr_reader :
|
49
|
-
attr_reader :
|
50
|
-
attr_reader :
|
51
|
-
attr_reader :
|
52
|
-
attr_reader :
|
53
|
-
attr_reader :
|
54
|
-
attr_reader :
|
55
|
-
attr_reader :
|
56
|
-
attr_reader :
|
57
|
-
attr_reader :
|
58
|
-
attr_reader :
|
59
|
-
attr_reader :
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
#
|
64
|
-
#
|
65
|
-
# @
|
66
|
-
#
|
67
|
-
# @
|
68
|
-
#
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
rtp
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
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
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
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
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
#
|
215
|
-
#
|
216
|
-
# @
|
217
|
-
#
|
218
|
-
def
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
#
|
224
|
-
#
|
225
|
-
#
|
226
|
-
#
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
end
|
231
|
-
|
232
|
-
#
|
233
|
-
#
|
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
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
#
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
#
|
279
|
-
#
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
#
|
286
|
-
#
|
287
|
-
#
|
288
|
-
# @return [
|
289
|
-
#
|
290
|
-
def
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
#
|
303
|
-
#
|
304
|
-
#
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
#
|
312
|
-
#
|
313
|
-
# @
|
314
|
-
# @param [
|
315
|
-
# @
|
316
|
-
#
|
317
|
-
def
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
end
|
322
|
-
|
323
|
-
# Sets the patient_id attribute.
|
324
|
-
#
|
325
|
-
# @param [nil, #to_s] value the new attribute value
|
326
|
-
#
|
327
|
-
def patient_id=(value)
|
328
|
-
@patient_id = value && value.to_s
|
329
|
-
end
|
330
|
-
|
331
|
-
# Sets the patient_last_name attribute.
|
332
|
-
#
|
333
|
-
def patient_last_name=(value)
|
334
|
-
@patient_last_name = value && value.to_s
|
335
|
-
end
|
336
|
-
|
337
|
-
# Sets the patient_first_name attribute.
|
338
|
-
#
|
339
|
-
# @param [nil, #to_s] value the new attribute value
|
340
|
-
#
|
341
|
-
def patient_first_name=(value)
|
342
|
-
@patient_first_name = value && value.to_s
|
343
|
-
end
|
344
|
-
|
345
|
-
# Sets the patient_middle_initial attribute.
|
346
|
-
#
|
347
|
-
# @param [nil, #to_s] value the new attribute value
|
348
|
-
#
|
349
|
-
def patient_middle_initial=(value)
|
350
|
-
@patient_middle_initial = value && value.to_s
|
351
|
-
end
|
352
|
-
|
353
|
-
# Sets the plan_id attribute.
|
354
|
-
#
|
355
|
-
# @param [nil, #to_s] value the new attribute value
|
356
|
-
#
|
357
|
-
def plan_id=(value)
|
358
|
-
@plan_id = value && value.to_s
|
359
|
-
end
|
360
|
-
|
361
|
-
# Sets the plan_date attribute.
|
362
|
-
#
|
363
|
-
# @param [nil, #to_s] value the new attribute value
|
364
|
-
#
|
365
|
-
def plan_date=(value)
|
366
|
-
@plan_date = value && value.to_s
|
367
|
-
end
|
368
|
-
|
369
|
-
# Sets the plan_time attribute.
|
370
|
-
#
|
371
|
-
# @param [nil, #to_s] value the new attribute value
|
372
|
-
#
|
373
|
-
def plan_time=(value)
|
374
|
-
@plan_time = value && value.to_s
|
375
|
-
end
|
376
|
-
|
377
|
-
# Sets the course_id attribute.
|
378
|
-
#
|
379
|
-
# @param [nil, #to_s] value the new attribute value
|
380
|
-
#
|
381
|
-
def course_id=(value)
|
382
|
-
@course_id = value && value.to_s
|
383
|
-
end
|
384
|
-
|
385
|
-
# Sets the diagnosis attribute.
|
386
|
-
#
|
387
|
-
# @param [nil, #to_s] value the new attribute value
|
388
|
-
#
|
389
|
-
def diagnosis=(value)
|
390
|
-
@diagnosis = value && value.to_s
|
391
|
-
end
|
392
|
-
|
393
|
-
# Sets the md_last_name attribute.
|
394
|
-
#
|
395
|
-
# @param [nil, #to_s] value the new attribute value
|
396
|
-
#
|
397
|
-
def md_last_name=(value)
|
398
|
-
@md_last_name = value && value.to_s
|
399
|
-
end
|
400
|
-
|
401
|
-
# Sets the md_first_name attribute.
|
402
|
-
#
|
403
|
-
# @param [nil, #to_s] value the new attribute value
|
404
|
-
#
|
405
|
-
def md_first_name=(value)
|
406
|
-
@md_first_name = value && value.to_s
|
407
|
-
end
|
408
|
-
|
409
|
-
# Sets the md_middle_initial attribute.
|
410
|
-
#
|
411
|
-
# @param [nil, #to_s] value the new attribute value
|
412
|
-
#
|
413
|
-
def md_middle_initial=(value)
|
414
|
-
@md_middle_initial = value && value.to_s
|
415
|
-
end
|
416
|
-
|
417
|
-
# Sets the md_approve_last_name attribute.
|
418
|
-
#
|
419
|
-
# @param [nil, #to_s] value the new attribute value
|
420
|
-
#
|
421
|
-
def md_approve_last_name=(value)
|
422
|
-
@md_approve_last_name = value && value.to_s
|
423
|
-
end
|
424
|
-
|
425
|
-
# Sets the md_approve_first_name attribute.
|
426
|
-
#
|
427
|
-
# @param [nil, #to_s] value the new attribute value
|
428
|
-
#
|
429
|
-
def md_approve_first_name=(value)
|
430
|
-
@md_approve_first_name = value && value.to_s
|
431
|
-
end
|
432
|
-
|
433
|
-
# Sets the md_approve_middle_initial attribute.
|
434
|
-
#
|
435
|
-
# @param [nil, #to_s] value the new attribute value
|
436
|
-
#
|
437
|
-
def md_approve_middle_initial=(value)
|
438
|
-
@md_approve_middle_initial = value && value.to_s
|
439
|
-
end
|
440
|
-
|
441
|
-
# Sets the phy_approve_last_name attribute.
|
442
|
-
#
|
443
|
-
# @param [nil, #to_s] value the new attribute value
|
444
|
-
#
|
445
|
-
def phy_approve_last_name=(value)
|
446
|
-
@phy_approve_last_name = value && value.to_s
|
447
|
-
end
|
448
|
-
|
449
|
-
# Sets the phy_approve_first_name attribute.
|
450
|
-
#
|
451
|
-
# @param [nil, #to_s] value the new attribute value
|
452
|
-
#
|
453
|
-
def phy_approve_first_name=(value)
|
454
|
-
@phy_approve_first_name = value && value.to_s
|
455
|
-
end
|
456
|
-
|
457
|
-
# Sets the phy_approve_middle_initial attribute.
|
458
|
-
#
|
459
|
-
# @param [nil, #to_s] value the new attribute value
|
460
|
-
#
|
461
|
-
def phy_approve_middle_initial=(value)
|
462
|
-
@phy_approve_middle_initial = value && value.to_s
|
463
|
-
end
|
464
|
-
|
465
|
-
# Sets the author_last_name attribute.
|
466
|
-
#
|
467
|
-
# @param [nil, #to_s] value the new attribute value
|
468
|
-
#
|
469
|
-
def author_last_name=(value)
|
470
|
-
@author_last_name = value && value.to_s
|
471
|
-
end
|
472
|
-
|
473
|
-
# Sets the author_first_name attribute.
|
474
|
-
#
|
475
|
-
# @param [nil, #to_s] value the new attribute value
|
476
|
-
#
|
477
|
-
def author_first_name=(value)
|
478
|
-
@author_first_name = value && value.to_s
|
479
|
-
end
|
480
|
-
|
481
|
-
# Sets the author_middle_initial attribute.
|
482
|
-
#
|
483
|
-
# @param [nil, #to_s] value the new attribute value
|
484
|
-
#
|
485
|
-
def author_middle_initial=(value)
|
486
|
-
@author_middle_initial = value && value.to_s
|
487
|
-
end
|
488
|
-
|
489
|
-
# Sets the rtp_mfg attribute.
|
490
|
-
#
|
491
|
-
# @param [nil, #to_s] value the new attribute value
|
492
|
-
#
|
493
|
-
def rtp_mfg=(value)
|
494
|
-
@rtp_mfg = value && value.to_s
|
495
|
-
end
|
496
|
-
|
497
|
-
# Sets the rtp_model attribute.
|
498
|
-
#
|
499
|
-
# @param [nil, #to_s] value the new attribute value
|
500
|
-
#
|
501
|
-
def rtp_model=(value)
|
502
|
-
@rtp_model = value && value.to_s
|
503
|
-
end
|
504
|
-
|
505
|
-
# Sets the rtp_version attribute.
|
506
|
-
#
|
507
|
-
# @param [nil, #to_s] value the new attribute value
|
508
|
-
#
|
509
|
-
def rtp_version=(value)
|
510
|
-
@rtp_version = value && value.to_s
|
511
|
-
end
|
512
|
-
|
513
|
-
# Sets the rtp_if_protocol attribute.
|
514
|
-
#
|
515
|
-
# @param [nil, #to_s] value the new attribute value
|
516
|
-
#
|
517
|
-
def rtp_if_protocol=(value)
|
518
|
-
@rtp_if_protocol = value && value.to_s
|
519
|
-
end
|
520
|
-
|
521
|
-
# Sets the rtp_if_version attribute.
|
522
|
-
#
|
523
|
-
# @param [nil, #to_s] value the new attribute value
|
524
|
-
#
|
525
|
-
def rtp_if_version=(value)
|
526
|
-
@rtp_if_version = value && value.to_s
|
527
|
-
end
|
528
|
-
|
529
|
-
|
530
|
-
private
|
531
|
-
|
532
|
-
|
533
|
-
# Creates a control point record from the given string.
|
534
|
-
#
|
535
|
-
# @param [String] string a string line containing a control point definition
|
536
|
-
#
|
537
|
-
def control_point(string)
|
538
|
-
cp = ControlPoint.load(string, @current_parent)
|
539
|
-
@current_parent = cp
|
540
|
-
end
|
541
|
-
|
542
|
-
# Creates a dose tracking record from the given string.
|
543
|
-
#
|
544
|
-
# @param [String] string a string line containing a dose tracking definition
|
545
|
-
#
|
546
|
-
def dose_tracking(string)
|
547
|
-
dt = DoseTracking.load(string, @current_parent)
|
548
|
-
@current_parent = dt
|
549
|
-
end
|
550
|
-
|
551
|
-
# Creates an extended
|
552
|
-
#
|
553
|
-
# @param [String] string a string line containing an extended
|
554
|
-
#
|
555
|
-
def
|
556
|
-
|
557
|
-
@current_parent =
|
558
|
-
end
|
559
|
-
|
560
|
-
#
|
561
|
-
#
|
562
|
-
# @param [String]
|
563
|
-
#
|
564
|
-
|
565
|
-
|
566
|
-
|
567
|
-
|
568
|
-
|
569
|
-
|
570
|
-
|
571
|
-
|
572
|
-
|
573
|
-
|
574
|
-
|
575
|
-
|
576
|
-
|
577
|
-
|
578
|
-
|
579
|
-
|
580
|
-
|
581
|
-
|
582
|
-
|
583
|
-
|
584
|
-
|
585
|
-
|
586
|
-
|
587
|
-
|
588
|
-
|
589
|
-
|
590
|
-
|
591
|
-
|
592
|
-
|
593
|
-
|
594
|
-
|
595
|
-
|
596
|
-
|
597
|
-
|
598
|
-
|
599
|
-
end
|
600
|
-
|
601
|
-
# Creates a site
|
602
|
-
#
|
603
|
-
# @param [String] string a string line containing a site
|
604
|
-
#
|
605
|
-
def
|
606
|
-
|
607
|
-
@current_parent =
|
608
|
-
end
|
609
|
-
|
610
|
-
#
|
611
|
-
#
|
612
|
-
# @
|
613
|
-
#
|
614
|
-
|
615
|
-
|
616
|
-
|
617
|
-
|
618
|
-
|
619
|
-
#
|
620
|
-
#
|
621
|
-
|
622
|
-
|
623
|
-
|
624
|
-
|
625
|
-
|
626
|
-
# Creates a
|
627
|
-
#
|
628
|
-
# @param [String] string a string line containing a
|
629
|
-
#
|
630
|
-
def
|
631
|
-
|
632
|
-
@current_parent =
|
633
|
-
end
|
634
|
-
|
635
|
-
|
636
|
-
|
1
|
+
# Copyright 2011-2020 Christoffer Lervag
|
2
|
+
#
|
3
|
+
# This program is free software: you can redistribute it and/or modify
|
4
|
+
# it under the terms of the GNU General Public License as published by
|
5
|
+
# the Free Software Foundation, either version 3 of the License, or
|
6
|
+
# (at your option) any later version.
|
7
|
+
#
|
8
|
+
# This program is distributed in the hope that it will be useful,
|
9
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
10
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
11
|
+
# GNU General Public License for more details.
|
12
|
+
#
|
13
|
+
# You should have received a copy of the GNU General Public License
|
14
|
+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
15
|
+
#
|
16
|
+
module RTP
|
17
|
+
|
18
|
+
# The Plan class is the highest level Record in the RTPConnect records hierarchy,
|
19
|
+
# and the one the user will interact with to read, modify and write files.
|
20
|
+
#
|
21
|
+
# @note Relations:
|
22
|
+
# * Parent: nil
|
23
|
+
# * Children: Prescription, DoseTracking
|
24
|
+
#
|
25
|
+
class Plan < Record
|
26
|
+
include Logging
|
27
|
+
|
28
|
+
# The Record which this instance belongs to (nil by definition).
|
29
|
+
attr_reader :parent
|
30
|
+
# An array of Prescription records (if any) that belongs to this Plan.
|
31
|
+
attr_reader :prescriptions
|
32
|
+
# The ExtendedPlan record (if any) that belongs to this Plan.
|
33
|
+
attr_reader :extended_plan
|
34
|
+
# An array of DoseTracking records (if any) that belongs to this Plan.
|
35
|
+
attr_reader :dose_trackings
|
36
|
+
attr_reader :patient_id
|
37
|
+
attr_reader :patient_last_name
|
38
|
+
attr_reader :patient_first_name
|
39
|
+
attr_reader :patient_middle_initial
|
40
|
+
attr_reader :plan_id
|
41
|
+
attr_reader :plan_date
|
42
|
+
attr_reader :plan_time
|
43
|
+
attr_reader :course_id
|
44
|
+
attr_reader :diagnosis
|
45
|
+
attr_reader :md_last_name
|
46
|
+
attr_reader :md_first_name
|
47
|
+
attr_reader :md_middle_initial
|
48
|
+
attr_reader :md_approve_last_name
|
49
|
+
attr_reader :md_approve_first_name
|
50
|
+
attr_reader :md_approve_middle_initial
|
51
|
+
attr_reader :phy_approve_last_name
|
52
|
+
attr_reader :phy_approve_first_name
|
53
|
+
attr_reader :phy_approve_middle_initial
|
54
|
+
attr_reader :author_last_name
|
55
|
+
attr_reader :author_first_name
|
56
|
+
attr_reader :author_middle_initial
|
57
|
+
attr_reader :rtp_mfg
|
58
|
+
attr_reader :rtp_model
|
59
|
+
attr_reader :rtp_version
|
60
|
+
attr_reader :rtp_if_protocol
|
61
|
+
attr_reader :rtp_if_version
|
62
|
+
|
63
|
+
# Creates a new Plan by loading a plan definition string (i.e. a single line).
|
64
|
+
#
|
65
|
+
# @note This method does not perform crc verification on the given string.
|
66
|
+
# If such verification is desired, use methods ::parse or ::read instead.
|
67
|
+
# @param [#to_s] string the plan definition record string line
|
68
|
+
# @param [Hash] options the options to use for loading the plan definition string
|
69
|
+
# @option options [Boolean] :repair if true, a record containing invalid CSV will be attempted fixed and loaded
|
70
|
+
# @return [Plan] the created Plan instance
|
71
|
+
# @raise [ArgumentError] if given a string containing an invalid number of elements
|
72
|
+
#
|
73
|
+
def self.load(string, options={})
|
74
|
+
rtp = self.new
|
75
|
+
rtp.load(string, options)
|
76
|
+
end
|
77
|
+
|
78
|
+
# Creates a Plan instance by parsing an RTPConnect string.
|
79
|
+
#
|
80
|
+
# @param [#to_s] string an RTPConnect ascii string (with single or multiple lines/records)
|
81
|
+
# @param [Hash] options the options to use for parsing the RTP string
|
82
|
+
# @option options [Boolean] :ignore_crc if true, the RTP records will be successfully loaded even if their checksums are invalid
|
83
|
+
# @option options [Boolean] :repair if true, any RTP records containing invalid CSV will be attempted fixed and loaded
|
84
|
+
# @option options [Boolean] :skip_unknown if true, unknown records will be skipped, and record instances will be built from the remaining recognized string records
|
85
|
+
# @return [Plan] the created Plan instance
|
86
|
+
# @raise [ArgumentError] if given an invalid string record
|
87
|
+
#
|
88
|
+
def self.parse(string, options={})
|
89
|
+
lines = string.to_s.split("\r\n")
|
90
|
+
# Create the Plan object:
|
91
|
+
line = lines.first
|
92
|
+
RTP.verify(line, options)
|
93
|
+
rtp = self.load(line, options)
|
94
|
+
lines[1..-1].each do |line|
|
95
|
+
# Validate, determine type, and process the line accordingly to
|
96
|
+
# build the hierarchy of records:
|
97
|
+
RTP.verify(line, options)
|
98
|
+
values = line.values(options[:repair])
|
99
|
+
keyword = values.first
|
100
|
+
method = RTP::PARSE_METHOD[keyword]
|
101
|
+
if method
|
102
|
+
rtp.send(method, line)
|
103
|
+
else
|
104
|
+
if options[:skip_unknown]
|
105
|
+
logger.warn("Skipped unknown record definition: #{keyword}")
|
106
|
+
else
|
107
|
+
raise ArgumentError, "Unknown keyword #{keyword} extracted from string."
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
return rtp
|
112
|
+
end
|
113
|
+
|
114
|
+
# Creates an Plan instance by reading and parsing an RTPConnect file.
|
115
|
+
#
|
116
|
+
# @param [String] file a string which specifies the path of the RTPConnect file to be loaded
|
117
|
+
# @param [Hash] options the options to use for reading the RTP file
|
118
|
+
# @option options [Boolean] :ignore_crc if true, the RTP records will be successfully loaded even if their checksums are invalid
|
119
|
+
# @option options [Boolean] :repair if true, any RTP records containing invalid CSV will be attempted fixed and loaded
|
120
|
+
# @option options [Boolean] :skip_unknown if true, unknown records will be skipped, and record instances will be built from the remaining recognized string records
|
121
|
+
# @return [Plan] the created Plan instance
|
122
|
+
# @raise [ArgumentError] if given an invalid file or the file given contains an invalid record
|
123
|
+
#
|
124
|
+
def self.read(file, options={})
|
125
|
+
raise ArgumentError, "Invalid argument 'file'. Expected String, got #{file.class}." unless file.is_a?(String)
|
126
|
+
# Read the file content:
|
127
|
+
str = nil
|
128
|
+
unless File.exist?(file)
|
129
|
+
logger.error("Invalid (non-existing) file: #{file}")
|
130
|
+
else
|
131
|
+
unless File.readable?(file)
|
132
|
+
logger.error("File exists but I don't have permission to read it: #{file}")
|
133
|
+
else
|
134
|
+
if File.directory?(file)
|
135
|
+
logger.error("Expected a file, got a directory: #{file}")
|
136
|
+
else
|
137
|
+
if File.size(file) < 10
|
138
|
+
logger.error("This file is too small to contain valid RTP information: #{file}.")
|
139
|
+
else
|
140
|
+
str = File.open(file, 'rb:ISO8859-1') { |f| f.read }
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
144
|
+
end
|
145
|
+
# Parse the file contents and create the RTP instance:
|
146
|
+
if str
|
147
|
+
rtp = self.parse(str, options)
|
148
|
+
else
|
149
|
+
raise "An RTP::Plan object could not be created from the specified file. Check the log for more details."
|
150
|
+
end
|
151
|
+
return rtp
|
152
|
+
end
|
153
|
+
|
154
|
+
# Creates a new Plan.
|
155
|
+
#
|
156
|
+
def initialize
|
157
|
+
super('PLAN_DEF', 10, 28)
|
158
|
+
@current_parent = self
|
159
|
+
# Child records:
|
160
|
+
@extended_plan = nil
|
161
|
+
@prescriptions = Array.new
|
162
|
+
@dose_trackings = Array.new
|
163
|
+
# No parent (by definition) for the Plan record:
|
164
|
+
@parent = nil
|
165
|
+
@attributes = [
|
166
|
+
# Required:
|
167
|
+
:keyword,
|
168
|
+
:patient_id,
|
169
|
+
:patient_last_name,
|
170
|
+
:patient_first_name,
|
171
|
+
:patient_middle_initial,
|
172
|
+
:plan_id,
|
173
|
+
:plan_date,
|
174
|
+
:plan_time,
|
175
|
+
:course_id,
|
176
|
+
# Optional:
|
177
|
+
:diagnosis,
|
178
|
+
:md_last_name,
|
179
|
+
:md_first_name,
|
180
|
+
:md_middle_initial,
|
181
|
+
:md_approve_last_name,
|
182
|
+
:md_approve_first_name,
|
183
|
+
:md_approve_middle_initial,
|
184
|
+
:phy_approve_last_name,
|
185
|
+
:phy_approve_first_name,
|
186
|
+
:phy_approve_middle_initial,
|
187
|
+
:author_last_name,
|
188
|
+
:author_first_name,
|
189
|
+
:author_middle_initial,
|
190
|
+
:rtp_mfg,
|
191
|
+
:rtp_model,
|
192
|
+
:rtp_version,
|
193
|
+
:rtp_if_protocol,
|
194
|
+
:rtp_if_version
|
195
|
+
]
|
196
|
+
end
|
197
|
+
|
198
|
+
# Checks for equality.
|
199
|
+
#
|
200
|
+
# Other and self are considered equivalent if they are
|
201
|
+
# of compatible types and their attributes are equivalent.
|
202
|
+
#
|
203
|
+
# @param other an object to be compared with self.
|
204
|
+
# @return [Boolean] true if self and other are considered equivalent
|
205
|
+
#
|
206
|
+
def ==(other)
|
207
|
+
if other.respond_to?(:to_plan)
|
208
|
+
other.send(:state) == state
|
209
|
+
end
|
210
|
+
end
|
211
|
+
|
212
|
+
alias_method :eql?, :==
|
213
|
+
|
214
|
+
# Adds a dose tracking record to this instance.
|
215
|
+
#
|
216
|
+
# @param [DoseTracking] child a DoseTracking instance which is to be associated with self
|
217
|
+
#
|
218
|
+
def add_dose_tracking(child)
|
219
|
+
@dose_trackings << child.to_dose_tracking
|
220
|
+
child.parent = self
|
221
|
+
end
|
222
|
+
|
223
|
+
# Adds an extended plan record to this instance.
|
224
|
+
#
|
225
|
+
# @param [ExtendedPlan] child an ExtendedPlan instance which is to be associated with self
|
226
|
+
#
|
227
|
+
def add_extended_plan(child)
|
228
|
+
@extended_plan = child.to_extended_plan
|
229
|
+
child.parent = self
|
230
|
+
end
|
231
|
+
|
232
|
+
# Adds a prescription site record to this instance.
|
233
|
+
#
|
234
|
+
# @param [Prescription] child a Prescription instance which is to be associated with self
|
235
|
+
#
|
236
|
+
def add_prescription(child)
|
237
|
+
@prescriptions << child.to_prescription
|
238
|
+
child.parent = self
|
239
|
+
end
|
240
|
+
|
241
|
+
# Collects the child records of this instance in a properly sorted array.
|
242
|
+
#
|
243
|
+
# @return [Array<Prescription, DoseTracking>] a sorted array of self's child records
|
244
|
+
#
|
245
|
+
def children
|
246
|
+
return [@extended_plan, @prescriptions, @dose_trackings].flatten.compact
|
247
|
+
end
|
248
|
+
|
249
|
+
# Removes the reference of the given instance from this instance.
|
250
|
+
#
|
251
|
+
# @param [ExtendedPlan, Prescription, DoseTracking] record a child record to be removed from this instance
|
252
|
+
#
|
253
|
+
def delete(record)
|
254
|
+
case record
|
255
|
+
when Prescription
|
256
|
+
delete_child(:prescriptions, record)
|
257
|
+
when DoseTracking
|
258
|
+
delete_child(:dose_trackings, record)
|
259
|
+
when ExtendedPlan
|
260
|
+
delete_extended_plan
|
261
|
+
else
|
262
|
+
logger.warn("Unknown class (record) given to Plan#delete: #{record.class}")
|
263
|
+
end
|
264
|
+
end
|
265
|
+
|
266
|
+
# Removes all dose_tracking references from this instance.
|
267
|
+
#
|
268
|
+
def delete_dose_trackings
|
269
|
+
delete_children(:dose_trackings)
|
270
|
+
end
|
271
|
+
|
272
|
+
# Removes the extended plan reference from this instance.
|
273
|
+
#
|
274
|
+
def delete_extended_plan
|
275
|
+
delete_child(:extended_plan)
|
276
|
+
end
|
277
|
+
|
278
|
+
# Removes all prescription references from this instance.
|
279
|
+
#
|
280
|
+
def delete_prescriptions
|
281
|
+
delete_children(:prescriptions)
|
282
|
+
end
|
283
|
+
|
284
|
+
# Computes a hash code for this object.
|
285
|
+
#
|
286
|
+
# @note Two objects with the same attributes will have the same hash code.
|
287
|
+
#
|
288
|
+
# @return [Fixnum] the object's hash code
|
289
|
+
#
|
290
|
+
def hash
|
291
|
+
state.hash
|
292
|
+
end
|
293
|
+
|
294
|
+
# Returns self.
|
295
|
+
#
|
296
|
+
# @return [Plan] self
|
297
|
+
#
|
298
|
+
def to_plan
|
299
|
+
self
|
300
|
+
end
|
301
|
+
|
302
|
+
# Returns self.
|
303
|
+
#
|
304
|
+
# @return [Plan] self
|
305
|
+
#
|
306
|
+
def to_rtp
|
307
|
+
self
|
308
|
+
end
|
309
|
+
|
310
|
+
# Writes the Plan object, along with its hiearchy of child objects,
|
311
|
+
# to a properly formatted RTPConnect ascii file.
|
312
|
+
#
|
313
|
+
# @param [String] file a path/file string
|
314
|
+
# @param [Hash] options an optional hash parameter
|
315
|
+
# @option options [Float] :version the Mosaiq compatibility version number (e.g. 2.4) used for the output
|
316
|
+
#
|
317
|
+
def write(file, options={})
|
318
|
+
f = open_file(file)
|
319
|
+
f.write(to_s(options))
|
320
|
+
f.close
|
321
|
+
end
|
322
|
+
|
323
|
+
# Sets the patient_id attribute.
|
324
|
+
#
|
325
|
+
# @param [nil, #to_s] value the new attribute value
|
326
|
+
#
|
327
|
+
def patient_id=(value)
|
328
|
+
@patient_id = value && value.to_s
|
329
|
+
end
|
330
|
+
|
331
|
+
# Sets the patient_last_name attribute.
|
332
|
+
#
|
333
|
+
def patient_last_name=(value)
|
334
|
+
@patient_last_name = value && value.to_s
|
335
|
+
end
|
336
|
+
|
337
|
+
# Sets the patient_first_name attribute.
|
338
|
+
#
|
339
|
+
# @param [nil, #to_s] value the new attribute value
|
340
|
+
#
|
341
|
+
def patient_first_name=(value)
|
342
|
+
@patient_first_name = value && value.to_s
|
343
|
+
end
|
344
|
+
|
345
|
+
# Sets the patient_middle_initial attribute.
|
346
|
+
#
|
347
|
+
# @param [nil, #to_s] value the new attribute value
|
348
|
+
#
|
349
|
+
def patient_middle_initial=(value)
|
350
|
+
@patient_middle_initial = value && value.to_s
|
351
|
+
end
|
352
|
+
|
353
|
+
# Sets the plan_id attribute.
|
354
|
+
#
|
355
|
+
# @param [nil, #to_s] value the new attribute value
|
356
|
+
#
|
357
|
+
def plan_id=(value)
|
358
|
+
@plan_id = value && value.to_s
|
359
|
+
end
|
360
|
+
|
361
|
+
# Sets the plan_date attribute.
|
362
|
+
#
|
363
|
+
# @param [nil, #to_s] value the new attribute value
|
364
|
+
#
|
365
|
+
def plan_date=(value)
|
366
|
+
@plan_date = value && value.to_s
|
367
|
+
end
|
368
|
+
|
369
|
+
# Sets the plan_time attribute.
|
370
|
+
#
|
371
|
+
# @param [nil, #to_s] value the new attribute value
|
372
|
+
#
|
373
|
+
def plan_time=(value)
|
374
|
+
@plan_time = value && value.to_s
|
375
|
+
end
|
376
|
+
|
377
|
+
# Sets the course_id attribute.
|
378
|
+
#
|
379
|
+
# @param [nil, #to_s] value the new attribute value
|
380
|
+
#
|
381
|
+
def course_id=(value)
|
382
|
+
@course_id = value && value.to_s
|
383
|
+
end
|
384
|
+
|
385
|
+
# Sets the diagnosis attribute.
|
386
|
+
#
|
387
|
+
# @param [nil, #to_s] value the new attribute value
|
388
|
+
#
|
389
|
+
def diagnosis=(value)
|
390
|
+
@diagnosis = value && value.to_s
|
391
|
+
end
|
392
|
+
|
393
|
+
# Sets the md_last_name attribute.
|
394
|
+
#
|
395
|
+
# @param [nil, #to_s] value the new attribute value
|
396
|
+
#
|
397
|
+
def md_last_name=(value)
|
398
|
+
@md_last_name = value && value.to_s
|
399
|
+
end
|
400
|
+
|
401
|
+
# Sets the md_first_name attribute.
|
402
|
+
#
|
403
|
+
# @param [nil, #to_s] value the new attribute value
|
404
|
+
#
|
405
|
+
def md_first_name=(value)
|
406
|
+
@md_first_name = value && value.to_s
|
407
|
+
end
|
408
|
+
|
409
|
+
# Sets the md_middle_initial attribute.
|
410
|
+
#
|
411
|
+
# @param [nil, #to_s] value the new attribute value
|
412
|
+
#
|
413
|
+
def md_middle_initial=(value)
|
414
|
+
@md_middle_initial = value && value.to_s
|
415
|
+
end
|
416
|
+
|
417
|
+
# Sets the md_approve_last_name attribute.
|
418
|
+
#
|
419
|
+
# @param [nil, #to_s] value the new attribute value
|
420
|
+
#
|
421
|
+
def md_approve_last_name=(value)
|
422
|
+
@md_approve_last_name = value && value.to_s
|
423
|
+
end
|
424
|
+
|
425
|
+
# Sets the md_approve_first_name attribute.
|
426
|
+
#
|
427
|
+
# @param [nil, #to_s] value the new attribute value
|
428
|
+
#
|
429
|
+
def md_approve_first_name=(value)
|
430
|
+
@md_approve_first_name = value && value.to_s
|
431
|
+
end
|
432
|
+
|
433
|
+
# Sets the md_approve_middle_initial attribute.
|
434
|
+
#
|
435
|
+
# @param [nil, #to_s] value the new attribute value
|
436
|
+
#
|
437
|
+
def md_approve_middle_initial=(value)
|
438
|
+
@md_approve_middle_initial = value && value.to_s
|
439
|
+
end
|
440
|
+
|
441
|
+
# Sets the phy_approve_last_name attribute.
|
442
|
+
#
|
443
|
+
# @param [nil, #to_s] value the new attribute value
|
444
|
+
#
|
445
|
+
def phy_approve_last_name=(value)
|
446
|
+
@phy_approve_last_name = value && value.to_s
|
447
|
+
end
|
448
|
+
|
449
|
+
# Sets the phy_approve_first_name attribute.
|
450
|
+
#
|
451
|
+
# @param [nil, #to_s] value the new attribute value
|
452
|
+
#
|
453
|
+
def phy_approve_first_name=(value)
|
454
|
+
@phy_approve_first_name = value && value.to_s
|
455
|
+
end
|
456
|
+
|
457
|
+
# Sets the phy_approve_middle_initial attribute.
|
458
|
+
#
|
459
|
+
# @param [nil, #to_s] value the new attribute value
|
460
|
+
#
|
461
|
+
def phy_approve_middle_initial=(value)
|
462
|
+
@phy_approve_middle_initial = value && value.to_s
|
463
|
+
end
|
464
|
+
|
465
|
+
# Sets the author_last_name attribute.
|
466
|
+
#
|
467
|
+
# @param [nil, #to_s] value the new attribute value
|
468
|
+
#
|
469
|
+
def author_last_name=(value)
|
470
|
+
@author_last_name = value && value.to_s
|
471
|
+
end
|
472
|
+
|
473
|
+
# Sets the author_first_name attribute.
|
474
|
+
#
|
475
|
+
# @param [nil, #to_s] value the new attribute value
|
476
|
+
#
|
477
|
+
def author_first_name=(value)
|
478
|
+
@author_first_name = value && value.to_s
|
479
|
+
end
|
480
|
+
|
481
|
+
# Sets the author_middle_initial attribute.
|
482
|
+
#
|
483
|
+
# @param [nil, #to_s] value the new attribute value
|
484
|
+
#
|
485
|
+
def author_middle_initial=(value)
|
486
|
+
@author_middle_initial = value && value.to_s
|
487
|
+
end
|
488
|
+
|
489
|
+
# Sets the rtp_mfg attribute.
|
490
|
+
#
|
491
|
+
# @param [nil, #to_s] value the new attribute value
|
492
|
+
#
|
493
|
+
def rtp_mfg=(value)
|
494
|
+
@rtp_mfg = value && value.to_s
|
495
|
+
end
|
496
|
+
|
497
|
+
# Sets the rtp_model attribute.
|
498
|
+
#
|
499
|
+
# @param [nil, #to_s] value the new attribute value
|
500
|
+
#
|
501
|
+
def rtp_model=(value)
|
502
|
+
@rtp_model = value && value.to_s
|
503
|
+
end
|
504
|
+
|
505
|
+
# Sets the rtp_version attribute.
|
506
|
+
#
|
507
|
+
# @param [nil, #to_s] value the new attribute value
|
508
|
+
#
|
509
|
+
def rtp_version=(value)
|
510
|
+
@rtp_version = value && value.to_s
|
511
|
+
end
|
512
|
+
|
513
|
+
# Sets the rtp_if_protocol attribute.
|
514
|
+
#
|
515
|
+
# @param [nil, #to_s] value the new attribute value
|
516
|
+
#
|
517
|
+
def rtp_if_protocol=(value)
|
518
|
+
@rtp_if_protocol = value && value.to_s
|
519
|
+
end
|
520
|
+
|
521
|
+
# Sets the rtp_if_version attribute.
|
522
|
+
#
|
523
|
+
# @param [nil, #to_s] value the new attribute value
|
524
|
+
#
|
525
|
+
def rtp_if_version=(value)
|
526
|
+
@rtp_if_version = value && value.to_s
|
527
|
+
end
|
528
|
+
|
529
|
+
|
530
|
+
private
|
531
|
+
|
532
|
+
|
533
|
+
# Creates a control point record from the given string.
|
534
|
+
#
|
535
|
+
# @param [String] string a string line containing a control point definition
|
536
|
+
#
|
537
|
+
def control_point(string)
|
538
|
+
cp = ControlPoint.load(string, @current_parent)
|
539
|
+
@current_parent = cp
|
540
|
+
end
|
541
|
+
|
542
|
+
# Creates a dose tracking record from the given string.
|
543
|
+
#
|
544
|
+
# @param [String] string a string line containing a dose tracking definition
|
545
|
+
#
|
546
|
+
def dose_tracking(string)
|
547
|
+
dt = DoseTracking.load(string, @current_parent)
|
548
|
+
@current_parent = dt
|
549
|
+
end
|
550
|
+
|
551
|
+
# Creates an extended plan record from the given string.
|
552
|
+
#
|
553
|
+
# @param [String] string a string line containing an extended plan definition
|
554
|
+
#
|
555
|
+
def extended_plan_def(string)
|
556
|
+
ep = ExtendedPlan.load(string, @current_parent)
|
557
|
+
@current_parent = ep
|
558
|
+
end
|
559
|
+
|
560
|
+
# Creates an extended treatment field record from the given string.
|
561
|
+
#
|
562
|
+
# @param [String] string a string line containing an extended treatment field definition
|
563
|
+
#
|
564
|
+
def extended_treatment_field(string)
|
565
|
+
ef = ExtendedField.load(string, @current_parent)
|
566
|
+
@current_parent = ef
|
567
|
+
end
|
568
|
+
|
569
|
+
# Tests if the path/file is writable, creates any folders if necessary, and opens the file for writing.
|
570
|
+
#
|
571
|
+
# @param [String] file a path/file string
|
572
|
+
# @raise if the given file cannot be created
|
573
|
+
#
|
574
|
+
def open_file(file)
|
575
|
+
# Check if file already exists:
|
576
|
+
if File.exist?(file)
|
577
|
+
# Is (the existing file) writable?
|
578
|
+
unless File.writable?(file)
|
579
|
+
raise "The program does not have permission or resources to create this file: #{file}"
|
580
|
+
end
|
581
|
+
else
|
582
|
+
# File does not exist.
|
583
|
+
# Check if this file's path contains a folder that does not exist, and therefore needs to be created:
|
584
|
+
folders = file.split(File::SEPARATOR)
|
585
|
+
if folders.length > 1
|
586
|
+
# Remove last element (which should be the file string):
|
587
|
+
folders.pop
|
588
|
+
path = folders.join(File::SEPARATOR)
|
589
|
+
# Check if this path exists:
|
590
|
+
unless File.directory?(path)
|
591
|
+
# We need to create (parts of) this path:
|
592
|
+
require 'fileutils'
|
593
|
+
FileUtils.mkdir_p(path)
|
594
|
+
end
|
595
|
+
end
|
596
|
+
end
|
597
|
+
# It has been verified that the file can be created:
|
598
|
+
return File.new(file, 'wb:ISO8859-1')
|
599
|
+
end
|
600
|
+
|
601
|
+
# Creates a prescription site record from the given string.
|
602
|
+
#
|
603
|
+
# @param [String] string a string line containing a prescription site definition
|
604
|
+
#
|
605
|
+
def prescription_site(string)
|
606
|
+
p = Prescription.load(string, @current_parent)
|
607
|
+
@current_parent = p
|
608
|
+
end
|
609
|
+
|
610
|
+
# Creates a site setup record from the given string.
|
611
|
+
#
|
612
|
+
# @param [String] string a string line containing a site setup definition
|
613
|
+
#
|
614
|
+
def site_setup(string)
|
615
|
+
s = SiteSetup.load(string, @current_parent)
|
616
|
+
@current_parent = s
|
617
|
+
end
|
618
|
+
|
619
|
+
# Collects the attributes of this instance.
|
620
|
+
#
|
621
|
+
# @note The CRC is not considered part of the attributes of interest and is excluded
|
622
|
+
# @return [Array<String>] an array of attributes
|
623
|
+
#
|
624
|
+
alias_method :state, :values
|
625
|
+
|
626
|
+
# Creates a treatment field record from the given string.
|
627
|
+
#
|
628
|
+
# @param [String] string a string line containing a treatment field definition
|
629
|
+
#
|
630
|
+
def treatment_field(string)
|
631
|
+
f = Field.load(string, @current_parent)
|
632
|
+
@current_parent = f
|
633
|
+
end
|
634
|
+
|
635
|
+
# Creates a simulation field record from the given string.
|
636
|
+
#
|
637
|
+
# @param [String] string a string line containing a simulation field definition
|
638
|
+
#
|
639
|
+
def simulation_field(string)
|
640
|
+
sf = SimulationField.load(string, @current_parent)
|
641
|
+
@current_parent = sf
|
642
|
+
end
|
643
|
+
|
644
|
+
end
|
645
|
+
|
637
646
|
end
|