source: ruby/branches/0.5/lib/open_ehr/assumed_library_types.rb@ 244

Last change on this file since 244 was 244, checked in by KOBAYASHI, Shinji, 15 years ago

move DvInterval test to rspec

File size: 14.7 KB
Line 
1# This module is related to the ticket #36
2require 'date'
3require 'time'
4
5module OpenEHR
6 module AssumedLibraryTypes
7 class Any < Object
8
9 end # of Any
10
11 class Interval < Any
12 attr_reader :lower, :upper
13
14 def initialize(args = {})
15 check_lower_upper(args[:lower], args[:upper])
16 self.lower_included = args[:lower_included]
17 self.upper_included = args[:upper_included]
18 end
19
20 def lower=(lower)
21 check_lower_upper(lower, @upper)
22 end
23
24 def upper=(upper)
25 check_lower_upper(@lower, upper)
26 end
27
28 def lower_included?
29 return @lower_included
30 end
31
32 def lower_included=(lower_included)
33 if (lower == nil) && (lower_included != nil)
34 raise ArgumentError, "lower is not set"
35 end
36 @lower_included = lower_included
37 end
38
39 def lower_unbounded?
40 return @lower.nil?
41 end
42
43 def upper_included?
44 return @upper_included
45 end
46
47 def upper_included=(upper_included)
48 if (upper == nil) && (upper_included != nil)
49 raise ArgumentError, "upper is not set"
50 end
51 @upper_included = upper_included
52 end
53
54 def upper_unbounded?
55 return @upper.nil?
56 end
57
58 def has?(value)
59 if ((@lower < value) && (value < @upper) ||
60 (@lower_included == true) && (@lower == value) ||
61 (@upper_included == true) && (@upper == value))
62 true
63 else
64 false
65 end
66 end
67
68 private
69
70 def check_lower_upper(lower, upper)
71 if lower.nil? && upper.nil?
72 raise ArgumentError, "Either lower or upper must be assigned"
73 end
74 unless (lower.nil? || upper.nil?)
75 if lower > upper
76 raise ArgumentError, "Upper must be larger than lower."
77 end
78 end
79 @lower = lower
80 @upper = upper
81 end
82 end # end of Interval
83
84 class TIME_DEFINITIONS < Any
85 DAYS_IN_LEAP_YEAR = 366
86 DAYS_IN_WEEK = 7
87 DAYS_IN_YEAR = 365
88 HOURS_IN_DAY = 24
89 MAX_DAYS_IN_MONTH = 31
90 MAX_DAYS_IN_YEAR = 366
91 MINUTES_IN_HOUR = 60
92 MONTH_IN_YEAR = 12
93 NOMINAL_DAYS_IN_MONTH = 30.42
94 NOMINAL_DAYS_IN_YEAR = 365.24
95 SECONDS_IN_MINUTE = 60
96
97 def self.valid_year?(year)
98 year >= 0
99 end
100
101 def self.valid_day?(y, m, d)
102 Date.valid_date?(y,m,d) and valid_year? y
103 end
104
105 def self.valid_hour?(h,m = nil, s = nil)
106 if !m.nil? and !valid_minute?(m)
107 return false
108 end
109 if !s.nil? and (!m.nil? and !valid_second?(s))
110 return false
111 end
112 (h >= 0 and h < HOURS_IN_DAY) or (h == HOURS_IN_DAY and m == 0 and s == 0)
113 end
114 def self.valid_minute?(mi)
115 mi >= 0 and mi < MINUTES_IN_HOUR
116 end
117 def self.valid_second?(s)
118 s >= 0 and s < SECONDS_IN_MINUTE
119 end
120 def self.valid_month?(mo)
121 mo >= 1 and mo <= MONTH_IN_YEAR
122 end
123 end # end of TIME_DEFINITIONS
124
125 module ISO8601_DATE_MODULE
126 attr_reader :year, :month, :day
127 def year=(year)
128 raise ArgumentError, "Year is not valid" unless ISO8601_DATE.valid_year?(year)
129 @year = year
130 end
131 def month=(month)
132 raise ArgumentError, "Month is not valid" unless month.nil? or ISO8601_DATE.valid_month?(month)
133 @month = month
134 end
135
136 def day=(day)
137 raise ArgumentError, "Day is not valid" unless day.nil? or ISO8601_DATE.valid_day?(@year, @month, day)
138 @day = day
139 end
140
141 def as_string
142 if (!@year.nil? and !@month.nil? and !@day.nil?)
143 Date.new(@year, @month, @day).to_s
144 elsif (!@year.nil? and !@month.nil? and @day.nil?)
145 Date.new(@year, @month).to_s[0,7]
146 elsif (!@year.nil? and @month.nil? and @day.nil?)
147 Date.new(@year).to_s[0,4]
148 end
149 end
150
151 def month_unknown?
152 @month.nil?
153 end
154
155 def day_unknown?
156 @day.nil?
157 end
158
159 def is_extended?
160 true
161 end
162
163 def is_partial?
164 month_unknown? or day_unknown?
165 end
166
167 protected
168 def leapyear?(year)
169 case
170 when year % 400 == 0: true
171 when year % 100 == 0: false
172 else year % 4 == 0
173 end
174 end
175 end
176
177 class ISO8601_DATE < TIME_DEFINITIONS
178 include ISO8601_DATE_MODULE
179 def initialize(string)
180 /(\d{4})(?:-(\d{2})(?:-(\d{2})?)?)?/ =~ string
181 if $1.nil?
182 raise ArgumentError, 'data invalid'
183 else
184 self.year = $1.to_i
185 end
186 if $2.nil?
187 self.month = nil
188 else
189 self.month = $2.to_i
190 end
191 if $3.nil?
192 self.day = nil
193 else
194 self.day = $3.to_i
195 end
196 end
197
198 def self.valid_iso8601_date?(string)
199 begin
200 Date.parse(string)
201 rescue
202 return false
203 end
204 true
205 end
206 end # end of ISO8601_DATE
207
208 module ISO8601_TIME_MODULE
209 attr_reader :hour, :minute, :second, :fractional_second, :timezone
210
211 def hour=(hour)
212 raise ArgumentError, "hour is not valid" if !ISO8601_TIME.valid_hour?(hour, @minute, @second)
213 @hour = hour
214 end
215
216 def minute_unknown?
217 @minute.nil?
218 end
219
220 def minute=(minute)
221 raise ArgumentError, "minute is not valid" if !minute.nil? and !ISO8601_TIME.valid_minute?(minute)
222 @minute = minute
223 end
224
225 def second_unknown?
226 @second.nil?
227 end
228
229 def second=(second)
230 raise ArgumentError, "minute not defined" if @minute.nil? and !second.nil?
231 raise ArgumentError, "second is not valid" if !second.nil? and !ISO8601_TIME.valid_second?(second)
232 @second = second
233 end
234
235 def fractional_second=(fractional_second)
236 raise ArgumentError, "minute not defined" if minute_unknown? and !fractional_second.nil?
237 raise ArgumentError, "second not defined" if second_unknown? and !fractional_second.nil?
238 raise ArgumentError, "fractional second should be lower than 1.0" if !fractional_second.nil? and fractional_second >= 1.0
239 @fractional_second = fractional_second
240 end
241
242 def has_fractional_second?
243 if @fractional_second.nil?
244 return false
245 else
246 return true
247 end
248 end
249
250 def timezone=(timezone)
251 unless timezone.nil? or timezone == 'Z'
252 if /[+-](\d{2}):?(\d{2})/ =~ timezone
253 @timezone = timezone
254 else
255 raise ArgumentError, "timezone invalid"
256 end
257 else
258 @timezone = nil
259 end
260 end
261
262 def is_decimal_sign_comma?
263 false
264 end
265
266 def is_extended?
267 true
268 end
269
270 def is_partial?
271 second_unknown? or minute_unknown?
272 end
273
274 def as_string
275 s = sprintf("%02d", @hour)
276 if !@minute.nil?
277 s += ":" + sprintf("%02d",@minute)
278 if !@second.nil?
279 s += ":" + sprintf("%02d", @second)
280 if !@fractional_second.nil?
281 s += "." + @fractional_second.to_s[2..-1]
282 if !@timezone.nil?
283 s += @timezone
284 end
285 end
286 end
287 end
288 return s
289 end
290 end
291
292 class ISO8601_TIME < TIME_DEFINITIONS
293 include ISO8601_TIME_MODULE
294 def initialize(string)
295 /(\d{2}):?(\d{2})?(:?)(\d{2})?((\.|,)(\d+))?(Z|([+-](\d{2}):?(\d{2})))?/ =~ string
296 if $2.nil?
297 self.minute = nil
298 else
299 self.minute = $2.to_i
300 end
301 if $4.nil?
302 self.second = nil
303 else
304 self.second = $4.to_i
305 end
306 if $1.nil?
307 raise ArgumentError, 'data invalid'
308 else
309 self.hour = $1.to_i
310 end
311 if $7.nil?
312 self.fractional_second = nil
313 else
314 self.fractional_second = ("0." + $7).to_f
315 end
316 if $8.nil?
317 self.timezone = nil
318 else
319 self.timezone = $8
320 end
321 end
322 def self.valid_iso8601_time?(s)
323 if /(\d{2}):?(\d{2})?(:?)(\d{2})?((\.|,)(\d+))?(Z|([+-](\d{2}):?(\d{2})))?/ =~ s
324# ISO 8601 regular expression by H. Yuki
325# http://digit.que.ne.jp/work/wiki.cgi?Perl%E3%83%A1%E3%83%A2%2FW3C%E5%BD%A2%E5%BC%8F%E3%81%AE%E6%97%A5%E6%99%82%E3%81%AE%E8%A7%A3%E6%9E%90
326# (\d{4})(?:-(\d{2})(?:-(\d{2})(?:T(\d{2}):(\d{2})(?::(\d{2})(?:\.(\d))?)?(Z|([+-]\d{2}):(\d{2}))?)?)?)?
327 hh = $1; mm = $2; ss = $4; msec = $7; tz = $8
328 if hh.to_i == HOURS_IN_DAY and (mm.nil? or mm.to_i == 0) and (ss.nil? or ss.to_i == 0) and (msec.nil? or msec.to_i==0)
329 return true
330 end
331 if hh.nil? or (hh.to_i < 0 or hh.to_i >= HOURS_IN_DAY)
332 return false
333 end
334 if !mm.nil?
335 if !self.valid_minute?(mm.to_i)
336 return false
337 end
338 end
339 if !ss.nil?
340 if !self.valid_second?(ss.to_i)
341 return false
342 end
343 end
344 if !tz.nil? and tz != "Z"
345 if /[+-](\d{2}):?(\d{2})/ =~ tz
346 h = $1; m = $2
347 if h.to_i < 0 or h.to_i >= HOURS_IN_DAY
348 return false
349 end
350 if m.to_i < 0 or m.to_i >= MINUTES_IN_HOUR
351 return false
352 end
353 else
354 return false
355 end
356 end
357 return true
358 else
359 return false
360 end
361 end
362 end # end of ISO8601_TIME
363
364 module ISO8601_DATE_TIME_MODULE
365 include ISO8601_DATE_MODULE, ISO8601_TIME_MODULE
366 def as_string
367 if (!@year.nil? and !@month.nil? and !@day.nil?)
368 s = Date.new(@year, @month, @day).to_s
369 elsif (!@year.nil? and !@month.nil? and @day.nil?)
370 return Date.new(@year, @month).to_s[0,7]
371 elsif (!@year.nil? and @month.nil? and @day.nil?)
372 return Date.new(@year).to_s[0,4]
373 end
374 unless hour.nil?
375 s += sprintf("T%02d", @hour)
376 unless @minute.nil?
377 s += ":" + sprintf("%02d",@minute)
378 unless @second.nil?
379 s += ":" + sprintf("%02d", @second)
380 unless @fractional_second.nil?
381 s += "." + @fractional_second.to_s[2..-1]
382 unless @timezone.nil?
383 s += @timezone
384 end
385 end
386 end
387 end
388 end
389 return s
390 end
391 end
392
393 class ISO8601_DATE_TIME < ISO8601_DATE
394 include ISO8601_DATE_TIME_MODULE
395 def initialize(string)
396 /(\d{4})(?:-(\d{2})(?:-(\d{2})(?:T(\d{2}):(\d{2})(?::(\d{2})(?:\.(\d+))?)?(Z|([+-]\d{2}):?(\d{2}))?)?)?)?/ =~ string
397 if $1.empty?
398 raise ArgumentError, 'format invalid'
399 else
400 self.year = $1.to_i
401 end
402 if $2.nil?
403 self.month = nil
404 else
405 self.month = $2.to_i
406 end
407 if $3.nil?
408 self.day = nil
409 else
410 self.day = $3.to_i
411 end
412 if $5.nil?
413 self.minute = nil
414 else
415 self.minute = $5.to_i
416 end
417 if $6.nil?
418 self.second = nil
419 else
420 self.second = $6.to_i
421 end
422 if $4.nil?
423 self.hour = nil
424 else
425 self.hour = $4.to_i
426 end
427 if $7.nil? or $7.empty?
428 self.fractional_second = nil
429 else
430 self.fractional_second = ("0."+$7).to_f
431 end
432 if $8.nil?
433 self.timezone = nil
434 else
435 self.timezone = $9+$10
436 end
437 end
438 end
439
440 class ISO8601_TIMEZONE
441 attr_accessor :sign, :hour, :minute
442
443 def is_gmt?
444 @sign == "+1" and @hour == 0 and @minute == 0
445 end
446
447 def as_string
448 if @sign == "+1"
449 s = "+"
450 elsif @sign == "-1"
451 s = "-"
452 end
453 sprintf("Z%s%02d%02d", s, @hour, @minute)
454 end
455 end # end of ISO8601_TIMEZONE
456
457 module ISO8601_DURATION_MODULE
458 attr_reader :years, :months, :weeks, :days
459 attr_reader :hours, :minutes, :seconds, :fractional_second
460
461 def years=(years)
462 unless years.nil? || years >= 0
463 raise ArgumentError, 'years must be above zero'
464 end
465 @years = years
466 end
467
468 def months=(months)
469 unless months.nil? || months >= 0
470 raise ArgumentError, 'months must be above zero'
471 end
472 @months = months
473 end
474
475 def weeks=(weeks)
476 unless weeks.nil? || weeks >= 0
477 raise ArgumentError, 'weeks must be above zero'
478 end
479 @weeks = weeks
480 end
481
482 def days=(days)
483 unless days.nil? || days >= 0
484 raise ArgumentError, 'days must be above zero'
485 end
486 @days = days
487 end
488
489 def hours=(hours)
490 unless hours.nil? || hours >= 0
491 raise ArgumentError, 'hours must be above zero'
492 end
493 @hours = hours
494 end
495
496 def minutes=(minutes)
497 unless minutes.nil? || minutes >= 0
498 raise ArgumentError, 'minutes must be above zero'
499 end
500 @minutes = minutes
501 end
502
503 def seconds=(seconds)
504 unless seconds.nil? || seconds >= 0
505 raise ArgumentError, 'seconds must be above zero'
506 end
507 @seconds = seconds
508 end
509
510 def fractional_second=(fractional_second)
511 unless fractional_second.nil? || (fractional_second >= 0 && fractional_second < 1.0)
512 raise ArgumentError, 'fractional_second must be between 0.0 and 1.0'
513 end
514 @fractional_second = fractional_second
515 end
516
517 def as_string
518 str = 'P'
519 unless @years.nil?
520 str += @years.to_s + 'Y'
521 end
522 unless @months.nil?
523 str += @months.to_s + 'M'
524 end
525 unless @weeks.nil?
526 str += @weeks.to_s + 'W'
527 end
528 unless @days.nil?
529 str += @days.to_s + 'D'
530 end
531 unless @hours.nil?
532 str += 'T' + @hours.to_s + 'H'
533 unless @minutes.nil?
534 str += @minutes.to_s + 'M'
535 unless @seconds.nil?
536 str += @seconds.to_s
537 unless @fractional_second.nil?
538 str += @fractional_second.to_s[1 .. -1]
539 end
540 str += 'S'
541 end
542 end
543 end
544 return str
545 end
546 end
547 class ISO8601_DURATION < TIME_DEFINITIONS
548 include ISO8601_DURATION_MODULE
549 def initialize(str)
550 /^P((\d+)Y)?((\d+)M)?((\d+)W)?((\d)D)?(T((\d+)H)?((\d+)M)?((\d+)(\.\d+)?S)?)?$/ =~ str
551 self.years = $2.to_i
552 self.months = $4.to_i
553 self.weeks = $6.to_i
554 self.days = $8.to_i
555 self.hours = $11.to_i
556 self.minutes = $13.to_i
557 self.seconds = $15.to_i
558 self.fractional_second = $16.to_f
559 end
560 end # end of ISO8601_DURATION
561 end # end of Assumed_Types
562end # end of OpenEHR
Note: See TracBrowser for help on using the repository browser.