icu-calendar 1.0.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.
- checksums.yaml +7 -0
- data/LICENSE +13 -0
- data/README.md +51 -0
- data/lib/icu/calendar.rb +401 -0
- data/lib/icu/calendar/library.rb +198 -0
- data/lib/icu/calendar/library/constants.rb +71 -0
- data/lib/icu/calendar/library/error_code.rb +33 -0
- data/lib/icu/calendar/library/version_info.rb +26 -0
- data/lib/icu/calendar/version.rb +5 -0
- metadata +80 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 5b86febf5c2e4f2d55a1b67b9e308b20b75e728f
|
4
|
+
data.tar.gz: ceca6826de5dfbe5a4485e6cd7c31872904e5f6a
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 17221530b16d9f8da24c767b7d9a4b4d140c2edbcb4d9f2ffbb85b62f15e42dba1c26d668c84009e71a8f64dac4a5ea14f9f849bc790003a186d232212da8ca5
|
7
|
+
data.tar.gz: 29c51cbe355bb924f707c64d584896d399e3f6ed061c55ebfc4231f35a6e5ef56bae8fa15ebe82365e993f1961e924ca96c069a1c001fbb3e21d2dfd30aa3aef
|
data/LICENSE
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
Copyright 2014 Christopher Bandy
|
2
|
+
|
3
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
you may not use this file except in compliance with the License.
|
5
|
+
You may obtain a copy of the License at
|
6
|
+
|
7
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
|
9
|
+
Unless required by applicable law or agreed to in writing, software
|
10
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
See the License for the specific language governing permissions and
|
13
|
+
limitations under the License.
|
data/README.md
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
# ICU::Calendar
|
2
|
+
|
3
|
+
[Ruby-FFI] bindings for the Calendar functionality of [ICU].
|
4
|
+
|
5
|
+
[](https://travis-ci.org/cbandy/icu-calendar)
|
6
|
+
|
7
|
+
|
8
|
+
## Requirements
|
9
|
+
|
10
|
+
* [ICU4C] >= 4.2
|
11
|
+
* [Ruby-FFI]
|
12
|
+
* Ruby >= 1.9.3
|
13
|
+
|
14
|
+
|
15
|
+
## Installation
|
16
|
+
|
17
|
+
```sh
|
18
|
+
gem install icu-calendar
|
19
|
+
```
|
20
|
+
|
21
|
+
### Ubuntu
|
22
|
+
|
23
|
+
```sh
|
24
|
+
sudo apt-get install ^libicu..$
|
25
|
+
```
|
26
|
+
|
27
|
+
## Usage
|
28
|
+
|
29
|
+
```ruby
|
30
|
+
require 'icu/calendar'
|
31
|
+
|
32
|
+
# Calendar for the default locale at the current time in the current timezone
|
33
|
+
ICU::Calendar.new
|
34
|
+
|
35
|
+
ICU::Calendar.new(locale: 'de_DE')
|
36
|
+
ICU::Calendar.new(time: Time.now - 300)
|
37
|
+
ICU::Calendar.new(timezone: 'America/New_York')
|
38
|
+
|
39
|
+
# Chinese calendar for the default locale
|
40
|
+
ICU::Calendar.new(locale: '@calendar=chinese')
|
41
|
+
|
42
|
+
calendar = ICU::Calendar.new
|
43
|
+
calendar[:year] # 2014
|
44
|
+
calendar.add(:month, 12)
|
45
|
+
calendar[:year] # 2015
|
46
|
+
```
|
47
|
+
|
48
|
+
|
49
|
+
[ICU]: http://icu-project.org "International Components for Unicode"
|
50
|
+
[ICU4C]: http://icu-project.org/download
|
51
|
+
[Ruby-FFI]: https://github.com/ffi/ffi
|
data/lib/icu/calendar.rb
ADDED
@@ -0,0 +1,401 @@
|
|
1
|
+
require 'icu/calendar/library'
|
2
|
+
|
3
|
+
module ICU
|
4
|
+
class Calendar
|
5
|
+
RuntimeError = Class.new(::RuntimeError)
|
6
|
+
|
7
|
+
include Comparable
|
8
|
+
|
9
|
+
class << self
|
10
|
+
def available_locales
|
11
|
+
(0...Library.ucal_countAvailable).map(&Library.method(:ucal_getAvailable))
|
12
|
+
end
|
13
|
+
|
14
|
+
def canonical_timezone_identifier(timezone)
|
15
|
+
FFI::MemoryPointer.new(:bool) do |is_system_id|
|
16
|
+
return Library.wchar_buffer_from_string(timezone) do |w_timezone|
|
17
|
+
Library.read_into_wchar_buffer(32) do |buffer, status|
|
18
|
+
Library.ucal_getCanonicalTimeZoneID(
|
19
|
+
w_timezone, -1,
|
20
|
+
buffer, buffer.size / buffer.type_size,
|
21
|
+
is_system_id, status
|
22
|
+
)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def country_timezones(country)
|
29
|
+
Library.read_wchar_enumeration(->(status) do
|
30
|
+
Library.ucal_openCountryTimeZones(country, status)
|
31
|
+
end).to_a
|
32
|
+
end
|
33
|
+
|
34
|
+
def default_timezone
|
35
|
+
Library.read_into_wchar_buffer(32) do |buffer, status|
|
36
|
+
Library.ucal_getDefaultTimeZone(buffer, buffer.size / buffer.type_size, status)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def default_timezone=(timezone)
|
41
|
+
Library.wchar_buffer_from_string(timezone) do |w_timezone|
|
42
|
+
Library.assert_success do |status|
|
43
|
+
Library.ucal_setDefaultTimeZone(w_timezone, status)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def dst_savings(timezone)
|
49
|
+
Library.wchar_buffer_from_string(timezone) do |w_timezone|
|
50
|
+
Library.assert_success do |status|
|
51
|
+
Library.ucal_getDSTSavings(w_timezone, status)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def timezone_data_version
|
57
|
+
Library.assert_success do |status|
|
58
|
+
Library.ucal_getTZDataVersion(status)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def timezone_identifiers(type, region = nil, offset = nil)
|
63
|
+
offset = FFI::MemoryPointer.new(:int32).write_int32(offset) unless offset.nil?
|
64
|
+
|
65
|
+
Library.read_wchar_enumeration(->(status) do
|
66
|
+
Library.ucal_openTimeZoneIDEnumeration(type, region, offset, status)
|
67
|
+
end).to_a
|
68
|
+
ensure
|
69
|
+
offset.free unless offset.nil?
|
70
|
+
end
|
71
|
+
|
72
|
+
def timezones
|
73
|
+
Library.read_wchar_enumeration(->(status) do
|
74
|
+
Library.ucal_openTimeZones(status)
|
75
|
+
end).to_a
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def [](field)
|
80
|
+
field_value_to_symbol(field, Library.assert_success do |status|
|
81
|
+
Library.ucal_get(@calendar, field, status)
|
82
|
+
end)
|
83
|
+
end
|
84
|
+
|
85
|
+
def []=(field, value)
|
86
|
+
if value.nil?
|
87
|
+
Library.ucal_clearField(@calendar, field)
|
88
|
+
else
|
89
|
+
Library.ucal_set(@calendar, field, value)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def <=>(other)
|
94
|
+
time <=> coerce_to_milliseconds(other)
|
95
|
+
end
|
96
|
+
|
97
|
+
def actual_maximum(field)
|
98
|
+
field_value_to_symbol(field, Library.assert_success do |status|
|
99
|
+
Library.ucal_getLimit(@calendar, field, :actual_maximum, status)
|
100
|
+
end)
|
101
|
+
end
|
102
|
+
|
103
|
+
def actual_minimum(field)
|
104
|
+
field_value_to_symbol(field, Library.assert_success do |status|
|
105
|
+
Library.ucal_getLimit(@calendar, field, :actual_minimum, status)
|
106
|
+
end)
|
107
|
+
end
|
108
|
+
|
109
|
+
def add(field, amount)
|
110
|
+
Library.assert_success do |status|
|
111
|
+
Library.ucal_add(@calendar, field, amount, status)
|
112
|
+
end
|
113
|
+
|
114
|
+
self
|
115
|
+
end
|
116
|
+
|
117
|
+
def clear
|
118
|
+
Library.ucal_clear(@calendar)
|
119
|
+
end
|
120
|
+
|
121
|
+
def daylight_time?
|
122
|
+
Library.assert_success do |status|
|
123
|
+
Library.ucal_inDaylightTime(@calendar, status)
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
def difference(from, field)
|
128
|
+
from = coerce_to_milliseconds(from)
|
129
|
+
Library.assert_success do |status|
|
130
|
+
Library.ucal_getFieldDifference(@calendar, from, field, status)
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
def eql?(other)
|
135
|
+
equivalent?(other) && time == other.time
|
136
|
+
end
|
137
|
+
|
138
|
+
def equivalent?(other)
|
139
|
+
Calendar === other && Library.ucal_equivalentTo(@calendar, other.calendar)
|
140
|
+
end
|
141
|
+
|
142
|
+
def first_day_of_week
|
143
|
+
Library.enum_type(:day_of_week)[Library.ucal_getAttribute(@calendar, :first_day_of_week)]
|
144
|
+
end
|
145
|
+
|
146
|
+
def first_day_of_week=(day_of_week)
|
147
|
+
day_of_week = Library.enum_type(:day_of_week)[day_of_week] if Symbol === day_of_week
|
148
|
+
Library.ucal_setAttribute(@calendar, :first_day_of_week, day_of_week)
|
149
|
+
end
|
150
|
+
|
151
|
+
def greatest_minimum(field)
|
152
|
+
field_value_to_symbol(field, Library.assert_success do |status|
|
153
|
+
Library.ucal_getLimit(@calendar, field, :greatest_minimum, status)
|
154
|
+
end)
|
155
|
+
end
|
156
|
+
|
157
|
+
def gregorian_change
|
158
|
+
Library.assert_success do |status|
|
159
|
+
Library.ucal_getGregorianChange(@calendar, status)
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
def gregorian_change=(time)
|
164
|
+
time = coerce_to_milliseconds(time)
|
165
|
+
|
166
|
+
Library.assert_success do |status|
|
167
|
+
Library.ucal_setGregorianChange(@calendar, time, status)
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
def initialize(options = {})
|
172
|
+
calendar = wchar_buffer_from_string_or_nil(options[:timezone]) do |timezone|
|
173
|
+
Library.assert_success do |status|
|
174
|
+
Library.ucal_open(timezone, -1, options[:locale], :default, status)
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
@calendar = automatically_close(calendar)
|
179
|
+
self.time = options[:time] if options[:time]
|
180
|
+
end
|
181
|
+
|
182
|
+
def is_set?(field)
|
183
|
+
Library.ucal_isSet(@calendar, field)
|
184
|
+
end
|
185
|
+
|
186
|
+
def least_maximum(field)
|
187
|
+
field_value_to_symbol(field, Library.assert_success do |status|
|
188
|
+
Library.ucal_getLimit(@calendar, field, :least_maximum, status)
|
189
|
+
end)
|
190
|
+
end
|
191
|
+
|
192
|
+
def lenient?
|
193
|
+
Library.ucal_getAttribute(@calendar, :lenient).nonzero?
|
194
|
+
end
|
195
|
+
|
196
|
+
def lenient=(value)
|
197
|
+
Library.ucal_setAttribute(@calendar, :lenient, value ? 1 : 0)
|
198
|
+
end
|
199
|
+
|
200
|
+
def locale(type = :valid)
|
201
|
+
Library.assert_success do |status|
|
202
|
+
Library.ucal_getLocaleByType(@calendar, type, status)
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
206
|
+
def maximum(field)
|
207
|
+
field_value_to_symbol(field, Library.assert_success do |status|
|
208
|
+
Library.ucal_getLimit(@calendar, field, :maximum, status)
|
209
|
+
end)
|
210
|
+
end
|
211
|
+
|
212
|
+
def minimal_days_in_first_week
|
213
|
+
Library.ucal_getAttribute(@calendar, :minimal_days_in_first_week)
|
214
|
+
end
|
215
|
+
|
216
|
+
def minimal_days_in_first_week=(value)
|
217
|
+
Library.ucal_setAttribute(@calendar, :minimal_days_in_first_week, value)
|
218
|
+
end
|
219
|
+
|
220
|
+
def minimum(field)
|
221
|
+
field_value_to_symbol(field, Library.assert_success do |status|
|
222
|
+
Library.ucal_getLimit(@calendar, field, :minimum, status)
|
223
|
+
end)
|
224
|
+
end
|
225
|
+
|
226
|
+
def next_timezone_transition(inclusive = false)
|
227
|
+
timezone_transition(inclusive ? :next_inclusive : :next)
|
228
|
+
end
|
229
|
+
|
230
|
+
def previous_timezone_transition(inclusive = false)
|
231
|
+
timezone_transition(inclusive ? :previous_inclusive : :previous)
|
232
|
+
end
|
233
|
+
|
234
|
+
def repeated_wall_time
|
235
|
+
Library.enum_type(:walltime_option)[Library.ucal_getAttribute(@calendar, :repeated_wall_time)]
|
236
|
+
end
|
237
|
+
|
238
|
+
def repeated_wall_time=(option)
|
239
|
+
option = Library.enum_type(:walltime_option)[option] if Symbol === option
|
240
|
+
Library.ucal_setAttribute(@calendar, :repeated_wall_time, option)
|
241
|
+
end
|
242
|
+
|
243
|
+
def roll(field, amount)
|
244
|
+
Library.assert_success do |status|
|
245
|
+
Library.ucal_roll(@calendar, field, amount, status)
|
246
|
+
end
|
247
|
+
|
248
|
+
self
|
249
|
+
end
|
250
|
+
|
251
|
+
def set_date(year, month, day)
|
252
|
+
Library.assert_success do |status|
|
253
|
+
Library.ucal_setDate(@calendar, year, month, day, status)
|
254
|
+
end
|
255
|
+
end
|
256
|
+
|
257
|
+
def set_date_and_time(year, month, day, hour, minute, second)
|
258
|
+
Library.assert_success do |status|
|
259
|
+
Library.ucal_setDateTime(@calendar, year, month, day, hour, minute, second, status)
|
260
|
+
end
|
261
|
+
end
|
262
|
+
|
263
|
+
def skipped_wall_time
|
264
|
+
Library.enum_type(:walltime_option)[Library.ucal_getAttribute(@calendar, :skipped_wall_time)]
|
265
|
+
end
|
266
|
+
|
267
|
+
def skipped_wall_time=(option)
|
268
|
+
option = Library.enum_type(:walltime_option)[option] if Symbol === option
|
269
|
+
Library.ucal_setAttribute(@calendar, :skipped_wall_time, option)
|
270
|
+
end
|
271
|
+
|
272
|
+
def time
|
273
|
+
Library.assert_success do |status|
|
274
|
+
Library.ucal_getMillis(@calendar, status)
|
275
|
+
end
|
276
|
+
end
|
277
|
+
|
278
|
+
def time=(time)
|
279
|
+
time = coerce_to_milliseconds(time)
|
280
|
+
|
281
|
+
Library.assert_success do |status|
|
282
|
+
Library.ucal_setMillis(@calendar, time, status)
|
283
|
+
end
|
284
|
+
end
|
285
|
+
|
286
|
+
def timezone
|
287
|
+
Library.read_into_wchar_buffer(32) do |buffer, status|
|
288
|
+
Library.ucal_getTimeZoneID(@calendar, buffer, buffer.size / buffer.type_size, status)
|
289
|
+
end
|
290
|
+
end
|
291
|
+
|
292
|
+
def timezone=(timezone)
|
293
|
+
wchar_buffer_from_string_or_nil(timezone) do |w_timezone|
|
294
|
+
Library.assert_success do |status|
|
295
|
+
Library.ucal_setTimeZone(@calendar, w_timezone, -1, status)
|
296
|
+
end
|
297
|
+
end
|
298
|
+
end
|
299
|
+
|
300
|
+
def timezone_display_name(type = :standard, locale = nil)
|
301
|
+
Library.read_into_wchar_buffer(32) do |buffer, status|
|
302
|
+
Library.ucal_getTimeZoneDisplayName(@calendar, type, locale, buffer, buffer.size / buffer.type_size, status)
|
303
|
+
end
|
304
|
+
end
|
305
|
+
|
306
|
+
def to_time
|
307
|
+
Time.new(
|
308
|
+
self[:year],
|
309
|
+
self[Library.enum_type(:date_field)[:month]] + 1,
|
310
|
+
self[:day_of_month],
|
311
|
+
self[:hour_of_day],
|
312
|
+
self[:minute],
|
313
|
+
self[:second] + Rational(self[:millisecond], 1000),
|
314
|
+
(self[:zone_offset] + self[:dst_offset]) / 1000
|
315
|
+
)
|
316
|
+
end
|
317
|
+
|
318
|
+
def type
|
319
|
+
Library.assert_success do |status|
|
320
|
+
Library.ucal_getType(@calendar, status)
|
321
|
+
end.to_sym
|
322
|
+
end
|
323
|
+
|
324
|
+
def weekday_type(day_of_week)
|
325
|
+
Library.assert_success do |status|
|
326
|
+
Library.ucal_getDayOfWeekType(@calendar, day_of_week, status)
|
327
|
+
end
|
328
|
+
end
|
329
|
+
|
330
|
+
def weekend?
|
331
|
+
Library.assert_success do |status|
|
332
|
+
Library.ucal_isWeekend(@calendar, time, status)
|
333
|
+
end
|
334
|
+
end
|
335
|
+
|
336
|
+
def weekend_transition(day_of_week)
|
337
|
+
Library.assert_success do |status|
|
338
|
+
Library.ucal_getWeekendTransition(@calendar, day_of_week, status)
|
339
|
+
end
|
340
|
+
end
|
341
|
+
|
342
|
+
protected
|
343
|
+
|
344
|
+
attr_reader :calendar
|
345
|
+
|
346
|
+
private
|
347
|
+
|
348
|
+
def automatically_close(calendar_pointer)
|
349
|
+
FFI::AutoPointer.new(calendar_pointer, Library.method(:ucal_close))
|
350
|
+
end
|
351
|
+
|
352
|
+
def coerce_to_milliseconds(value)
|
353
|
+
if Calendar === value
|
354
|
+
value.time
|
355
|
+
else
|
356
|
+
value = value.to_time if value.respond_to? :to_time
|
357
|
+
value = value.getutc.to_f * 1000 if value.is_a? Time
|
358
|
+
value
|
359
|
+
end
|
360
|
+
end
|
361
|
+
|
362
|
+
def field_value_to_symbol(field, value)
|
363
|
+
case field
|
364
|
+
when :am_pm, :day_of_week, :month
|
365
|
+
Library.enum_type(field)[value]
|
366
|
+
else
|
367
|
+
value
|
368
|
+
end
|
369
|
+
end
|
370
|
+
|
371
|
+
def initialize_copy(other)
|
372
|
+
super
|
373
|
+
|
374
|
+
@calendar = automatically_close(
|
375
|
+
Library.assert_success do |status|
|
376
|
+
Library.ucal_clone(@calendar, status)
|
377
|
+
end
|
378
|
+
)
|
379
|
+
end
|
380
|
+
|
381
|
+
def timezone_transition(type)
|
382
|
+
FFI::MemoryPointer.new(:double) do |time|
|
383
|
+
valid = Library.assert_success do |status|
|
384
|
+
Library.ucal_getTimeZoneTransitionDate(@calendar, type, time, status)
|
385
|
+
end
|
386
|
+
|
387
|
+
return valid ? time.read_double : nil
|
388
|
+
end
|
389
|
+
end
|
390
|
+
|
391
|
+
def wchar_buffer_from_string_or_nil(string)
|
392
|
+
if string.nil?
|
393
|
+
yield string
|
394
|
+
else
|
395
|
+
Library.wchar_buffer_from_string(string) do |buffer|
|
396
|
+
yield buffer
|
397
|
+
end
|
398
|
+
end
|
399
|
+
end
|
400
|
+
end
|
401
|
+
end
|
@@ -0,0 +1,198 @@
|
|
1
|
+
require 'ffi'
|
2
|
+
|
3
|
+
module ICU
|
4
|
+
class Calendar
|
5
|
+
module Library
|
6
|
+
extend FFI::Library
|
7
|
+
|
8
|
+
%w( icutu ).tap do |libraries|
|
9
|
+
begin
|
10
|
+
ffi_lib(*libraries)
|
11
|
+
rescue LoadError
|
12
|
+
ffi_lib(*libraries.map do |lib|
|
13
|
+
if 'dll' == FFI::Platform::LIBSUFFIX
|
14
|
+
[42, 44, 46, *(48..100)].map { |i| "#{lib}#{i}.#{FFI::Platform::LIBSUFFIX}" }
|
15
|
+
else
|
16
|
+
[42, 44, 46, *(48..100)].map { |i| "#{lib}.#{FFI::Platform::LIBSUFFIX}.#{i}" }
|
17
|
+
end
|
18
|
+
end)
|
19
|
+
end.each do |library|
|
20
|
+
@suffix ||= ['', '_4_2', '_44', '_46', *(48..100).map { |i| "_#{i}" }].find do |suffix|
|
21
|
+
function_names("u_errorName#{suffix}", nil).any? { |name| library.find_function(name) }
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
require_relative 'library/constants'
|
27
|
+
require_relative 'library/error_code'
|
28
|
+
require_relative 'library/version_info'
|
29
|
+
|
30
|
+
U_BUFFER_OVERFLOW_ERROR = 15
|
31
|
+
U_MAX_VERSION_LENGTH = 4
|
32
|
+
U_MAX_VERSION_STRING_LENGTH = 20
|
33
|
+
U_ZERO_ERROR = 0
|
34
|
+
|
35
|
+
class << self
|
36
|
+
def assert_success
|
37
|
+
ErrorCode.new do |status|
|
38
|
+
result = yield status
|
39
|
+
raise RuntimeError, status.to_s unless status.success?
|
40
|
+
return result
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def read_into_wchar_buffer(length)
|
45
|
+
ErrorCode.new do |status|
|
46
|
+
for _ in 1..2
|
47
|
+
FFI::Buffer.new(:uint16, length, false) do |buffer|
|
48
|
+
length = yield buffer, status
|
49
|
+
return buffer.read_array_of_uint16(length).pack('U*') if status.success?
|
50
|
+
raise RuntimeError, status.to_s unless status.buffer_overflow?
|
51
|
+
status.clear
|
52
|
+
end
|
53
|
+
end
|
54
|
+
raise RuntimeError, "#{status}: Needed #{length}"
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def read_wchar_enumeration(open)
|
59
|
+
return enum_for(:read_wchar_enumeration, open) unless block_given?
|
60
|
+
|
61
|
+
Library::ErrorCode.new do |status|
|
62
|
+
enumeration = open.call(status)
|
63
|
+
raise RuntimeError, status.to_s unless status.success?
|
64
|
+
|
65
|
+
begin
|
66
|
+
FFI::MemoryPointer.new(:int32) do |length|
|
67
|
+
loop do
|
68
|
+
pointer = Library.uenum_unext(enumeration, length, status)
|
69
|
+
raise RuntimeError, status.to_s unless status.success?
|
70
|
+
break if pointer.null?
|
71
|
+
yield pointer.read_array_of_uint16(length.read_int32).pack('U*')
|
72
|
+
end
|
73
|
+
end
|
74
|
+
ensure
|
75
|
+
Library.uenum_close(enumeration)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
def version
|
81
|
+
@version ||= VersionInfo.new.tap { |version| u_getVersion(version) }
|
82
|
+
end
|
83
|
+
|
84
|
+
def wchar_buffer_from_string(string, &block)
|
85
|
+
codepoints = string.encode('UTF-8').unpack('U*') << 0
|
86
|
+
FFI::Buffer.new(:uint16, codepoints.length, false) do |buffer|
|
87
|
+
buffer.write_array_of_uint16(codepoints)
|
88
|
+
return yield buffer
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
private
|
93
|
+
|
94
|
+
def attach_icu_function(name, type, *args)
|
95
|
+
attach_function name, "#{name}#{@suffix}", *args, type
|
96
|
+
end
|
97
|
+
|
98
|
+
def icu_version_at_least(version)
|
99
|
+
Gem::Version.new(version) <= Gem::Version.new(self.version)
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
enum :am_pm, am_pm_enum
|
104
|
+
enum :attribute, attribute_enum
|
105
|
+
enum :calendar_type, calendar_type_enum
|
106
|
+
enum :date_field, date_field_enum
|
107
|
+
enum :day_of_week, day_of_week_enum
|
108
|
+
enum :display_name_type, display_name_type_enum
|
109
|
+
enum :limit_type, limit_type_enum
|
110
|
+
enum :locale_type, locale_type_enum
|
111
|
+
enum :month, month_enum
|
112
|
+
enum :system_timezone_type, system_timezone_type_enum
|
113
|
+
enum :timezone_transition_type, timezone_transition_type_enum
|
114
|
+
enum :walltime_option, walltime_option_enum
|
115
|
+
enum :weekday_type, weekday_type_enum
|
116
|
+
|
117
|
+
typedef :pointer, :calendar
|
118
|
+
typedef :double, :date
|
119
|
+
typedef :pointer, :enumeration
|
120
|
+
typedef ErrorCode, :status
|
121
|
+
typedef VersionInfo, :version
|
122
|
+
|
123
|
+
attach_icu_function :u_errorName, :string, [:int]
|
124
|
+
|
125
|
+
attach_icu_function :u_getVersion, :void, [:version]
|
126
|
+
attach_icu_function :u_versionToString, :void, [:version, :buffer_out]
|
127
|
+
|
128
|
+
# Enumeration
|
129
|
+
attach_icu_function :uenum_close, :void, [:enumeration]
|
130
|
+
attach_icu_function :uenum_next, :string, [:enumeration, :buffer_out, :status]
|
131
|
+
attach_icu_function :uenum_unext, :pointer, [:enumeration, :buffer_out, :status]
|
132
|
+
|
133
|
+
# Locales
|
134
|
+
attach_icu_function :ucal_countAvailable, :int32, []
|
135
|
+
attach_icu_function :ucal_getAvailable, :string, [:int32]
|
136
|
+
attach_icu_function :uloc_getDefault, :string, []
|
137
|
+
|
138
|
+
# Time Zones
|
139
|
+
attach_icu_function :ucal_getCanonicalTimeZoneID, :int32, [:buffer_in, :int32, :buffer_out, :int32, :buffer_out, :status]
|
140
|
+
attach_icu_function :ucal_getDefaultTimeZone, :int32, [:buffer_out, :int32, :status]
|
141
|
+
attach_icu_function :ucal_getDSTSavings, :int32, [:buffer_in, :status]
|
142
|
+
attach_icu_function :ucal_getTZDataVersion, :string, [:status]
|
143
|
+
attach_icu_function :ucal_setDefaultTimeZone, :void, [:buffer_in, :status]
|
144
|
+
|
145
|
+
attach_icu_function :ucal_openTimeZones, :enumeration, [:status]
|
146
|
+
attach_icu_function :ucal_openCountryTimeZones, :enumeration, [:string, :status]
|
147
|
+
|
148
|
+
# Calendar
|
149
|
+
attach_icu_function :ucal_clone, :calendar, [:calendar, :status]
|
150
|
+
attach_icu_function :ucal_close, :void, [:calendar]
|
151
|
+
attach_icu_function :ucal_equivalentTo, :bool, [:calendar, :calendar]
|
152
|
+
attach_icu_function :ucal_open, :calendar, [:buffer_in, :int32, :string, :calendar_type, :status]
|
153
|
+
|
154
|
+
attach_icu_function :ucal_getAttribute, :int32, [:calendar, :attribute]
|
155
|
+
attach_icu_function :ucal_getGregorianChange, :date, [:calendar, :status]
|
156
|
+
attach_icu_function :ucal_getLocaleByType, :string, [:calendar, :locale_type, :status]
|
157
|
+
attach_icu_function :ucal_getMillis, :date, [:calendar, :status]
|
158
|
+
attach_icu_function :ucal_getTimeZoneDisplayName, :int32, [:calendar, :display_name_type, :string, :buffer_out, :int32, :status]
|
159
|
+
attach_icu_function :ucal_getType, :string, [:calendar, :status]
|
160
|
+
attach_icu_function :ucal_inDaylightTime, :bool, [:calendar, :status]
|
161
|
+
attach_icu_function :ucal_setAttribute, :void, [:calendar, :attribute, :int32]
|
162
|
+
attach_icu_function :ucal_setDate, :void, [:calendar, :int32, :month, :int32, :status]
|
163
|
+
attach_icu_function :ucal_setDateTime, :void, [:calendar, :int32, :month, :int32, :int32, :int32, :int32, :status]
|
164
|
+
attach_icu_function :ucal_setGregorianChange, :void, [:calendar, :date, :status]
|
165
|
+
attach_icu_function :ucal_setMillis, :void, [:calendar, :date, :status]
|
166
|
+
attach_icu_function :ucal_setTimeZone, :void, [:calendar, :buffer_in, :int32, :status]
|
167
|
+
|
168
|
+
# Calendar Fields
|
169
|
+
attach_icu_function :ucal_add, :void, [:calendar, :date_field, :int32, :status]
|
170
|
+
attach_icu_function :ucal_clear, :void, [:calendar]
|
171
|
+
attach_icu_function :ucal_clearField, :void, [:calendar, :date_field]
|
172
|
+
attach_icu_function :ucal_get, :int32, [:calendar, :date_field, :status]
|
173
|
+
attach_icu_function :ucal_getLimit, :int32, [:calendar, :date_field, :limit_type, :status]
|
174
|
+
attach_icu_function :ucal_isSet, :bool, [:calendar, :date_field]
|
175
|
+
attach_icu_function :ucal_roll, :void, [:calendar, :date_field, :int32, :status]
|
176
|
+
attach_icu_function :ucal_set, :void, [:calendar, :date_field, :int32]
|
177
|
+
|
178
|
+
if icu_version_at_least('4.4')
|
179
|
+
attach_icu_function :ucal_getDayOfWeekType, :weekday_type, [:calendar, :day_of_week, :status]
|
180
|
+
attach_icu_function :ucal_getWeekendTransition, :int32, [:calendar, :day_of_week, :status]
|
181
|
+
attach_icu_function :ucal_isWeekend, :bool, [:calendar, :date, :status]
|
182
|
+
end
|
183
|
+
|
184
|
+
if icu_version_at_least('4.8')
|
185
|
+
attach_icu_function :ucal_getFieldDifference, :int32, [:calendar, :date, :date_field, :status]
|
186
|
+
attach_icu_function :ucal_openTimeZoneIDEnumeration, :enumeration, [:system_timezone_type, :string, :buffer_in, :status]
|
187
|
+
end
|
188
|
+
|
189
|
+
if icu_version_at_least('50')
|
190
|
+
attach_icu_function :ucal_getTimeZoneTransitionDate, :bool, [:calendar, :timezone_transition_type, :buffer_out, :status]
|
191
|
+
end
|
192
|
+
|
193
|
+
if icu_version_at_least('51')
|
194
|
+
attach_icu_function :ucal_getTimeZoneID, :int32, [:calendar, :buffer_out, :int32, :status]
|
195
|
+
end
|
196
|
+
end
|
197
|
+
end
|
198
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
class ICU::Calendar
|
2
|
+
module Library
|
3
|
+
|
4
|
+
class << self
|
5
|
+
private
|
6
|
+
|
7
|
+
def am_pm_enum
|
8
|
+
[:am, :pm]
|
9
|
+
end
|
10
|
+
|
11
|
+
def attribute_enum
|
12
|
+
[
|
13
|
+
:lenient, :first_day_of_week, :minimal_days_in_first_week,
|
14
|
+
# ICU >= 49
|
15
|
+
:repeated_wall_time, :skipped_wall_time,
|
16
|
+
]
|
17
|
+
end
|
18
|
+
|
19
|
+
def calendar_type_enum
|
20
|
+
[:default, :gregorian]
|
21
|
+
end
|
22
|
+
|
23
|
+
def date_field_enum
|
24
|
+
[
|
25
|
+
:era, :year, :month, :week_of_year, :week_of_month,
|
26
|
+
:date, :day_of_year, :day_of_month, 5, :day_of_week, 7, :day_of_week_in_month,
|
27
|
+
:am_pm, :hour, :hour_of_day, :minute, :second, :millisecond, :zone_offset, :dst_offset,
|
28
|
+
:year_woy, :dow_local, :extended_year, :julian_day, :milliseconds_in_day, :is_leap_month,
|
29
|
+
:field_count
|
30
|
+
]
|
31
|
+
end
|
32
|
+
|
33
|
+
def day_of_week_enum
|
34
|
+
[:sunday, 1, :monday, :tuesday, :wednesday, :thursday, :friday, :saturday]
|
35
|
+
end
|
36
|
+
|
37
|
+
def display_name_type_enum
|
38
|
+
[:standard, :short_standard, :dst, :short_dst]
|
39
|
+
end
|
40
|
+
|
41
|
+
def limit_type_enum
|
42
|
+
[:minimum, :maximum, :greatest_minimum, :least_maximum, :actual_minimum, :actual_maximum]
|
43
|
+
end
|
44
|
+
|
45
|
+
def locale_type_enum
|
46
|
+
[:actual, :valid]
|
47
|
+
end
|
48
|
+
|
49
|
+
def month_enum
|
50
|
+
[:january, :february, :march, :april, :may, :june, :july, :august, :september, :october, :november, :december, :undecimber]
|
51
|
+
end
|
52
|
+
|
53
|
+
def system_timezone_type_enum
|
54
|
+
[:any, :canonical, :canonical_location]
|
55
|
+
end
|
56
|
+
|
57
|
+
def timezone_transition_type_enum
|
58
|
+
[:next, :next_inclusive, :previous, :previous_inclusive]
|
59
|
+
end
|
60
|
+
|
61
|
+
def walltime_option_enum
|
62
|
+
[:last, :first, :next_valid]
|
63
|
+
end
|
64
|
+
|
65
|
+
def weekday_type_enum
|
66
|
+
[:weekday, :weekend, :weekend_onset, :weekend_cease]
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
class ICU::Calendar
|
2
|
+
module Library
|
3
|
+
class ErrorCode < FFI::MemoryPointer
|
4
|
+
extend FFI::DataConverter
|
5
|
+
|
6
|
+
def self.native_type
|
7
|
+
FFI::Type::POINTER
|
8
|
+
end
|
9
|
+
|
10
|
+
def initialize
|
11
|
+
super(:int)
|
12
|
+
end
|
13
|
+
|
14
|
+
def buffer_overflow?
|
15
|
+
to_i == U_BUFFER_OVERFLOW_ERROR
|
16
|
+
end
|
17
|
+
|
18
|
+
def failure?
|
19
|
+
to_i > U_ZERO_ERROR
|
20
|
+
end
|
21
|
+
|
22
|
+
def success?
|
23
|
+
to_i <= U_ZERO_ERROR
|
24
|
+
end
|
25
|
+
|
26
|
+
alias_method :to_i, :read_int
|
27
|
+
|
28
|
+
def to_s
|
29
|
+
Library.u_errorName(to_i)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
class ICU::Calendar
|
2
|
+
module Library
|
3
|
+
class VersionInfo < FFI::MemoryPointer
|
4
|
+
extend FFI::DataConverter
|
5
|
+
|
6
|
+
def self.native_type
|
7
|
+
FFI::Type::POINTER
|
8
|
+
end
|
9
|
+
|
10
|
+
def initialize
|
11
|
+
super(:uint8, U_MAX_VERSION_LENGTH)
|
12
|
+
end
|
13
|
+
|
14
|
+
def to_a
|
15
|
+
read_array_of_uint8(U_MAX_VERSION_LENGTH)
|
16
|
+
end
|
17
|
+
|
18
|
+
def to_s
|
19
|
+
FFI::MemoryPointer.new(:char, U_MAX_VERSION_STRING_LENGTH) do |buffer|
|
20
|
+
Library.u_versionToString(self, buffer)
|
21
|
+
return buffer.read_string_to_null
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
metadata
ADDED
@@ -0,0 +1,80 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: icu-calendar
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Chris Bandy
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-11-15 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: rspec
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - '>='
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '3.0'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - '>='
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '3.0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: ffi
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - '>='
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - '>='
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
description:
|
42
|
+
email: bandy.chris@gmail.com
|
43
|
+
executables: []
|
44
|
+
extensions: []
|
45
|
+
extra_rdoc_files: []
|
46
|
+
files:
|
47
|
+
- LICENSE
|
48
|
+
- README.md
|
49
|
+
- lib/icu/calendar.rb
|
50
|
+
- lib/icu/calendar/library.rb
|
51
|
+
- lib/icu/calendar/version.rb
|
52
|
+
- lib/icu/calendar/library/constants.rb
|
53
|
+
- lib/icu/calendar/library/version_info.rb
|
54
|
+
- lib/icu/calendar/library/error_code.rb
|
55
|
+
homepage: https://github.com/cbandy/icu-calendar
|
56
|
+
licenses:
|
57
|
+
- Apache License Version 2.0
|
58
|
+
metadata: {}
|
59
|
+
post_install_message:
|
60
|
+
rdoc_options: []
|
61
|
+
require_paths:
|
62
|
+
- lib
|
63
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
64
|
+
requirements:
|
65
|
+
- - '>='
|
66
|
+
- !ruby/object:Gem::Version
|
67
|
+
version: 1.9.3
|
68
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
69
|
+
requirements:
|
70
|
+
- - '>='
|
71
|
+
- !ruby/object:Gem::Version
|
72
|
+
version: '0'
|
73
|
+
requirements:
|
74
|
+
- ICU 4.2 or greater, http://www.icu-project.org/
|
75
|
+
rubyforge_project:
|
76
|
+
rubygems_version: 2.0.14
|
77
|
+
signing_key:
|
78
|
+
specification_version: 4
|
79
|
+
summary: Date arithmetic and calendar data from ICU
|
80
|
+
test_files: []
|