ffi-icu 0.0.9 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/lib/ffi-icu.rb CHANGED
@@ -31,9 +31,11 @@ end
31
31
 
32
32
  require "ffi-icu/core_ext/string"
33
33
  require "ffi-icu/lib"
34
+ require "ffi-icu/lib/util"
34
35
  require "ffi-icu/uchar"
35
36
  require "ffi-icu/chardet"
36
37
  require "ffi-icu/collation"
38
+ require "ffi-icu/locale"
37
39
  require "ffi-icu/transliteration"
38
40
  require "ffi-icu/normalization"
39
41
  require "ffi-icu/break_iterator"
data/lib/ffi-icu/lib.rb CHANGED
@@ -15,7 +15,13 @@ module ICU
15
15
  elsif FFI::Platform::IS_WINDOWS
16
16
  ENV['PATH'].split(File::PATH_SEPARATOR)
17
17
  else
18
- [ '/usr/local/{lib64,lib}', '/opt/local/{lib64,lib}', '/usr/{lib64,lib}' ]
18
+ [
19
+ '/usr/local/{lib64,lib}',
20
+ '/opt/local/{lib64,lib}',
21
+ '/usr/{lib64,lib}',
22
+ '/usr/lib/x86_64-linux-gnu', # for Debian Multiarch http://wiki.debian.org/Multiarch
23
+ '/usr/lib/i386-linux-gnu', # for Debian Multiarch
24
+ ]
19
25
  end
20
26
  end
21
27
  end
@@ -42,7 +48,7 @@ module ICU
42
48
  lib_names.compact! if lib_names
43
49
 
44
50
  if not lib_names or lib_names.length == 0
45
- raise LoadError, "Could not find ICU on #{ICU.platform.inspect}, patches appreciated!"
51
+ raise LoadError, "Could not find ICU on #{ICU.platform.inspect}. Patches welcome, or you can add the containing directory yourself: #{self}.search_paths << '/path/to/lib'"
46
52
  end
47
53
 
48
54
  # And now try to load the library
@@ -123,6 +129,14 @@ module ICU
123
129
  ret
124
130
  end
125
131
 
132
+ def self.cldr_version
133
+ result = FFI::MemoryPointer.new(:char, 64)
134
+ version_info = FFI::MemoryPointer.new(:uint8, 4)
135
+ check_error { |status| ulocdata_getCLDRVersion(version_info, status) }
136
+ u_versionToString(version_info, result)
137
+ result.read_string_to_null
138
+ end
139
+
126
140
  def self.enum_ptr_to_array(enum_ptr)
127
141
  length = check_error do |status|
128
142
  uenum_count(enum_ptr, status)
@@ -150,6 +164,53 @@ module ICU
150
164
  attach_function :uenum_next, "uenum_next#{suffix}", [:pointer, :pointer, :pointer], :string
151
165
  attach_function :u_charsToUChars, "u_charsToUChars#{suffix}", [:string, :pointer, :int32_t], :void
152
166
  attach_function :u_UCharsToChars, "u_UCharsToChars#{suffix}", [:pointer, :string, :int32_t], :void
