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

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

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