icu4r_19 1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,87 @@
1
+ 25-May-2006
2
+ * ustring.c: preventing memory leaks when exception is thrown from block in UString#each_* methods
3
+
4
+ * fmt.cpp: preventing memory leaks when message can't be formatted (UString#fmt) or date parsed
5
+
6
+ 20-May-2006
7
+ * collator.c: a little docs added
8
+
9
+ * ustring.c, uregex.c: fixes in split(), UString#[regexp, index] now allows negative indices
10
+
11
+ * test/test_ustring.rb: more tests
12
+
13
+ 27-Apr-2006
14
+ * collator.c: added UCollator class
15
+
16
+ * converter.c: added UConverter class
17
+
18
+ 24-Apr-2006
19
+ * UString: added eql? method (fixes usage of UString as Hash key); fixed sentinel bug in normalize
20
+
21
+ * test/test_calendar: removing some dependencies from ICU content and user locale in test_default and test_time_zones (by report of Daigo Moriwaki)
22
+
23
+ 02-Feb-2006
24
+ * UString: moved parse_date to UCalendar.parse
25
+
26
+ * UResourceBundle: aref can accept additional parameter and return actual locale
27
+
28
+ * UCalendar: simplified formmating options
29
+
30
+ 26-Jan-2006
31
+ * UString: sub, gsub, scan, each_* now set "busy" flag before calling block, thus preventing scanned string to be modfied inside block
32
+
33
+ * ustring.c: fixed? bug with sentinels, also Array#to_u, and fixed again
34
+
35
+ 25-Jan-2006
36
+ * UString: addde foldcase method
37
+
38
+ * UString: added char_span(start,[len, locale]) method.
39
+
40
+ * ustring.c: fixed bug with incorrect sentinel set in splice_units
41
+
42
+ 24-Jan-2006:
43
+ * split source code to: uregex.c, ubundle.c, ucore_ext.c
44
+
45
+ * changed main lib name: icu4r.c
46
+
47
+ 23-Jan-2006:
48
+ * UCalendar: added <, ==, >, clone, equal? methods
49
+
50
+ * UResourceBundle: throw an exception on clone
51
+
52
+ 22-Jan-2006
53
+ * added tests for UCalendar
54
+
55
+ * calendar.c: UCalendar services added
56
+
57
+ 21-Jan-2006
58
+ * UString#to_s: removed NFC before conversion
59
+
60
+ * fmt.cpp: extern problem bugfix(?)
61
+
62
+ 20-Jan-2006:
63
+ * UString: strictly sticking with code unit ranges, cleanup
64
+
65
+ * Array#to_u: replace invalid chars with U+FFFD
66
+
67
+ 19-Jan-2006
68
+ * UString#chars: added NFC before split
69
+
70
+ * UString#to_s: added NFC before conversion
71
+
72
+ * UString#normalize: added quick checks before normalization
73
+
74
+ * UString#split: removed split(//) support
75
+
76
+ * UString: fixed bugs with ranges: slice, conv_unit_range, conv_point_range
77
+
78
+ * UString: added unescape method
79
+
80
+ * UString: cleanup initializations - now uniform icu_ustr_alloc_and_wrap
81
+
82
+ * UString#sub!: now calls gsub
83
+
84
+ * UResourceBundle: added open_direct
85
+
86
+ 18-Jan-2006
87
+ * initial release 0.1.0
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2006 Nikolai Lugovoi
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README ADDED
@@ -0,0 +1,156 @@
1
+ == ICU4R - ICU Unicode bindings for Ruby
2
+
3
+ ICU4R is an attempt to provide better Unicode support for Ruby,
4
+ where it lacks for a long time.
5
+
6
+ Current code is mostly rewritten string.c from Ruby 1.8.3.
7
+
8
+ ICU4R is Ruby C-extension binding for ICU library[1]
9
+ and provides following classes and functionality:
10
+
11
+ * UString:
12
+ - String-like class with internal UTF16 storage;
13
+ - UCA rules for UString comparisons (<=>, casecmp);
14
+ - encoding(codepage) conversion;
15
+ - Unicode normalization;
16
+ - transliteration, also rule-based;
17
+
18
+ Bunch of locale-sensitive functions:
19
+ - upcase/downcase;
20
+ - string collation;
21
+ - string search;
22
+ - iterators over text line/word/char/sentence breaks;
23
+ - message formatting (number/currency/string/time);
24
+ - date and number parsing.
25
+
26
+ * URegexp - unicode regular expressions.
27
+
28
+ * UResourceBundle - access to resource bundles, including ICU locale data.
29
+
30
+ * UCalendar - date manipulation and timezone info.
31
+
32
+ * UConverter - codepage conversions API
33
+
34
+ * UCollator - locale-sensitive string comparison
35
+
36
+ == Install and usage
37
+
38
+ > ruby extconf.rb
39
+ > make && make check
40
+ > make install
41
+
42
+ Now, in your scripts just require 'icu4r'.
43
+
44
+ To create RDoc, run
45
+ > sh tools/doc.sh
46
+
47
+ == Requirements
48
+
49
+ To build and use ICU4R you will need GCC and ICU v3.4 libraries[2].
50
+
51
+ == Differences from Ruby String and Regexp classes
52
+
53
+ === UString vs String
54
+
55
+ 1. UString substring/index methods use UTF16 codeunit indexes, not code points.
56
+
57
+ 2. UString supports most methods from String class. Missing methods are:
58
+ capitalize, capitalize!, swapcase, swapcase!
59
+ %, center, ljust, rjust
60
+ chomp, chomp!, chop, chop!
61
+ count, delete, delete!, squeeze, squeeze!, tr, tr!, tr_s, tr_s!
62
+ crypt, intern, sum, unpack
63
+ dump, each_byte, each_line
64
+ hex, oct, to_i, to_sym
65
+ reverse, reverse!
66
+ succ, succ!, next, next!, upto
67
+
68
+ 3. Instead of String#% method, UString#format is provided. See FORMATTING for short reference.
69
+
70
+ 4. UStrings can be created via String.to_u(encoding='utf8') or global u(str,[encoding='utf8'])
71
+ calls. Note that +encoding+ parameter must be value of String class.
72
+
73
+ 5. There's difference between character grapheme, codepoint and codeunit. See UNICODE reports for
74
+ gory details, but in short: locale dependent notion of character can be presented using
75
+ more than one codepoint - base letter and combining (accents) (also possible more than one!), and
76
+ each codepoint can require more than one codeunit to store (for UTF8 codeunit size is 8bit, though
77
+ some codepoints require up to 4bytes). So, UString has normalization and locale dependent break
78
+ iterators.
79
+
80
+ 6. Currently UString doesn't include Enumerable module.
81
+
82
+ 7. UString index/[] methods which accept URegexp, throw exception if Regexp passed.
83
+
84
+ 8. UString#<=>, UString#casecmp use UCA rules.
85
+
86
+ === URegexp
87
+
88
+ UString uses ICU regexp library. Pattern syntax is described in [./docs/UNICODE_REGEXPS] and ICU docs.
89
+
90
+ There are some differences between processing in Ruby Regexp and URegexp:
91
+
92
+ 1. When UString#sub, UString#gsub are called with block, special vars ($~, $&, $1, ...) aren't
93
+ set, as their values are processed through deep ruby core code. Instead, block receives UMatch object,
94
+ which is essentially immutable array of matching groups:
95
+ "test".u.gsub(ure("(e)(.)")) do |match|
96
+ puts match[0] # => 'es' <--> $&
97
+ puts match[1] # => 'e' <--> $1
98
+ puts match[2] # => 's' <--> $2
99
+ end
100
+
101
+ 2. In URegexp search pattern backreferences are in form \n (\1, \2, ...),
102
+ in replacement string - in form $1, $2, ...
103
+
104
+ NOTE: URegexp considers char to be a digit NOT ONLY ASCII (0x0030-0x0039), but
105
+ any Unicode char, which has property Decimal digit number (Nd), e.g.:
106
+ a = [?$, 0x1D7D9].pack("U*").u * 2
107
+ puts a.inspect_names
108
+ <U000024>DOLLAR SIGN
109
+ <U01D7D9>MATHEMATICAL DOUBLE-STRUCK DIGIT ONE
110
+ <U000024>DOLLAR SIGN
111
+ <U01D7D9>MATHEMATICAL DOUBLE-STRUCK DIGIT ONE
112
+ puts "abracadabra".u.gsub(/(b)/.U, a)
113
+ abbracadabbra
114
+
115
+
116
+ 3. One can create URegexp using global Kernel#ure function, Regexp#U, Regexp#to_u, or
117
+ from UString using URegexp.new, e.g:
118
+ /pattern/.U =~ "string".u
119
+
120
+ 4. There are differences about Regexp and URegexp multiline matching options:
121
+ t = "text\ntest"
122
+ # ^,$ handling : URegexp multiline <-> Ruby default
123
+ t.u =~ ure('^\w+$', URegexp::MULTILINE)
124
+ => #<UMatch:0xf6f7de04 @ranges=[0..3], @cg=[\u0074\u0065\u0078\u0074]>
125
+ t =~ /^\w+$/
126
+ => 0
127
+ # . matches \n : URegexp DOTALL <-> /m
128
+ t.u =~ ure('.+test', URegexp::DOTALL)
129
+ => #<UMatch:0xf6fa4d88 ...
130
+ t.u =~ /.+test/m
131
+
132
+ 5. UMatch.range(idx) returns range for capturing group idx. This range is in codeunits.
133
+
134
+ === References
135
+
136
+ 1. ICU Official Homepage http://ibm.com/software/globalization/icu/
137
+ 2. ICU downloads http://ibm.com/software/globalization/icu/downloads.jsp
138
+ 3. ICU Home Page http://icu.sf.net
139
+ 4. Unicode Home Page http://www.unicode.org
140
+
141
+ ==== BUGS, DOCS, TO DO
142
+
143
+ The code is slow and inefficient yet, is still highly experimental,
144
+ so can have many security and memory leaks, bugs, inconsistent
145
+ documentation, incomplete test suite. Use it at your own risk.
146
+
147
+ Bug reports and feature requests are welcome :)
148
+
149
+ === Copying
150
+
151
+ This extension module is copyrighted free software by Nikolai Lugovoi.
152
+
153
+ You can redistribute it and/or modify it under the terms of MIT License.
154
+
155
+ Nikolai Lugovoi <meadow.nnick@gmail.com>
156
+
@@ -0,0 +1,32 @@
1
+ require 'rake/gempackagetask'
2
+ spec = Gem::Specification.new do |s|
3
+ s.authors = [ "Nikolai Lugovoi", "Perry Smith" ]
4
+ s.description = File.read(File.join(File.dirname(__FILE__), 'README'))
5
+ s.email = "pedz@easesoftware.com"
6
+ s.extensions = [ 'extconf.rb' ]
7
+ s.extra_rdoc_files = [
8
+ 'README',
9
+ 'docs/FORMATTING',
10
+ 'docs/UNICODE_REGEXPS',
11
+ 'MIT-LICENSE',
12
+ 'calendar.c',
13
+ 'collator.c',
14
+ 'converter.c',
15
+ 'icu4r.c',
16
+ 'ubundle.c',
17
+ 'ucore_ext.c',
18
+ 'uregex.c',
19
+ 'ustring.c'
20
+ ]
21
+ s.files = Dir['**/**']
22
+ s.has_rdoc = true
23
+ s.homepage = "https://github.com/pedz/icu4r_19"
24
+ s.name = "icu4r_19"
25
+ s.platform = Gem::Platform::RUBY
26
+ s.rdoc_options = [ '-c', 'utf-8', '-x', 'dummy' ]
27
+ s.required_ruby_version = '>=1.9'
28
+ s.requirements = [ 'ICU libraries v 4.6.1' ]
29
+ s.summary = "Ruby extension for Unicode support using ICU - 1.9.2 compatible"
30
+ s.version = "1.0"
31
+ end
32
+ Rake::GemPackageTask.new(spec).define
@@ -0,0 +1,636 @@
1
+ #include <unicode/ucal.h>
2
+ #include <unicode/uenum.h>
3
+ #include <unicode/udat.h>
4
+ #include "icu_common.h"
5
+ extern VALUE rb_cUString;
6
+ extern VALUE icu_ustr_new(UChar * ptr, long len);
7
+ extern VALUE icu_ustr_new_set(UChar * ptr, long len, long capa);
8
+ static VALUE s_calendar_fields, s_calendar_formats;
9
+ extern VALUE rb_cUCalendar;
10
+ #define UCALENDAR(obj) ((UCalendar *)DATA_PTR(obj))
11
+ /**
12
+ * Document-class: UCalendar
13
+ *
14
+ * The UCalendar class provides methods for converting between a specific instant in
15
+ * time and a set of calendar fields such as YEAR, MONTH, DAY_OF_MONTH, HOUR, and so on,
16
+ * and for manipulating the calendar fields, such as getting the date of the next week.
17
+ * An instant in time can be represented by a millisecond value that is an offset from the
18
+ * Epoch, January 1, 1970 00:00:00.000 GMT (Gregorian).
19
+ *
20
+ * Also timezone info and methods are provided.
21
+ *
22
+ * NOTE: months are zero-based.
23
+ */
24
+
25
+ /**
26
+ * call-seq:
27
+ * UCalendar.time_zones
28
+ *
29
+ * Returns array with all time zones (as UString values).
30
+ */
31
+ VALUE icu4r_cal_all_tz (VALUE obj)
32
+ {
33
+ UErrorCode status = U_ZERO_ERROR;
34
+ UEnumeration * zones ;
35
+ VALUE ret ;
36
+ UChar * name;
37
+ int32_t len;
38
+ zones = ucal_openTimeZones (&status);
39
+ ICU_RAISE(status);
40
+ ret = rb_ary_new();
41
+ while( (name = (UChar*)uenum_unext(zones, &len, &status))) {
42
+ rb_ary_push(ret, icu_ustr_new(name, len));
43
+ }
44
+ uenum_close(zones);
45
+ return ret;
46
+ }
47
+
48
+
49
+ /**
50
+ * call-seq:
51
+ * UCalendar.tz_for_country(country)
52
+ *
53
+ * Returns array with all time zones associated with the given country.
54
+ * Note: <code>country</code> must be value of type String.
55
+ * Returned array content is UString's
56
+ *
57
+ * UCalendar.tz_for_country("GB") # => [ "Europe/Belfast", "Europe/London", "GB", "GB-Eire"]
58
+ *
59
+ */
60
+ VALUE icu4r_cal_country_tz (VALUE obj, VALUE ctry)
61
+ {
62
+ UErrorCode status = U_ZERO_ERROR;
63
+ UEnumeration * zones ;
64
+ VALUE ret ;
65
+ UChar * name;
66
+ int32_t len;
67
+ Check_Type(ctry, T_STRING);
68
+ zones = ucal_openCountryTimeZones (RSTRING_PTR(ctry), &status) ;
69
+ ICU_RAISE(status);
70
+ ret = rb_ary_new();
71
+ while( (name = (UChar*)uenum_unext(zones, &len, &status))) {
72
+ rb_ary_push(ret, icu_ustr_new(name, len));
73
+ }
74
+ uenum_close(zones);
75
+ return ret;
76
+ }
77
+
78
+ /**
79
+ * call-seq:
80
+ * UCalendar.default_tz => ustring
81
+ *
82
+ * Returns the default time zone name as UString.
83
+ *
84
+ * UCalendar.default_tz # "EET"
85
+ *
86
+ */
87
+ VALUE icu4r_cal_get_default_tz(VALUE obj)
88
+ {
89
+ UErrorCode status = U_ZERO_ERROR;
90
+ UChar * buf ;
91
+ long capa = 0;
92
+ capa = ucal_getDefaultTimeZone (buf, capa, &status);
93
+ if( U_BUFFER_OVERFLOW_ERROR == status) {
94
+ buf = ALLOC_N(UChar, capa+1);
95
+ status = U_ZERO_ERROR;
96
+ capa = ucal_getDefaultTimeZone (buf, capa, &status);
97
+ return icu_ustr_new_set(buf, capa, capa+1);
98
+ }
99
+ ICU_RAISE(status);
100
+ return Qnil;
101
+ }
102
+
103
+ /**
104
+ * call-seq:
105
+ * UCalendar.default_tz = ustring
106
+ *
107
+ * Set the default time zone.
108
+ *
109
+ * UCalendar.default_tz="GMT+00".u
110
+ * UCalendar.default_tz="Europe/Paris".u
111
+ */
112
+ VALUE icu4r_cal_set_default_tz(VALUE obj, VALUE tz)
113
+ {
114
+ UErrorCode status = U_ZERO_ERROR;
115
+ Check_Class(tz, rb_cUString);
116
+ ucal_setDefaultTimeZone (ICU_PTR(tz), &status);
117
+ ICU_RAISE(status);
118
+ return tz;
119
+ }
120
+ /**
121
+ * call-seq:
122
+ * UCalendar.dst_savings(zone_id)
123
+ *
124
+ * Return the amount of time in milliseconds that the clock is advanced
125
+ * during daylight savings time for the given time zone, or zero if the time
126
+ * zone does not observe daylight savings time.
127
+ *
128
+ * UCalendar.dst_savings("GMT+00".u) # => 3600000
129
+ *
130
+ */
131
+ VALUE icu4r_cal_dst_savings(VALUE obj, VALUE zone)
132
+ {
133
+ UErrorCode status = U_ZERO_ERROR;
134
+ int32_t dst;
135
+ Check_Class(zone, rb_cUString);
136
+ dst = ucal_getDSTSavings (ICU_PTR(zone), &status);
137
+ ICU_RAISE(status);
138
+ return INT2FIX(dst);
139
+ }
140
+
141
+ /**
142
+ * call-seq:
143
+ * UCalendar.now
144
+ *
145
+ * Get the current date and time. in millis
146
+ *
147
+ * UCalendar.now # => 1137934561000.0
148
+ *
149
+ */
150
+ VALUE icu4r_cal_now(VALUE obj){
151
+ return rb_float_new(ucal_getNow());
152
+ }
153
+ //-----------------
154
+
155
+ void icu4r_cal_free(UCalendar * cal){
156
+ ucal_close(cal);
157
+ }
158
+ static VALUE icu4r_cal_alloc(VALUE klass)
159
+ {
160
+ return Data_Wrap_Struct(klass, 0, icu4r_cal_free, 0);
161
+ }
162
+ /**
163
+ * call-seq:
164
+ * UCalendar.new(zone_id = nil, locale = nil, traditional = false)
165
+ *
166
+ * Creates new instance of UCalendar, for given time zone id (UString),
167
+ * locale (Ruby String), and kind , by default gregorian.
168
+ * New instance has current time.
169
+ *
170
+ */
171
+ VALUE icu4r_cal_init (int argc, VALUE * argv, VALUE self)
172
+ {
173
+ VALUE zone, loc, cal_type;
174
+ UChar * zone_id = NULL;
175
+ char * locale = NULL;
176
+ UCalendarType c_type = UCAL_GREGORIAN;
177
+ int32_t n, zone_len =0 , locale_len =0;
178
+ UCalendar * calendar;
179
+ UErrorCode status = U_ZERO_ERROR;
180
+ n = rb_scan_args(argc, argv, "03", &zone, &loc, &cal_type);
181
+ if( n >= 1) {
182
+ Check_Class(zone, rb_cUString);
183
+ zone_id = ICU_PTR(zone);
184
+ zone_len = ICU_LEN(zone);
185
+ }
186
+ if( n >= 2) {
187
+ Check_Type(loc, T_STRING);
188
+ locale = RSTRING_PTR(loc);
189
+ locale_len = RSTRING_LEN(loc);
190
+ }
191
+ if( n >= 3) {
192
+ if( Qtrue == cal_type ) {
193
+ c_type = UCAL_TRADITIONAL;
194
+ }
195
+ }
196
+ calendar = ucal_open(zone_id, zone_len, locale, c_type, &status);
197
+ ICU_RAISE(status);
198
+ DATA_PTR(self) = calendar;
199
+ return self;
200
+ }
201
+
202
+ int icu4r_get_cal_field_int(VALUE field)
203
+ {
204
+ VALUE field_const;
205
+ field_const = rb_hash_aref(s_calendar_fields, field);
206
+ if(field_const == Qnil)
207
+ rb_raise(rb_eArgError, "no such field %s", RSTRING_PTR(rb_obj_as_string(field)));
208
+ return NUM2INT(field_const);
209
+ }
210
+
211
+ /**
212
+ * call-seq:
213
+ * calendar.add(field, int_amount)
214
+ *
215
+ * Add a specified signed amount to a particular field in a UCalendar.
216
+ *
217
+ * c.add(:week_of_year, 2)
218
+ */
219
+ VALUE icu4r_cal_add(VALUE obj, VALUE field, VALUE amount)
220
+ {
221
+ UErrorCode status = U_ZERO_ERROR;
222
+ int date_field;
223
+ Check_Type(field, T_SYMBOL);
224
+ Check_Type(amount, T_FIXNUM);
225
+ date_field = icu4r_get_cal_field_int(field);
226
+ ucal_add(UCALENDAR(obj), date_field, FIX2INT(amount) , &status);
227
+ ICU_RAISE(status);
228
+ return Qnil;
229
+ }
230
+
231
+ /**
232
+ * call-seq:
233
+ * calendar.roll(field, int_amount)
234
+ *
235
+ * Adds a signed amount to the specified calendar field without changing larger fields.
236
+ * A negative roll amount means to subtract from field without changing larger fields.
237
+ * If the specified amount is 0, this method performs nothing.
238
+ *
239
+ * Example: Consider a GregorianCalendar originally set to August 31, 1999. Calling roll(:month, 8)
240
+ * sets the calendar to April 30, 1999. Using a Gregorian Calendar, the :day_of_month field cannot
241
+ * be 31 in the month April. :day_of_month is set to the closest possible value, 30. The :year field
242
+ * maintains the value of 1999 because it is a larger field than :month.
243
+ */
244
+ VALUE icu4r_cal_roll(VALUE obj, VALUE field, VALUE amount)
245
+ {
246
+ UErrorCode status = U_ZERO_ERROR;
247
+ int date_field;
248
+ Check_Type(field, T_SYMBOL);
249
+ Check_Type(amount, T_FIXNUM);
250
+ date_field = icu4r_get_cal_field_int(field);
251
+ ucal_roll(UCALENDAR(obj), date_field, FIX2INT(amount) , &status);
252
+ ICU_RAISE(status);
253
+ return Qnil;
254
+ }
255
+ /**
256
+ * call-seq:
257
+ * calendar[field]
258
+ *
259
+ * Get the current value of a field from a UCalendar.
260
+ *
261
+ */
262
+ VALUE icu4r_cal_aref(VALUE obj, VALUE field)
263
+ {
264
+ UErrorCode status = U_ZERO_ERROR;
265
+ int date_field;
266
+ int32_t value;
267
+ Check_Type(field, T_SYMBOL);
268
+ date_field = icu4r_get_cal_field_int(field);
269
+ value = ucal_get(UCALENDAR(obj), date_field, &status);
270
+ ICU_RAISE(status);
271
+ return INT2FIX(value);
272
+ }
273
+
274
+ /**
275
+ * call-seq:
276
+ * calendar[field]=int_value
277
+ *
278
+ * Set the value of a field in a UCalendar.
279
+ */
280
+ VALUE icu4r_cal_aset(VALUE obj, VALUE field, VALUE amount)
281
+ {
282
+ int date_field, ret;
283
+ UErrorCode status = U_ZERO_ERROR;
284
+ Check_Type(field, T_SYMBOL);
285
+ Check_Type(amount, T_FIXNUM);
286
+ date_field = icu4r_get_cal_field_int(field);
287
+ ucal_set(UCALENDAR(obj), date_field, FIX2INT(amount) );
288
+ ret = ucal_get(UCALENDAR(obj), date_field, &status);
289
+
290
+ return INT2FIX(ret);
291
+ }
292
+ /**
293
+ * call-seq:
294
+ * calendar.millis
295
+ *
296
+ * return this calendar value in milliseconds.
297
+ */
298
+ VALUE icu4r_cal_millis(VALUE obj)
299
+ {
300
+ UErrorCode status = U_ZERO_ERROR;
301
+ double millis;
302
+ millis = ucal_getMillis(UCALENDAR(obj), &status);
303
+ ICU_RAISE(status);
304
+ return rb_float_new(millis);
305
+ }
306
+ /**
307
+ * call-seq:
308
+ * calendar.millis = new_value
309
+ *
310
+ * Sets calendar's value in milliseconds.
311
+ */
312
+ VALUE icu4r_cal_set_millis(VALUE obj,VALUE milli)
313
+ {
314
+ UErrorCode status = U_ZERO_ERROR;
315
+ Check_Type(milli, T_FLOAT);
316
+ ucal_setMillis(UCALENDAR(obj), rb_num2dbl(milli), &status);
317
+ ICU_RAISE(status);
318
+ return Qnil;
319
+ }
320
+
321
+ /**
322
+ * call-seq:
323
+ * calendar.set_date(year, month, date)
324
+ *
325
+ * Set a UCalendar's current date.
326
+ */
327
+ VALUE icu4r_cal_set_date(VALUE obj,VALUE year, VALUE mon, VALUE date)
328
+ {
329
+ UErrorCode status = U_ZERO_ERROR;
330
+ Check_Type(year, T_FIXNUM);
331
+ Check_Type(mon, T_FIXNUM);
332
+ Check_Type(date, T_FIXNUM);
333
+ ucal_setDate(UCALENDAR(obj), FIX2INT(year), FIX2INT(mon), FIX2INT(date), &status);
334
+ ICU_RAISE(status);
335
+ return Qnil;
336
+ }
337
+ /**
338
+ * call-seq:
339
+ * calendar.set_date_time(year, month, date, hour, minute, second)
340
+ *
341
+ * Set a UCalendar's current date and time.
342
+ */
343
+ VALUE icu4r_cal_set_date_time(VALUE obj,VALUE year, VALUE mon, VALUE date, VALUE hour, VALUE min, VALUE sec)
344
+ {
345
+ UErrorCode status = U_ZERO_ERROR;
346
+ Check_Type(year, T_FIXNUM);
347
+ Check_Type(mon, T_FIXNUM);
348
+ Check_Type(date, T_FIXNUM);
349
+ Check_Type(hour, T_FIXNUM);
350
+ Check_Type(min, T_FIXNUM);
351
+ Check_Type(sec, T_FIXNUM);
352
+
353
+ ucal_setDateTime(UCALENDAR(obj),
354
+ FIX2INT(year), FIX2INT(mon), FIX2INT(date),
355
+ FIX2INT(hour), FIX2INT(min), FIX2INT(sec),
356
+ &status);
357
+ ICU_RAISE(status);
358
+ return Qnil;
359
+ }
360
+
361
+ /**
362
+ * call-seq:
363
+ * calendar.time_zone = zone_id
364
+ *
365
+ * Set the TimeZone used by a UCalendar.
366
+ */
367
+ VALUE icu4r_cal_set_tz(VALUE obj, VALUE zone)
368
+ {
369
+ UErrorCode status = U_ZERO_ERROR;
370
+ Check_Class(zone, rb_cUString);
371
+ ucal_setTimeZone(UCALENDAR(obj), ICU_PTR(zone), ICU_LEN(zone), &status);
372
+ ICU_RAISE(status);
373
+ return Qnil;
374
+
375
+ }
376
+
377
+ /**
378
+ * call-seq:
379
+ * calendar.in_daylight_time?
380
+ *
381
+ * Determine if a UCalendar is currently in daylight savings time.
382
+ *
383
+ * Daylight savings time is not used in all parts of the world
384
+ */
385
+ VALUE icu4r_cal_in_daylight(VALUE obj)
386
+ {
387
+ UErrorCode status = U_ZERO_ERROR;
388
+ int32_t answer;
389
+ answer = ucal_inDaylightTime(UCALENDAR(obj), &status);
390
+ ICU_RAISE(status);
391
+ return answer ? Qtrue : Qfalse;
392
+ }
393
+
394
+ /**
395
+ * call-seq:
396
+ * calendar.time_zone(locale = nil)
397
+ *
398
+ * Returns the TimeZone name used in this UCalendar. Name is returned in requested locale or default, if not set.
399
+ */
400
+ VALUE icu4r_cal_get_tz (int argc, VALUE * argv, VALUE obj)
401
+ {
402
+ UErrorCode status = U_ZERO_ERROR;
403
+ UChar * buf = NULL;
404
+ long capa = 0;
405
+ char *locale = NULL;
406
+ VALUE loc;
407
+ if( rb_scan_args(argc, argv, "01", &loc) == 1){
408
+ Check_Type(loc, T_STRING);
409
+ locale = RSTRING_PTR(loc);
410
+ }
411
+
412
+ capa = ucal_getTimeZoneDisplayName(UCALENDAR(obj), UCAL_STANDARD, locale, buf, capa, &status);
413
+ if( U_BUFFER_OVERFLOW_ERROR == status) {
414
+ buf = ALLOC_N(UChar, capa+1);
415
+ status = U_ZERO_ERROR;
416
+ capa = ucal_getTimeZoneDisplayName(UCALENDAR(obj), UCAL_STANDARD, locale, buf, capa, &status);
417
+ return icu_ustr_new_set(buf, capa, capa+1);
418
+ }
419
+ ICU_RAISE(status);
420
+ return Qnil;
421
+
422
+ }
423
+ int icu4r_get_cal_format_int(VALUE field)
424
+ {
425
+ VALUE field_const;
426
+ field_const = rb_hash_aref(s_calendar_formats, field);
427
+ if(field_const == Qnil) {
428
+ rb_warn("no such format %s , using default", RSTRING_PTR(rb_obj_as_string(field)));
429
+ return UDAT_DEFAULT;
430
+ }
431
+ return NUM2INT(field_const);
432
+ }
433
+ /** call-seq:
434
+ * calendar.format(pattern = nil , locale = nil)
435
+ *
436
+ * Formats this calendar time using given pattern and locale. Returns UString or nil on failure.
437
+ * Valid value types for pattern are:
438
+ * nil - long format for date and time
439
+ * UString - specification of format, as defined in docs/FORMATTING
440
+ * Symbol - one of :short, :medium, :long, :full, :none , sets format for both date and time
441
+ * Hash - {:time => aSymbol, :date => aSymbol} - sets separate formats for date and time, valid symbols see above
442
+ */
443
+ VALUE icu4r_cal_format(int argc, VALUE * argv, VALUE obj)
444
+ {
445
+ UErrorCode status = U_ZERO_ERROR;
446
+ UDateFormat * format;
447
+ UDate time_to_format;
448
+ UChar * buf = NULL, * pattern = NULL;
449
+ long capa = 0, pattern_len = 0;
450
+ char *locale = NULL;
451
+ VALUE loc, pat, ret = Qnil;
452
+ int n , def_d_format = UDAT_FULL, def_t_format = UDAT_FULL;
453
+
454
+ n = rb_scan_args(argc, argv, "02", &pat, &loc);
455
+ if( n == 2) {
456
+ Check_Type(loc, T_STRING);
457
+ locale = RSTRING_PTR(loc);
458
+ }
459
+ if (n >= 1 && pat != Qnil) {
460
+ switch(TYPE(pat)) {
461
+ case T_SYMBOL:
462
+ def_d_format = def_t_format = icu4r_get_cal_format_int(pat);
463
+ break;
464
+ case T_HASH:
465
+ def_d_format = icu4r_get_cal_format_int(rb_hash_aref(pat, ID2SYM(rb_intern("date"))));
466
+ def_t_format = icu4r_get_cal_format_int(rb_hash_aref(pat, ID2SYM(rb_intern("time"))));
467
+ break;
468
+ default:
469
+ Check_Class(pat, rb_cUString);
470
+ pattern = ICU_PTR(pat);
471
+ pattern_len = ICU_LEN(pat);
472
+ break;
473
+ }
474
+ }
475
+
476
+ format = udat_open(def_t_format, def_d_format, locale, NULL, 0, NULL, 0, &status);
477
+ if( pattern ) {
478
+ udat_applyPattern(format, 0, pattern, pattern_len);
479
+ }
480
+ ICU_RAISE(status);
481
+ udat_setCalendar(format, UCALENDAR(obj));
482
+ time_to_format = ucal_getMillis(UCALENDAR(obj), &status);
483
+
484
+ capa = udat_format(format, time_to_format, buf, capa, NULL, &status);
485
+ if( U_BUFFER_OVERFLOW_ERROR == status) {
486
+ buf = ALLOC_N(UChar, capa+1);
487
+ status = U_ZERO_ERROR;
488
+ capa = udat_format(format, time_to_format, buf, capa, NULL, &status);
489
+ ret = icu_ustr_new_set(buf, capa, capa+1);
490
+ }
491
+ udat_close(format);
492
+ ICU_RAISE(status);
493
+ return ret;
494
+ }
495
+
496
+ /**
497
+ * Document-method: clone
498
+ *
499
+ * call-seq:
500
+ * cal.clone => UCalendar
501
+ *
502
+ * Create and return a copy of this calendar.
503
+ */
504
+ extern VALUE icu4r_cal_clone(VALUE obj);
505
+ /**
506
+ * Document-method: eql?
507
+ *
508
+ * call-seq:
509
+ * cal.eql?(other)
510
+ *
511
+ * Compares the equality of two UCalendar objects.
512
+ *
513
+ * This comparison is very exacting; two UCalendar objects must be in exactly the
514
+ * same state to be considered equal.
515
+ */
516
+ extern VALUE icu4r_cal_equal(VALUE obj, VALUE other);
517
+
518
+ /**
519
+ * call-seq:
520
+ * cal <=> other_cal => -1, 0, +1
521
+ *
522
+ * Comparison---Returns -1 if <i>other_cal</i> is before than, 0 if
523
+ * <i>other_cal</i> is equal to, and +1 if <i>other_cal</i> is after than
524
+ * <i>str</i>.
525
+ *
526
+ * Value of calendar's milliseconds are compared.
527
+ */
528
+
529
+ VALUE icu4r_cal_cmp (VALUE c1, VALUE c2)
530
+ {
531
+ UErrorCode status = U_ZERO_ERROR;
532
+ double millis1, millis2;
533
+ Check_Class(c1, rb_cUCalendar);
534
+ Check_Class(c2, rb_cUCalendar);
535
+ millis1 = ucal_getMillis(UCALENDAR(c1), &status);
536
+ millis2 = ucal_getMillis(UCALENDAR(c2), &status);
537
+ ICU_RAISE(status);
538
+ if(millis1 < millis2) return INT2FIX(-1);
539
+ if(millis1 > millis2) return INT2FIX(1);
540
+ return INT2FIX(0);
541
+ }
542
+ /* parsing */
543
+ extern UCalendar * icu_date_parse(UChar * str, int32_t str_len, char * locale, UChar * val, int32_t len);
544
+
545
+ /**
546
+ * call-seq:
547
+ * UCalendar.parse( pattern, locale, value)
548
+ *
549
+ * Parses given value, using format pattern with respect to +locale+.
550
+ *
551
+ * UCalendar.parse("HH:mm:ss E dd/MM/yyyy".u, "en", "20:15:01 Fri 13/01/2006".u) # => Time.local(2006,"jan",13,20,15,1)
552
+ *
553
+ */
554
+
555
+ VALUE
556
+ icu4r_cal_parse( obj, str, locale, val)
557
+ VALUE obj, str, locale, val;
558
+ {
559
+ UCalendar * cal;
560
+ VALUE ret;
561
+ Check_Type(locale, T_STRING);
562
+ Check_Class(val, rb_cUString);
563
+ cal = icu_date_parse(ICU_PTR(str), ICU_LEN(str), RSTRING_PTR(locale), ICU_PTR(val), ICU_LEN(val));
564
+ ret = Data_Wrap_Struct(obj, 0, icu4r_cal_free, cal);
565
+ return ret;
566
+ }
567
+
568
+ void initialize_calendar(void) {
569
+
570
+ rb_cUCalendar = rb_define_class("UCalendar", rb_cObject);
571
+ rb_define_alloc_func(rb_cUCalendar, icu4r_cal_alloc);
572
+
573
+ s_calendar_fields = rb_hash_new();
574
+ /* Valid symbols to use as field reference in UCalendar#[], UCalendar#[]=, UCalendar#add are:
575
+ :era , :year , :month , :week_of_year , :week_of_month , :date , :day_of_year , :day_of_week, :day_of_week_in_month,
576
+ :am_pm , :hour , :hour_of_day , :minute , :second , :millisecond , :zone_offset , :dst_offset:
577
+ */
578
+ rb_define_const(rb_cUCalendar, "UCALENDAR_FIELDS", s_calendar_fields);
579
+ rb_hash_aset(s_calendar_fields, ID2SYM(rb_intern("era")), INT2NUM(UCAL_ERA ));
580
+ rb_hash_aset(s_calendar_fields, ID2SYM(rb_intern("year")), INT2NUM(UCAL_YEAR ));
581
+ rb_hash_aset(s_calendar_fields, ID2SYM(rb_intern("month")), INT2NUM(UCAL_MONTH));
582
+ rb_hash_aset(s_calendar_fields, ID2SYM(rb_intern("week_of_year")), INT2NUM(UCAL_WEEK_OF_YEAR ));
583
+ rb_hash_aset(s_calendar_fields, ID2SYM(rb_intern("week_of_month")), INT2NUM(UCAL_WEEK_OF_MONTH));
584
+ rb_hash_aset(s_calendar_fields, ID2SYM(rb_intern("date")), INT2NUM(UCAL_DATE));
585
+ rb_hash_aset(s_calendar_fields, ID2SYM(rb_intern("day_of_year")), INT2NUM(UCAL_DAY_OF_YEAR));
586
+ rb_hash_aset(s_calendar_fields, ID2SYM(rb_intern("day_of_week")), INT2NUM(UCAL_DAY_OF_WEEK));
587
+ rb_hash_aset(s_calendar_fields, ID2SYM(rb_intern("day_of_week_in_month")), INT2NUM(UCAL_DAY_OF_WEEK_IN_MONTH));
588
+ rb_hash_aset(s_calendar_fields, ID2SYM(rb_intern("am_pm")), INT2NUM(UCAL_AM_PM));
589
+ rb_hash_aset(s_calendar_fields, ID2SYM(rb_intern("hour")), INT2NUM(UCAL_HOUR));
590
+ rb_hash_aset(s_calendar_fields, ID2SYM(rb_intern("hour_of_day")), INT2NUM(UCAL_HOUR_OF_DAY));
591
+ rb_hash_aset(s_calendar_fields, ID2SYM(rb_intern("minute")), INT2NUM(UCAL_MINUTE ));
592
+ rb_hash_aset(s_calendar_fields, ID2SYM(rb_intern("second")), INT2NUM(UCAL_SECOND));
593
+ rb_hash_aset(s_calendar_fields, ID2SYM(rb_intern("millisecond")), INT2NUM(UCAL_MILLISECOND ));
594
+ rb_hash_aset(s_calendar_fields, ID2SYM(rb_intern("zone_offset")), INT2NUM(UCAL_ZONE_OFFSET));
595
+ rb_hash_aset(s_calendar_fields, ID2SYM(rb_intern("dst_offset")), INT2NUM(UCAL_DST_OFFSET));
596
+
597
+ s_calendar_formats = rb_hash_new();
598
+ rb_define_const(rb_cUCalendar, "UCALENDAR_FORMATS", s_calendar_formats);
599
+ rb_hash_aset(s_calendar_formats, ID2SYM(rb_intern("full")), INT2NUM(UDAT_FULL));
600
+ rb_hash_aset(s_calendar_formats, ID2SYM(rb_intern("long")), INT2NUM(UDAT_LONG));
601
+ rb_hash_aset(s_calendar_formats, ID2SYM(rb_intern("medium")), INT2NUM(UDAT_MEDIUM));
602
+ rb_hash_aset(s_calendar_formats, ID2SYM(rb_intern("short")), INT2NUM(UDAT_SHORT));
603
+ rb_hash_aset(s_calendar_formats, ID2SYM(rb_intern("default")), INT2NUM(UDAT_DEFAULT));
604
+ rb_hash_aset(s_calendar_formats, ID2SYM(rb_intern("none")), INT2NUM(UDAT_NONE));
605
+
606
+
607
+ rb_define_singleton_method(rb_cUCalendar, "now", icu4r_cal_now, 0);
608
+
609
+ rb_define_singleton_method(rb_cUCalendar, "default_tz=", icu4r_cal_set_default_tz, 1);
610
+ rb_define_singleton_method(rb_cUCalendar, "default_tz", icu4r_cal_get_default_tz, 0);
611
+ rb_define_singleton_method(rb_cUCalendar, "time_zones", icu4r_cal_all_tz, 0);
612
+ rb_define_singleton_method(rb_cUCalendar, "tz_for_country", icu4r_cal_country_tz, 1);
613
+ rb_define_singleton_method(rb_cUCalendar, "dst_savings", icu4r_cal_dst_savings, 1);
614
+ rb_define_singleton_method(rb_cUCalendar, "parse", icu4r_cal_parse, 3);
615
+
616
+ rb_define_method(rb_cUCalendar, "initialize", icu4r_cal_init, -1);
617
+ rb_define_method(rb_cUCalendar, "add", icu4r_cal_add, 2);
618
+ rb_define_method(rb_cUCalendar, "roll", icu4r_cal_roll, 2);
619
+ rb_define_method(rb_cUCalendar, "[]", icu4r_cal_aref, 1);
620
+ rb_define_method(rb_cUCalendar, "[]=", icu4r_cal_aset, 2);
621
+ rb_define_method(rb_cUCalendar, "millis=", icu4r_cal_set_millis, 1);
622
+ rb_define_method(rb_cUCalendar, "millis", icu4r_cal_millis,0);
623
+ rb_define_method(rb_cUCalendar, "set_date", icu4r_cal_set_date,3);
624
+ rb_define_method(rb_cUCalendar, "set_date_time", icu4r_cal_set_date_time,6);
625
+ rb_define_method(rb_cUCalendar, "time_zone=", icu4r_cal_set_tz,1);
626
+ rb_define_method(rb_cUCalendar, "time_zone", icu4r_cal_get_tz,-1);
627
+ rb_define_method(rb_cUCalendar, "in_daylight_time?", icu4r_cal_in_daylight,0);
628
+ rb_define_method(rb_cUCalendar, "format", icu4r_cal_format,-1);
629
+
630
+ rb_define_method(rb_cUCalendar, "clone", icu4r_cal_clone,0);
631
+ rb_define_method(rb_cUCalendar, "eql?", icu4r_cal_equal,1);
632
+ rb_define_method(rb_cUCalendar, "<=>", icu4r_cal_cmp,1);
633
+
634
+ rb_include_module(rb_cUCalendar, rb_mComparable);
635
+
636
+ }