167
+ attach_function :u_versionToString, "u_versionToString#{suffix}", [:pointer, :pointer], :void
168
+
169
+ #
170
+ # Locale
171
+ #
172
+ # http://icu-project.org/apiref/icu4c/uloc_8h.html
173
+ #
174
+
175
+ enum :layout_type, [:ltr, :rtl, :ttb, :btt, :unknown]
176
+
177
+ attach_function :uloc_addLikelySubtags, "uloc_addLikelySubtags#{suffix}", [:string, :pointer, :int32_t, :pointer], :int32_t
178
+ attach_function :uloc_canonicalize, "uloc_canonicalize#{suffix}", [:string, :pointer, :int32_t, :pointer], :int32_t
179
+ attach_function :uloc_countAvailable, "uloc_countAvailable#{suffix}", [], :int32_t
180
+ attach_function :uloc_forLanguageTag, "uloc_forLanguageTag#{suffix}", [:string, :pointer, :int32_t, :pointer, :pointer], :int32_t
181
+ attach_function :uloc_getAvailable, "uloc_getAvailable#{suffix}", [:int32_t], :string
182
+ attach_function :uloc_getBaseName, "uloc_getBaseName#{suffix}", [:string, :pointer, :int32_t, :pointer], :int32_t
183
+ attach_function :uloc_getCountry, "uloc_getCountry#{suffix}", [:string, :pointer, :int32_t, :pointer], :int32_t
184
+ attach_function :uloc_getDefault, "uloc_getDefault#{suffix}", [], :string
185
+ attach_function :uloc_getISO3Country, "uloc_getISO3Country#{suffix}", [:string], :string
186
+ attach_function :uloc_getISO3Language, "uloc_getISO3Language#{suffix}", [:string], :string
187
+ attach_function :uloc_getISOCountries, "uloc_getISOCountries#{suffix}", [], :pointer
188
+ attach_function :uloc_getISOLanguages, "uloc_getISOLanguages#{suffix}", [], :pointer
189
+ attach_function :uloc_getKeywordValue, "uloc_getKeywordValue#{suffix}", [:string, :string, :pointer, :int32_t, :pointer], :int32_t
190
+ attach_function :uloc_getLanguage, "uloc_getLanguage#{suffix}", [:string, :pointer, :int32_t, :pointer], :int32_t
191
+ attach_function :uloc_getLocaleForLCID, "uloc_getLocaleForLCID#{suffix}", [:uint32, :pointer, :int32_t, :pointer], :int32_t
192
+ attach_function :uloc_getLCID, "uloc_getLCID#{suffix}", [:string], :uint32
193
+ attach_function :uloc_getName, "uloc_getName#{suffix}", [:string, :pointer, :int32_t, :pointer], :int32_t
194
+ attach_function :uloc_getParent, "uloc_getParent#{suffix}", [:string, :pointer, :int32_t, :pointer], :int32_t
195
+ attach_function :uloc_getScript, "uloc_getScript#{suffix}", [:string, :pointer, :int32_t, :pointer], :int32_t
196
+ attach_function :uloc_getVariant, "uloc_getVariant#{suffix}", [:string, :pointer, :int32_t, :pointer], :int32_t
197
+ attach_function :uloc_minimizeSubtags, "uloc_minimizeSubtags#{suffix}", [:string, :pointer, :int32_t, :pointer], :int32_t
198
+ attach_function :uloc_openKeywords, "uloc_openKeywords#{suffix}", [:string, :pointer], :pointer
199
+ attach_function :uloc_setDefault, "uloc_setDefault#{suffix}", [:string, :pointer], :void
200
+ attach_function :uloc_setKeywordValue, "uloc_setKeywordValue#{suffix}", [:string, :string, :pointer, :int32_t, :pointer], :int32_t
201
+ attach_function :uloc_toLanguageTag, "uloc_toLanguageTag#{suffix}", [:string, :pointer, :int32_t, :int8_t, :pointer], :int32_t
202
+
203
+ attach_function :uloc_getCharacterOrientation, "uloc_getCharacterOrientation#{suffix}", [:string, :pointer], :layout_type
204
+ attach_function :uloc_getDisplayCountry, "uloc_getDisplayCountry#{suffix}", [:string, :string, :pointer, :int32_t, :pointer], :int32_t
205
+ attach_function :uloc_getDisplayKeyword, "uloc_getDisplayKeyword#{suffix}", [:string, :string, :pointer, :int32_t, :pointer], :int32_t
206
+ attach_function :uloc_getDisplayKeywordValue, "uloc_getDisplayKeywordValue#{suffix}", [:string, :string, :string, :pointer, :int32_t, :pointer], :int32_t
207
+ attach_function :uloc_getDisplayLanguage, "uloc_getDisplayLanguage#{suffix}", [:string, :string, :pointer, :int32_t, :pointer], :int32_t
208
+ attach_function :uloc_getDisplayName, "uloc_getDisplayName#{suffix}", [:string, :string, :pointer, :int32_t, :pointer], :int32_t
209
+ attach_function :uloc_getDisplayScript, "uloc_getDisplayScript#{suffix}", [:string, :string, :pointer, :int32_t, :pointer], :int32_t
210
+ attach_function :uloc_getDisplayVariant, "uloc_getDisplayVariant#{suffix}", [:string, :string, :pointer, :int32_t, :pointer], :int32_t
211
+ attach_function :uloc_getLineOrientation, "uloc_getLineOrientation#{suffix}", [:string, :pointer], :layout_type
212
+
213
+ attach_function :ulocdata_getCLDRVersion, "ulocdata_getCLDRVersion#{suffix}", [:pointer, :pointer], :void
153
214
 
