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, 11 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.