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
RevLine 
[83]1# This module is related to the ticket #36
[70]2require 'date'
[81]3require 'time'
[70]4
[216]5module OpenEHR
[167]6  module AssumedLibraryTypes
[69]7    class Any < Object
8     
9    end # of Any
[143]10
[69]11    class Interval < Any
[143]12      attr_reader :lower, :upper
13     
[4]14      def initialize(lower, upper,
15                     lower_included = nil, upper_included = nil)
16        check_lower_upper(lower, upper)
[143]17        self.lower_included = lower_included
18        self.upper_included = upper_included
[4]19      end
[21]20
[143]21      def lower=(lower)
[4]22        check_lower_upper(lower, @upper)
23      end
[21]24
[143]25      def upper=(upper)
[4]26        check_lower_upper(@lower, upper)
27      end
[21]28
[143]29      def lower_included?
30        return @lower_included
31      end
32
33      def lower_included=(lower_included)
[4]34        if (lower == nil) && (lower_included != nil)
35          raise ArgumentError, "lower is not set"
36        end
37        @lower_included = lower_included
38      end
[143]39     
40      def lower_unbounded?
41        return @lower.nil?
42      end
[21]43
[143]44      def upper_included?
45        return @upper_included
46      end
47
48      def upper_included=(upper_included)
[4]49        if (upper == nil) && (upper_included != nil)
50          raise ArgumentError, "upper is not set"
51        end
[143]52        @upper_included = upper_included
[4]53      end
[21]54
[143]55      def upper_unbounded?
56        return @upper.nil?
57      end
58
[4]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
[21]68
[4]69      private
[21]70
[4]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
[143]75        unless (lower.nil? || upper.nil?)
76          if lower > upper
77            raise ArgumentError, "Upper must be larger than lower."
78          end
[4]79        end
80        @lower = lower
81        @upper = upper
[143]82      end
[69]83    end # end of Interval
[143]84 
[69]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
[70]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
[83]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)
[70]114      end
[81]115      def self.valid_minute?(mi)
116        mi >= 0 and mi < MINUTES_IN_HOUR
[70]117      end
118      def self.valid_second?(s)
119        s >= 0 and s < SECONDS_IN_MINUTE
120      end
[81]121      def self.valid_month?(mo)
122        mo >= 1 and mo <= MONTH_IN_YEAR
[70]123      end
[69]124    end # end of TIME_DEFINITIONS
125
[120]126    module ISO8601_DATE_MODULE
[70]127      attr_reader :year, :month, :day
128      def year=(year)
[120]129        raise ArgumentError, "Year is not valid" unless ISO8601_DATE.valid_year?(year)
[70]130        @year = year
131      end
132      def month=(month)
[120]133        raise ArgumentError, "Month is not valid" unless month.nil? or ISO8601_DATE.valid_month?(month)
[70]134        @month = month
135      end
[125]136
[70]137      def day=(day)
[120]138        raise ArgumentError, "Day is not valid" unless day.nil? or ISO8601_DATE.valid_day?(@year, @month, day)
[70]139        @day = day
140      end
[125]141
[70]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
[125]151
[70]152      def month_unknown?
153        @month.nil?
154      end
[125]155
[70]156      def day_unknown?
157        @day.nil?
158      end
[125]159
[70]160      def is_extended?
161        true
162      end
[125]163
[70]164      def is_partial?
165        month_unknown? or day_unknown?
166      end
[149]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
[120]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
[149]198
[81]199      def self.valid_iso8601_date?(string)
[70]200        begin
[81]201          Date.parse(string)
[70]202        rescue
203          return false
204        end
205        true
206      end
[79]207    end # end of ISO8601_DATE
208
[120]209    module ISO8601_TIME_MODULE
[83]210      attr_reader :hour, :minute, :second, :fractional_second, :timezone
[120]211
[83]212      def hour=(hour)
213        raise ArgumentError, "hour is not valid" if !ISO8601_TIME.valid_hour?(hour, @minute, @second)
214        @hour = hour
215      end
[124]216
[83]217      def minute_unknown?
218        @minute.nil?
219      end
[124]220
[83]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
[124]225
[83]226      def second_unknown?
227        @second.nil?
228      end
[124]229
[83]230      def second=(second)
[120]231        raise ArgumentError, "minute not defined" if @minute.nil? and !second.nil?
[83]232        raise ArgumentError, "second is not valid" if !second.nil? and !ISO8601_TIME.valid_second?(second)
233        @second = second
234      end
[124]235
[83]236      def fractional_second=(fractional_second)
[120]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
[83]240        @fractional_second = fractional_second
241      end
[124]242
[83]243      def has_fractional_second?
244        if @fractional_second.nil?
245          return false
246        else
247          return true
248        end
249      end
[124]250
[120]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
[124]262
[83]263      def is_decimal_sign_comma?
[126]264        false
[83]265      end
[124]266
[83]267      def is_extended?
268        true
269      end
[124]270
[83]271      def is_partial?
272        second_unknown? or minute_unknown?
273      end
[125]274
[81]275      def as_string
[83]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?
[125]282              s += "." + @fractional_second.to_s[2..-1]
[83]283              if !@timezone.nil?
284                s += @timezone
[81]285              end
286            end
287          end
288        end
[125]289        return s
[81]290      end
[120]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
[81]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
[83]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)
[81]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
[79]363    end # end of ISO8601_TIME
364
[149]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
[120]394    class ISO8601_DATE_TIME < ISO8601_DATE
[149]395      include ISO8601_DATE_TIME_MODULE
[120]396      def initialize(string)
[121]397        /(\d{4})(?:-(\d{2})(?:-(\d{2})(?:T(\d{2}):(\d{2})(?::(\d{2})(?:\.(\d+))?)?(Z|([+-]\d{2}):?(\d{2}))?)?)?)?/ =~ string
[120]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
[121]428        if $7.nil? or $7.empty?
[120]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
[121]436          self.timezone = $9+$10
[120]437        end
438      end
439    end
[149]440 
[79]441    class ISO8601_TIMEZONE
442      attr_accessor :sign, :hour, :minute
[124]443
[79]444      def is_gmt?
[80]445        @sign == "+1" and @hour == 0 and @minute == 0
[79]446      end
[124]447
[79]448      def as_string
[80]449        if @sign == "+1"
450          s = "+"
451        elsif @sign == "-1"
452          s = "-"
453        end
454        sprintf("Z%s%02d%02d", s, @hour, @minute)
[79]455      end
456    end # end of ISO8601_TIMEZONE
[123]457
[149]458    module ISO8601_DURATION_MODULE
[126]459      attr_reader :years, :months, :weeks, :days
460      attr_reader :hours, :minutes, :seconds, :fractional_second
461
462      def years=(years)
[128]463        unless years.nil? || years >= 0
[126]464          raise ArgumentError, 'years must be above zero'
465        end
466        @years = years
467      end
[124]468
[126]469      def months=(months)
[128]470        unless months.nil? || months >= 0
[126]471          raise ArgumentError, 'months must be above zero'
472        end
473        @months = months
[124]474      end
[126]475
476      def weeks=(weeks)
[128]477        unless weeks.nil? || weeks >= 0
[126]478          raise ArgumentError, 'weeks must be above zero'
479        end
480        @weeks = weeks
481      end
482
483      def days=(days)
[128]484        unless days.nil? || days >= 0
[126]485          raise ArgumentError, 'days must be above zero'
486        end
487        @days = days
488      end
489
490      def hours=(hours)
[128]491        unless hours.nil? || hours >= 0
[126]492          raise ArgumentError, 'hours must be above zero'
493        end
494        @hours = hours
495      end
496
497      def minutes=(minutes)
[128]498        unless minutes.nil? || minutes >= 0
[126]499          raise ArgumentError, 'minutes must be above zero'
500        end
501        @minutes = minutes
502      end
503
504      def seconds=(seconds)
[128]505        unless seconds.nil? || seconds >= 0
[126]506          raise ArgumentError, 'seconds must be above zero'
507        end
508        @seconds = seconds
509      end
510
511      def fractional_second=(fractional_second)
[128]512        unless fractional_second.nil? || (fractional_second >= 0 && fractional_second < 1.0)
[126]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
[149]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
[124]561    end # end of ISO8601_DURATION
[69]562  end # end of Assumed_Types
563end # end of OpenEHR
Note: See TracBrowser for help on using the repository browser.