154
215
  # CharDet
155
216
  #
@@ -0,0 +1,47 @@
1
+ module ICU
2
+ module Lib
3
+ module Util
4
+ def self.read_null_terminated_array_of_strings(pointer)
5
+ offset = 0
6
+ result = []
7
+
8
+ while (ptr = pointer.get_pointer(offset)) != FFI::Pointer::NULL do
9
+ result << ptr.read_string
10
+ offset += FFI::Pointer.size
11
+ end
12
+
13
+ result
14
+ end
15
+
16
+ def self.read_string_buffer(length)
17
+ attempts = 0
18
+
19
+ begin
20
+ result = FFI::MemoryPointer.new(:char, length)
21
+ Lib.check_error { |status| length = yield result, status }
22
+ rescue BufferOverflowError
23
+ attempts += 1
24
+ retry if attempts < 2
25
+ raise BufferOverflowError, "needed: #{length}"
26
+ end
27
+
28
+ result.read_string(length)
29
+ end
30
+
31
+ def self.read_uchar_buffer(length)
32
+ attempts = 0
33
+
34
+ begin
35
+ result = UCharPointer.new(length)
36
+ Lib.check_error { |status| length = yield result, status }
37
+ rescue BufferOverflowError
38
+ attempts += 1
39
+ retry if attempts < 2
40
+ raise BufferOverflowError, "needed: #{length}"
41
+ end
42
+
43
+ result.string(length)
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,224 @@
1
+ module ICU
2
+ class Locale
3
+ class << self
4
+ def available
5
+ (0...Lib.uloc_countAvailable).map do |idx|
6
+ Locale.new(Lib.uloc_getAvailable(idx))
7
+ end
8
+ end
9
+
10
+ def default
11
+ Locale.new(Lib.uloc_getDefault)
12
+ end
13
+
14
+ def default=(locale)
15
+ Lib.check_error { |status| Lib.uloc_setDefault(locale.to_s, status) }
16
+ end
17
+
18
+ def for_language_tag(tag)
19
+ result = Lib::Util.read_string_buffer(64) do |buffer, status|
20
+ Lib.uloc_forLanguageTag(tag, buffer, buffer.size, nil, status)
21
+ end
22
+
23
+ Locale.new(result)
24
+ end
25
+
26
+ def for_lcid(id)
27
+ result = Lib::Util.read_string_buffer(64) do |buffer, status|
28
+ Lib.uloc_getLocaleForLCID(id, buffer, buffer.size, status)
29
+ end
30
+
31
+ Locale.new(result)
32
+ end
33
+
34
+ def iso_countries
35
+ Lib::Util.read_null_terminated_array_of_strings(Lib.uloc_getISOCountries)
36
+ end
37
+
38
+ def iso_languages
39
+ Lib::Util.read_null_terminated_array_of_strings(Lib.uloc_getISOLanguages)
40
+ end
41
+ end
42
+
43
+ attr_reader :id
44
+
45
+ def initialize(id)
46
+ @id = id.to_s
47
+ end
48
+
49
+ def ==(other)
50
+ other.is_a?(self.class) && other.id == self.id
51
+ end
52
+
53
+ def base_name
54
+ Lib::Util.read_string_buffer(64) do |buffer, status|
55
+ Lib.uloc_getBaseName(@id, buffer, buffer.size, status)
56
+ end
57
+ end
58
+
59
+ def canonical
60
+ Lib::Util.read_string_buffer(64) do |buffer, status|
61
+ Lib.uloc_canonicalize(@id, buffer, buffer.size, status)
62
+ end
63
+ end
64
+
65
+ def character_orientation
66
+ Lib.check_error { |status| Lib.uloc_getCharacterOrientation(@id, status) }
67
+ end
68
+
69
+ def country
70
+ Lib::Util.read_string_buffer(64) do |buffer, status|
71
+ Lib.uloc_getCountry(@id, buffer, buffer.size, status)
72
+ end
73
+ end
74
+
75
+ def display_country(locale = nil)
76
+ locale = locale.to_s unless locale.nil?
77
+
78
+ Lib::Util.read_uchar_buffer(64) do |buffer, status|
79
+ Lib.uloc_getDisplayCountry(@id, locale, buffer, buffer.size, status)
80
+ end
81
+ end
82
+
83
+ def display_language(locale = nil)
84
+ locale = locale.to_s unless locale.nil?
85
+
86
+ Lib::Util.read_uchar_buffer(64) do |buffer, status|
87
+ Lib.uloc_getDisplayLanguage(@id, locale, buffer, buffer.size, status)
88
+ end
89
+ end
90
+
91
+ def display_name(locale = nil)
92
+ locale = locale.to_s unless locale.nil?
93
+
94
+ Lib::Util.read_uchar_buffer(64) do |buffer, status|
95
+ Lib.uloc_getDisplayName(@id, locale, buffer, buffer.size, status)
96
+ end
97
+ end
98
+
99
+ def display_script(locale = nil)
100
+ locale = locale.to_s unless locale.nil?
101
+
102
+ Lib::Util.read_uchar_buffer(64) do |buffer, status|
103
+ Lib.uloc_getDisplayScript(@id, locale, buffer, buffer.size, status)
104
+ end
105
+ end
106
+
107
+ def display_variant(locale = nil)
108
+ locale = locale.to_s unless locale.nil?
109
+
110
+ Lib::Util.read_uchar_buffer(64) do |buffer, status|
111
+ Lib.uloc_getDisplayVariant(@id, locale, buffer, buffer.size, status)
112
+ end
113
+ end
114
+
115
+ def iso_country
116
+ Lib.uloc_getISO3Country(@id)
117
+ end
118
+
119
+ def iso_language
120
+ Lib.uloc_getISO3Language(@id)
121
+ end
122
+
123
+ def keyword(keyword)
124
+ Lib::Util.read_string_buffer(64) do |buffer, status|
125
+ Lib.uloc_getKeywordValue(@id, keyword.to_s, buffer, buffer.size, status)
126
+ end
127
+ end
128
+
129
+ def keywords
130
+ enum_ptr = Lib.check_error { |status| Lib.uloc_openKeywords(@id, status) }
131
+
132
+ begin
133
+ Lib.enum_ptr_to_array(enum_ptr)
134
+ ensure
135
+ Lib.uenum_close(enum_ptr)
136
+ end
137
+ end
138
+
139
+ def language
140
+ Lib::Util.read_string_buffer(64) do |buffer, status|
141
+ Lib.uloc_getLanguage(@id, buffer, buffer.size, status)
142
+ end
143
+ end
144
+
145
+ def lcid
146
+ Lib.uloc_getLCID(@id)
147
+ end
148
+
149
+ def line_orientation
150
+ Lib.check_error { |status| Lib.uloc_getLineOrientation(@id, status) }
151
+ end
152
+
153
+ def name
154
+ Lib::Util.read_string_buffer(64) do |buffer, status|
155
+ Lib.uloc_getName(@id, buffer, buffer.size, status)
156
+ end
157
+ end
158
+
159
+ def parent
160
+ Lib::Util.read_string_buffer(64) do |buffer, status|
161
+ Lib.uloc_getParent(@id, buffer, buffer.size, status)
162
+ end
163
+ end
164
+
165
+ def script
166
+ Lib::Util.read_string_buffer(64) do |buffer, status|
167
+ Lib.uloc_getScript(@id, buffer, buffer.size, status)
168
+ end
169
+ end
170
+
171
+ def to_language_tag(strict = false)
172
+ Lib::Util.read_string_buffer(64) do |buffer, status|
173
+ Lib.uloc_toLanguageTag(@id, buffer, buffer.size, strict ? 1 : 0, status)
174
+ end
175
+ end
176
+
177
+ alias_method :to_s, :id
178
+
179
+ def variant
180
+ Lib::Util.read_string_buffer(64) do |buffer, status|
181
+ Lib.uloc_getVariant(@id, buffer, buffer.size, status)
182
+ end
183
+ end
184
+
185
+ def with_keyword(keyword, value)
186
+ keyword = keyword.to_s
187
+ length = @id.length + keyword.length + 64
188
+
189
+ unless value.nil?
190
+ value = value.to_s
191
+ length += value.length
192
+ end
193
+
194
+ result = Lib::Util.read_string_buffer(length) do |buffer, status|
195
+ buffer.write_string(@id)
196
+ Lib.uloc_setKeywordValue(keyword, value, buffer, buffer.size, status)
197
+ end
198
+
199
+ Locale.new(result)
200
+ end
201
+
202
+ def with_keywords(hash)
203
+ hash.reduce(self) do |locale, (keyword, value)|
204
+ locale.with_keyword(keyword, value)
205
+ end
206
+ end
207
+
208
+ def with_likely_subtags
209
+ result = Lib::Util.read_string_buffer(64) do |buffer, status|
210
+ Lib.uloc_addLikelySubtags(@id, buffer, buffer.size, status)
211
+ end
212
+
213
+ Locale.new(result)
214
+ end
215
+
216
+ def with_minimized_subtags
217
+ result = Lib::Util.read_string_buffer(64) do |buffer, status|
218
+ Lib.uloc_minimizeSubtags(@id, buffer, buffer.size, status)
219
+ end
220
+
221
+ Locale.new(result)
222
+ end
223
+ end
224
+ end
data/lib/ffi-icu/uchar.rb CHANGED
@@ -9,7 +9,7 @@ module ICU
9
9
  bytes = str.unpack("U*")
