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

Last change on this file since 216 was 216, checked in by KOBAYASHI, Shinji, 11 years ago

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