10
10
 
11
11
  ptr = new bytes.size
12
- ptr.put_array_of_uint16 0, bytes
12
+ ptr.write_array_of_uint16 bytes
13
13
 
14
14
  ptr
15
15
  end
@@ -29,7 +29,7 @@ module ICU
29
29
  def string(length = nil)
30
30
  length ||= size / TYPE_SIZE
31
31
 
32
- wstring = get_array_of_uint16(0, length)
32
+ wstring = read_array_of_uint16(length)
33
33
  wstring.pack("U*")
34
34
  end
35
35
 
@@ -1,3 +1,3 @@
1
1
  module ICU
2
- VERSION = "0.0.9"
2
+ VERSION = "0.1.0"
3
3
  end
@@ -36,7 +36,7 @@ module ICU
36
36
  it "should compare two strings" do
37
37
  collator.compare("blåbærsyltetøy", "blah").should == 1
38
38
  collator.compare("blah", "blah").should == 0
39
- collator.compare("baah", "blah").should == -1
39
+ collator.compare("ba", "bl").should == -1
40
40
  end
41
41
 
42
42
  it "should know if a string is greater than another" do
data/spec/lib_spec.rb ADDED
@@ -0,0 +1,47 @@
1
+ # encoding: UTF-8
2
+
3
+ require 'spec_helper'
4
+
5
+ module ICU
6
+ describe Lib do
7
+ describe 'error checking' do
8
+ let(:return_value) { double }
9
+
10
+ context 'upon success' do
11
+ it 'returns the block result' do
12
+ Lib.check_error { |status| return_value }.should == return_value
13
+ Lib.check_error { |status| status.write_int(0); return_value }.should == return_value
14
+ end
15
+ end
16
+
17
+ context 'upon failure' do
18
+ it 'raises an error' do
19
+ expect { Lib.check_error { |status| status.write_int(1) } }.to raise_error ICU::Error, /U_.*_ERROR/
20
+ end
21
+ end
22
+
23
+ context 'upon warning' do
24
+ before(:each) { @verbose = $VERBOSE }
25
+ after(:each) { $VERBOSE = @verbose }
26
+
27
+ context 'when warnings are enabled' do
28
+ before(:each) { $VERBOSE = true }
29
+
30
+ it 'prints to STDERR and returns the block result' do
31
+ $stderr.should_receive(:puts) { |message| message.should match /U_.*_WARNING/ }
32
+ Lib.check_error { |status| status.write_int(-127); return_value }.should == return_value
33
+ end
34
+ end
35
+
36
+ context 'when warnings are disabled' do
37
+ before(:each) { $VERBOSE = false }
38
+
39
+ it 'returns the block result' do
40
+ $stderr.should_not_receive(:puts)
41
+ Lib.check_error { |status| status.write_int(-127); return_value }.should == return_value
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,250 @@
1
+ # encoding: UTF-8
2
+
3
+ require 'spec_helper'
4
+
5
+ module ICU
6
+ describe Locale do
7
+ describe 'the available locales' do
8
+ subject { Locale.available }
9
+
10
+ it { should be_an Array }
11
+ it { should_not be_empty }
12
+ its(:first) { should be_a Locale }
13
+ end
14
+
15
+ describe 'the available ISO 639 country codes' do
16
+ subject { Locale.iso_countries }
17
+
18
+ it { should be_an Array }
19
+ it { should_not be_empty }
20
+ its(:first) { should be_a String }
21
+ end
22
+
23
+ describe 'the available ISO 639 language codes' do
24
+ subject { Locale.iso_languages }
25
+
26
+ it { should be_an Array }
27
+ it { should_not be_empty }
28
+ its(:first) { should be_a String }
29
+ end
30
+
31
+ describe 'the default' do
32
+ subject { Locale.default }
33
+
34
+ let(:locale) do
35
+ locales = Locale.available
36
+ locales.delete(Locale.default)
37
+ locales.respond_to?(:sample) ? locales.sample : locales.choice
38
+ end
39
+
40
+ it { should be_a Locale }
41
+
42
+ it 'can be assigned using Locale' do
43
+ (Locale.default = locale).should == locale
44
+ Locale.default.should == locale
45
+ end
46
+
47
+ it 'can be assigned using string' do
48
+ string = locale.to_s
49
+
50
+ (Locale.default = string).should == string
51
+ Locale.default.should == Locale.new(string)
52
+ end
53
+
54
+ it 'can be assigned using symbol' do
55
+ symbol = locale.to_s.to_sym
56
+
57
+ (Locale.default = symbol).should == symbol
58
+ Locale.default.should == Locale.new(symbol)
59
+ end
60
+ end
61
+
62
+ describe 'BCP 47 language tags' do
63
+ it 'converts a language tag to a locale' do
64
+ Locale.for_language_tag('en-us').should == Locale.new('en_US')
65
+ Locale.for_language_tag('nan-Hant-tw').should == Locale.new('nan_Hant_TW')
66
+ end
67
+
68
+ it 'returns a language tag for a locale' do
69
+ if Gem::Version.new(Lib.cldr_version) < Gem::Version.new('1.8')
70
+ Locale.new('en_US').to_language_tag.should == 'en-us'
71
+ Locale.new('zh_TW').to_language_tag.should == 'zh-tw'
72
+ Locale.new('zh_Hans_CH_PINYIN').to_language_tag.should == 'zh-hans-ch-u-co-pinyin'
73
+ else
74
+ Locale.new('en_US').to_language_tag.should == 'en-US'
75
+ Locale.new('zh_TW').to_language_tag.should == 'zh-TW'
76
+ Locale.new('zh_Hans_CH_PINYIN').to_language_tag.should == 'zh-Hans-CH-u-co-pinyin'
77
+ end
78
+ end
79
+ end
80
+
81
+ describe 'Win32 locale IDs' do
82
+ it 'converts an LCID to a locale' do
83
+ Locale.for_lcid(1033).should == Locale.new('en_US')
84
+ Locale.for_lcid(1036).should == Locale.new('fr_FR')
85
+ end
86
+
87
+ it 'returns an LCID for a locale' do
88
+ Locale.new('en_US').lcid.should == 1033
89
+ Locale.new('es_US').lcid.should == 21514
90
+ end
91
+ end
92
+
93
+ describe 'display' do
94
+ context 'in a specific locale' do
95
+ it 'returns the country' do
96
+ Locale.new('de_DE').display_country('en').should == 'Germany'
97
+ Locale.new('en_US').display_country('fr').should == 'États-Unis'
98
+ end
99
+
100
+ it 'returns the language' do
101
+ Locale.new('fr_FR').display_language('de').should == 'Französisch'
102
+ Locale.new('zh_CH').display_language('en').should == 'Chinese'
103
+ end
104
+
105
+ it 'returns the name' do
106
+ Locale.new('en_US').display_name('de').should == 'Englisch (Vereinigte Staaten)'
107
+ Locale.new('zh_CH').display_name('fr').should == 'chinois (Suisse)'
108
+ end
109
+
110
+ it 'returns the script' do
111
+ Locale.new('ja_Hira_JP').display_script('en').should == 'Hiragana'
112
+ Locale.new('ja_Hira_JP').display_script('ru').should == 'Хирагана'
113
+ end
114
+
115
+ it 'returns the variant' do
116
+ Locale.new('zh_Hans_CH_PINYIN').display_variant('en').should == 'Pinyin Romanization'
117
+
118
+ if Gem::Version.new(Lib.cldr_version) > Gem::Version.new('1.8')
119
+ Locale.new('zh_Hans_CH_PINYIN').display_variant('es').should == 'Romanización pinyin'
120
+ end
121
+ end
122
+ end
123
+
124
+ context 'in the default locale' do
125
+ let(:locale) { Locale.new('de_DE') }
126
+
127
+ it 'returns the country' do
128
+ locale.display_country.should == locale.display_country(Locale.default)
129
+ end
130
+
131
+ it 'returns the language' do
132
+ locale.display_language.should == locale.display_language(Locale.default)
133
+ end
134
+
135
+ it 'returns the name' do
136
+ locale.display_name.should == locale.display_name(Locale.default)
137
+ end
138
+
139
+ it 'returns the script' do
140
+ locale.display_script.should == locale.display_script(Locale.default)
141
+ end
142
+
143
+ it 'returns the variant' do
144
+ locale.display_variant.should == locale.display_variant(Locale.default)
145
+ end
146
+ end
147
+ end
148
+
149
+ describe 'formatting' do
150
+ let(:locale) { Locale.new('de-de.utf8@collation = phonebook') }
151
+
152
+ it('is formatted') { locale.name.should == 'de_DE.utf8@collation=phonebook' }
153
+ it('is formatted without keywords') { locale.base_name.should == 'de_DE.utf8' }
154
+ it('is formatted for ICU') { locale.canonical.should == 'de_DE@collation=phonebook' }
155
+ end
156
+
157
+ it 'truncates a properly formatted locale, returning the "parent"' do
158
+ Locale.new('es-mx').parent.should == ''
159
+ Locale.new('es_MX').parent.should == 'es'
160
+ Locale.new('zh_Hans_CH_PINYIN').parent.should == 'zh_Hans_CH'
161
+ end
162
+
163
+ describe 'ISO codes' do
164
+ it 'returns the ISO 3166 alpha-3 country code' do
165
+ Locale.new('en_US').iso_country.should == 'USA'
166
+ Locale.new('zh_CN').iso_country.should == 'CHN'
167
+ end
168
+
169
+ it 'returns the ISO 639 three-letter language code' do
170
+ Locale.new('en_US').iso_language.should == 'eng'
171
+ Locale.new('zh_CN').iso_language.should == 'zho'
172
+ end
173
+ end
174
+
175
+ describe 'keywords' do
176
+ context 'when improperly formatted' do
177
+ let(:locale) { Locale.new('de_DE@euro') }
178
+
179
+ it 'raises an error' do
180
+ expect { locale.keywords }.to raise_error(ICU::Error)
181
+ end
182
+ end
183
+
184
+ context 'when properly formatted' do
185
+ let(:locale) { Locale.new('de_DE@currency=EUR') }
186
+
187
+ it 'returns the list of keywords' do
188
+ locale.keywords.should == ['currency']
189
+ end
190
+ end
191
+
192
+ it 'can be read' do
193
+ Locale.new('en_US@calendar=chinese').keyword('calendar').should == 'chinese'
194
+ Locale.new('en_US@calendar=chinese').keyword(:calendar).should == 'chinese'
195
+ Locale.new('en_US@some=thing').keyword('missing').should == ''
196
+ end
197
+
198
+ it 'can be added' do
199
+ Locale.new('de_DE').with_keyword('currency', 'EUR').should == Locale.new('de_DE@currency=EUR')
200
+ Locale.new('de_DE').with_keyword(:currency, :EUR).should == Locale.new('de_DE@currency=EUR')
201
+ end
202
+
203
+ it 'can be added using hash' do
204
+ Locale.new('fr').with_keywords(:a => :b, :c => :d).should == Locale.new('fr@a=b;c=d')
205
+ end
206
+
207
+ it 'can be removed' do
208
+ Locale.new('en_US@some=thing').with_keyword(:some, nil).should == Locale.new('en_US')
209
+ Locale.new('en_US@some=thing').with_keyword(:some, '').should == Locale.new('en_US')
210
+ end
211
+ end
212
+
213
+ describe 'orientation' do
214
+ it 'returns the character orientation' do
215
+ Locale.new('ar').character_orientation.should == :rtl
216
+ Locale.new('en').character_orientation.should == :ltr
217
+ Locale.new('fa').character_orientation.should == :rtl
218
+ end
219
+
220
+ it 'returns the line orientation' do
221
+ Locale.new('ar').line_orientation.should == :ttb
222
+ Locale.new('en').line_orientation.should == :ttb
223
+ Locale.new('fa').line_orientation.should == :ttb
224
+ end
225
+ end
226
+
227
+ describe 'subtags' do
228
+ let(:locale) { Locale.new('zh-hans-ch-pinyin') }
229
+
230
+ it('returns the country code') { locale.country.should == 'CH' }
231
+ it('returns the language code') { locale.language.should == 'zh' }
232
+ it('returns the script code') { locale.script.should == 'Hans' }
233
+ it('returns the variant code') { locale.variant.should == 'PINYIN' }
234
+
235
+ describe 'likely subtags according to UTS #35' do
236
+ it 'adds likely subtags' do
237
+ Locale.new('en').with_likely_subtags.should == Locale.new('en_Latn_US')
238
+ Locale.new('sr').with_likely_subtags.should == Locale.new('sr_Cyrl_RS')
239
+ Locale.new('zh_TW').with_likely_subtags.should == Locale.new('zh_Hant_TW')
240
+ end
241
+
242
+ it 'removes likely subtags' do
243
+ Locale.new('en_US').with_minimized_subtags.should == Locale.new('en')
244
+ Locale.new('sr_RS').with_minimized_subtags.should == Locale.new('sr')
245
+ Locale.new('zh_Hant_TW').with_minimized_subtags.should == Locale.new('zh_TW')
246
+ end
247
+ end
248
+ end
249
+ end
250
+ end
@@ -0,0 +1,31 @@
1
+ # encoding: UTF-8
2
+
3
+ require 'spec_helper'
4
+
5
+ module ICU
6
+ describe UCharPointer do
7
+ it 'allocates enough memory for 16-bit characters' do
8
+ UCharPointer.new(5).size.should == 10
9
+ end
10
+
11
+ it 'builds a buffer from a string' do
12
+ ptr = UCharPointer.from_string('abc')
13
+ ptr.should be_a UCharPointer
14
+ ptr.size.should == 6
15
+ ptr.read_array_of_uint16(3).should == [0x61, 0x62, 0x63]
16
+ end
17
+
18
+ describe 'converting to string' do
19
+ let(:ptr) { UCharPointer.new(3).write_array_of_uint16 [0x78, 0x0, 0x79] }
20
+
21
+ it 'returns the the entire buffer by default' do
22
+ ptr.string.should == "x\0y"
23
+ end
24
+
25
+ it 'returns strings of the specified length' do
26
+ ptr.string(0).should == ""
27
+ ptr.string(2).should == "x\0"
28
+ end
29
+ end
30
+ end
31
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ffi-icu
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.9
4
+ version: 0.1.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -84,6 +84,8 @@ files:
84
84
  - lib/ffi-icu/collation.rb
85
85
  - lib/ffi-icu/core_ext/string.rb
86
86
  - lib/ffi-icu/lib.rb
87
+ - lib/ffi-icu/lib/util.rb
88
+ - lib/ffi-icu/locale.rb
87
89
  - lib/ffi-icu/normalization.rb
88
90
  - lib/ffi-icu/transliteration.rb
89
91
  - lib/ffi-icu/uchar.rb
@@ -91,10 +93,13 @@ files:
91
93
  - spec/break_iterator_spec.rb
92
94
  - spec/chardet_spec.rb
93
95
  - spec/collation_spec.rb
96
+ - spec/lib_spec.rb
97
+ - spec/locale_spec.rb
94
98
  - spec/normalization_spec.rb
95
99
  - spec/spec.opts
96
100
  - spec/spec_helper.rb
97
101
  - spec/transliteration_spec.rb
102
+ - spec/uchar_spec.rb
98
103
  - test.c
99
104
  homepage: http://github.com/jarib/ffi-icu
100
105
  licenses: []
@@ -125,8 +130,11 @@ test_files:
125
130
  - spec/break_iterator_spec.rb
126
131
  - spec/chardet_spec.rb
127
132
  - spec/collation_spec.rb
133
+ - spec/lib_spec.rb
134
+ - spec/locale_spec.rb
128
135
  - spec/normalization_spec.rb
129
136
  - spec/spec.opts
130
137
  - spec/spec_helper.rb
131
138
  - spec/transliteration_spec.rb
139
+ - spec/uchar_spec.rb
132
140
  has_rdoc: