twitter_cldr 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.
Files changed (180) hide show
  1. data/LICENSE +177 -0
  2. data/NOTICE +26 -0
  3. data/README.md +83 -0
  4. data/Rakefile +36 -0
  5. data/lib/ext/calendars/date.rb +20 -0
  6. data/lib/ext/calendars/datetime.rb +36 -0
  7. data/lib/ext/calendars/time.rb +20 -0
  8. data/lib/ext/localized_object.rb +15 -0
  9. data/lib/ext/numbers/bignum.rb +3 -0
  10. data/lib/ext/numbers/fixnum.rb +3 -0
  11. data/lib/ext/numbers/float.rb +3 -0
  12. data/lib/ext/numbers/localized_number.rb +53 -0
  13. data/lib/ext/strings/symbol.rb +17 -0
  14. data/lib/formatters/base.rb +36 -0
  15. data/lib/formatters/calendars/date_formatter.rb +9 -0
  16. data/lib/formatters/calendars/datetime_formatter.rb +217 -0
  17. data/lib/formatters/calendars/time_formatter.rb +9 -0
  18. data/lib/formatters/numbers/currency_formatter.rb +25 -0
  19. data/lib/formatters/numbers/decimal_formatter.rb +22 -0
  20. data/lib/formatters/numbers/helpers/base.rb +18 -0
  21. data/lib/formatters/numbers/helpers/fraction.rb +29 -0
  22. data/lib/formatters/numbers/helpers/integer.rb +46 -0
  23. data/lib/formatters/numbers/number_formatter.rb +48 -0
  24. data/lib/formatters/numbers/percent_formatter.rb +18 -0
  25. data/lib/formatters/plurals/rules.rb +34 -0
  26. data/lib/shared/currencies.rb +33 -0
  27. data/lib/shared/languages.rb +48 -0
  28. data/lib/shared/resources.rb +45 -0
  29. data/lib/shared/timezones.rb +1 -0
  30. data/lib/tokenizers/base.rb +112 -0
  31. data/lib/tokenizers/calendars/date_tokenizer.rb +24 -0
  32. data/lib/tokenizers/calendars/datetime_tokenizer.rb +46 -0
  33. data/lib/tokenizers/calendars/time_tokenizer.rb +24 -0
  34. data/lib/tokenizers/key_path.rb +30 -0
  35. data/lib/tokenizers/numbers/number_tokenizer.rb +50 -0
  36. data/lib/tokenizers/token.rb +17 -0
  37. data/lib/twitter_cldr.rb +104 -0
  38. data/lib/version.rb +3 -0
  39. data/resources/ar/calendars.yml +145 -0
  40. data/resources/ar/languages.yml +498 -0
  41. data/resources/ar/numbers.yml +35 -0
  42. data/resources/ar/plurals.yml +1 -0
  43. data/resources/da/calendars.yml +157 -0
  44. data/resources/da/languages.yml +508 -0
  45. data/resources/da/numbers.yml +31 -0
  46. data/resources/da/plurals.yml +1 -0
  47. data/resources/de/calendars.yml +152 -0
  48. data/resources/de/languages.yml +508 -0
  49. data/resources/de/numbers.yml +31 -0
  50. data/resources/de/plurals.yml +1 -0
  51. data/resources/en/calendars.yml +145 -0
  52. data/resources/en/languages.yml +510 -0
  53. data/resources/en/numbers.yml +31 -0
  54. data/resources/en/plurals.yml +1 -0
  55. data/resources/es/calendars.yml +145 -0
  56. data/resources/es/languages.yml +508 -0
  57. data/resources/es/numbers.yml +30 -0
  58. data/resources/es/plurals.yml +1 -0
  59. data/resources/fa/calendars.yml +150 -0
  60. data/resources/fa/languages.yml +484 -0
  61. data/resources/fa/numbers.yml +30 -0
  62. data/resources/fa/plurals.yml +1 -0
  63. data/resources/fi/calendars.yml +176 -0
  64. data/resources/fi/languages.yml +508 -0
  65. data/resources/fi/numbers.yml +31 -0
  66. data/resources/fi/plurals.yml +1 -0
  67. data/resources/fil/calendars.yml +159 -0
  68. data/resources/fil/languages.yml +115 -0
  69. data/resources/fil/numbers.yml +31 -0
  70. data/resources/fil/plurals.yml +1 -0
  71. data/resources/fr/calendars.yml +149 -0
  72. data/resources/fr/languages.yml +508 -0
  73. data/resources/fr/numbers.yml +31 -0
  74. data/resources/fr/plurals.yml +1 -0
  75. data/resources/he/calendars.yml +145 -0
  76. data/resources/he/languages.yml +266 -0
  77. data/resources/he/numbers.yml +31 -0
  78. data/resources/he/plurals.yml +1 -0
  79. data/resources/hi/calendars.yml +144 -0
  80. data/resources/hi/languages.yml +505 -0
  81. data/resources/hi/numbers.yml +31 -0
  82. data/resources/hi/plurals.yml +1 -0
  83. data/resources/hu/calendars.yml +145 -0
  84. data/resources/hu/languages.yml +508 -0
  85. data/resources/hu/numbers.yml +30 -0
  86. data/resources/hu/plurals.yml +1 -0
  87. data/resources/id/calendars.yml +145 -0
  88. data/resources/id/languages.yml +506 -0
  89. data/resources/id/numbers.yml +30 -0
  90. data/resources/id/plurals.yml +1 -0
  91. data/resources/it/calendars.yml +164 -0
  92. data/resources/it/languages.yml +503 -0
  93. data/resources/it/numbers.yml +30 -0
  94. data/resources/it/plurals.yml +1 -0
  95. data/resources/ja/calendars.yml +157 -0
  96. data/resources/ja/languages.yml +502 -0
  97. data/resources/ja/numbers.yml +30 -0
  98. data/resources/ja/plurals.yml +1 -0
  99. data/resources/ko/calendars.yml +133 -0
  100. data/resources/ko/languages.yml +505 -0
  101. data/resources/ko/numbers.yml +30 -0
  102. data/resources/ko/plurals.yml +1 -0
  103. data/resources/ms/calendars.yml +145 -0
  104. data/resources/ms/languages.yml +54 -0
  105. data/resources/ms/numbers.yml +30 -0
  106. data/resources/ms/plurals.yml +1 -0
  107. data/resources/nl/calendars.yml +145 -0
  108. data/resources/nl/languages.yml +508 -0
  109. data/resources/nl/numbers.yml +31 -0
  110. data/resources/nl/plurals.yml +1 -0
  111. data/resources/no/calendars.yml +122 -0
  112. data/resources/no/languages.yml +508 -0
  113. data/resources/no/numbers.yml +30 -0
  114. data/resources/no/plurals.yml +1 -0
  115. data/resources/pl/calendars.yml +161 -0
  116. data/resources/pl/languages.yml +504 -0
  117. data/resources/pl/numbers.yml +31 -0
  118. data/resources/pl/plurals.yml +1 -0
  119. data/resources/pt/calendars.yml +145 -0
  120. data/resources/pt/languages.yml +508 -0
  121. data/resources/pt/numbers.yml +31 -0
  122. data/resources/pt/plurals.yml +1 -0
  123. data/resources/ru/calendars.yml +176 -0
  124. data/resources/ru/languages.yml +508 -0
  125. data/resources/ru/numbers.yml +30 -0
  126. data/resources/ru/plurals.yml +1 -0
  127. data/resources/shared/currencies.yml +451 -0
  128. data/resources/sv/calendars.yml +145 -0
  129. data/resources/sv/languages.yml +508 -0
  130. data/resources/sv/numbers.yml +31 -0
  131. data/resources/sv/plurals.yml +1 -0
  132. data/resources/th/calendars.yml +145 -0
  133. data/resources/th/languages.yml +507 -0
  134. data/resources/th/numbers.yml +30 -0
  135. data/resources/th/plurals.yml +1 -0
  136. data/resources/tr/calendars.yml +145 -0
  137. data/resources/tr/languages.yml +508 -0
  138. data/resources/tr/numbers.yml +30 -0
  139. data/resources/tr/plurals.yml +1 -0
  140. data/resources/ur/calendars.yml +133 -0
  141. data/resources/ur/languages.yml +81 -0
  142. data/resources/ur/numbers.yml +31 -0
  143. data/resources/ur/plurals.yml +1 -0
  144. data/resources/zh/calendars.yml +169 -0
  145. data/resources/zh/languages.yml +506 -0
  146. data/resources/zh/numbers.yml +30 -0
  147. data/resources/zh/plurals.yml +1 -0
  148. data/resources/zh-Hant/calendars.yml +141 -0
  149. data/resources/zh-Hant/languages.yml +409 -0
  150. data/resources/zh-Hant/numbers.yml +30 -0
  151. data/spec/ext/calendars/date_spec.rb +45 -0
  152. data/spec/ext/calendars/datetime_spec.rb +43 -0
  153. data/spec/ext/calendars/time_spec.rb +45 -0
  154. data/spec/ext/numbers/bignum_spec.rb +19 -0
  155. data/spec/ext/numbers/fixnum_spec.rb +19 -0
  156. data/spec/ext/numbers/float_spec.rb +19 -0
  157. data/spec/ext/numbers/localized_number_spec.rb +53 -0
  158. data/spec/ext/strings/symbol_spec.rb +23 -0
  159. data/spec/formatters/base_spec.rb +12 -0
  160. data/spec/formatters/calendars/datetime_formatter_spec.rb +324 -0
  161. data/spec/formatters/numbers/currency_formatter_spec.rb +27 -0
  162. data/spec/formatters/numbers/decimal_formatter_spec.rb +30 -0
  163. data/spec/formatters/numbers/helpers/fraction_spec.rb +22 -0
  164. data/spec/formatters/numbers/helpers/integer_spec.rb +99 -0
  165. data/spec/formatters/numbers/number_formatter_spec.rb +79 -0
  166. data/spec/formatters/numbers/percent_formatter_spec.rb +12 -0
  167. data/spec/formatters/plurals/rules_spec.rb +73 -0
  168. data/spec/shared/currencies_spec.rb +55 -0
  169. data/spec/shared/languages_spec.rb +82 -0
  170. data/spec/shared/resources_spec.rb +44 -0
  171. data/spec/spec_helper.rb +31 -0
  172. data/spec/tokenizers/base_spec.rb +134 -0
  173. data/spec/tokenizers/calendars/date_tokenizer_spec.rb +36 -0
  174. data/spec/tokenizers/calendars/datetime_tokenizer_spec.rb +52 -0
  175. data/spec/tokenizers/calendars/time_tokenizer_spec.rb +34 -0
  176. data/spec/tokenizers/key_path_spec.rb +44 -0
  177. data/spec/tokenizers/numbers/number_tokenizer_spec.rb +60 -0
  178. data/spec/tokenizers/token_spec.rb +18 -0
  179. data/spec/twitter_cldr_spec.rb +53 -0
  180. metadata +293 -0
@@ -0,0 +1,73 @@
1
+ require File.join(File.dirname(File.dirname(File.dirname(__FILE__))), "spec_helper")
2
+ include TwitterCldr::Formatters::Plurals
3
+
4
+ describe Rules do
5
+ describe "#get_resource" do
6
+ it "calls eval on the hash that gets returned, lambdas and all" do
7
+ result = Rules.send(:get_resource, :ru)
8
+ result.should include(:ru)
9
+ result[:ru].should include(:i18n)
10
+ result[:ru][:i18n].should include(:plural)
11
+ result[:ru][:i18n][:plural].should include(:keys)
12
+ result[:ru][:i18n][:plural][:keys].size.should == 4
13
+
14
+ result[:ru][:i18n][:plural].should include(:rule)
15
+ result[:ru][:i18n][:plural][:rule].should be_a(Proc)
16
+ end
17
+ end
18
+
19
+ describe "#rule_for" do
20
+ it "returns :one for English 1, :other for everything else" do
21
+ Rules.rule_for(1, :en).should == :one
22
+ [5, 9, 10, 20, 60, 99, 100, 103, 141].each do |num|
23
+ Rules.rule_for(num, :en).should == :other
24
+ end
25
+ end
26
+
27
+ it "returns the correct values for Russian rules" do
28
+ Rules.rule_for(1, :ru).should == :one
29
+ Rules.rule_for(2, :ru).should == :few
30
+ Rules.rule_for(3, :ru).should == :few
31
+ Rules.rule_for(4, :ru).should == :few
32
+ Rules.rule_for(5, :ru).should == :many
33
+ Rules.rule_for(6, :ru).should == :many
34
+ Rules.rule_for(7, :ru).should == :many
35
+ Rules.rule_for(8, :ru).should == :many
36
+ Rules.rule_for(9, :ru).should == :many
37
+ Rules.rule_for(10, :ru).should == :many
38
+ Rules.rule_for(11, :ru).should == :many
39
+
40
+ Rules.rule_for(101, :ru).should == :one
41
+ Rules.rule_for(102, :ru).should == :few
42
+ Rules.rule_for(111, :ru).should == :many
43
+ end
44
+
45
+ it "returns :other if there's an error" do
46
+ stub(Rules).get_resource { lambda { raise "Jelly beans" } }
47
+ Rules.rule_for(1, :en).should == :other
48
+ Rules.rule_for(1, :ru).should == :other
49
+ end
50
+ end
51
+
52
+ describe "#all_for" do
53
+ it "returns a list of all applicable rules for the given locale" do
54
+ Rules.all_for(:en).each { |rule| [:one, :other].should include(rule) }
55
+ Rules.all_for(:ru).each { |rule| [:one, :few, :many, :other].should include(rule) }
56
+ end
57
+
58
+ it "should return an empty array on error" do
59
+ stub(Rules).get_resource { lambda { raise "Jelly beans" } }
60
+ Rules.all_for(:en).should == []
61
+ Rules.all_for(:ru).should == []
62
+ end
63
+ end
64
+
65
+ describe "#all" do
66
+ it "gets rules for the default locale (usually supplied by FastGettext)" do
67
+ mock(TwitterCldr).get_locale { :ru }
68
+ rules = Rules.all
69
+ rules.size.should == 4
70
+ rules.each { |rule| [:one, :few, :many, :other].should include(rule) }
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,55 @@
1
+ require File.join(File.dirname(__FILE__), %w[.. spec_helper])
2
+ include TwitterCldr::Shared
3
+
4
+ TEST_COUNTRIES = ["Australia", "Thailand", "Russia", "China", "Japan", "Peru", "South Africa", "India", "South Korea", "United Kingdom"]
5
+ TEST_CODES = ["AUD", "THB", "RUB", "CNY", "JPY", "PEN", "ZAR", "INR", "KRW", "GBP"]
6
+
7
+ describe Currencies do
8
+ describe "#countries" do
9
+ it "should list all supported countries" do
10
+ countries = Currencies.countries
11
+ countries.size.should == 112
12
+ TEST_COUNTRIES.each { |country| countries.should include(country) }
13
+ end
14
+ end
15
+
16
+ describe "#currency_codes" do
17
+ it "should list all supported country codes" do
18
+ codes = Currencies.currency_codes
19
+ codes.size.should == 112
20
+ TEST_CODES.each { |code| codes.should include(code) }
21
+ end
22
+ end
23
+
24
+ describe "#for_country" do
25
+ it "should return all information for the given country" do
26
+ data = Currencies.for_country("Peru")
27
+ data.should be_a(Hash)
28
+
29
+ data.should include(:code)
30
+ data[:code].should == "PEN"
31
+ data.should include(:currency)
32
+ data[:currency].should == "Nuevo Sol"
33
+ data.should include(:symbol)
34
+ data[:symbol].should == "S/."
35
+
36
+ data.should_not include(:country)
37
+ end
38
+ end
39
+
40
+ describe "#for_code" do
41
+ it "should return all information for the given currency code" do
42
+ data = Currencies.for_code("PEN")
43
+ data.should be_a(Hash)
44
+
45
+ data.should include(:country)
46
+ data[:country].should == "Peru"
47
+ data.should include(:currency)
48
+ data[:currency].should == "Nuevo Sol"
49
+ data.should include(:symbol)
50
+ data[:symbol].should == "S/."
51
+
52
+ data.should_not include(:code)
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,82 @@
1
+ require File.join(File.dirname(__FILE__), %w[.. spec_helper])
2
+ include TwitterCldr::Shared
3
+
4
+ describe Languages do
5
+ describe "#translate_language" do
6
+ it "should translate a language from one locale to another" do
7
+ Languages.translate_language("Russian", :en, :es).should == "ruso"
8
+ Languages.translate_language("ruso", :es, :en).should == "Russian"
9
+ Languages.translate_language("Spanish", :en, :es).should == "español"
10
+ Languages.translate_language("ruso", :es, :ru).should == "русский"
11
+ end
12
+
13
+ it "should be capitalization agnostic" do
14
+ Languages.translate_language("russian", :en, :es).should == "ruso"
15
+ Languages.translate_language("RUSSIAN", :en, :es).should == "ruso"
16
+ end
17
+
18
+ it "defaults the destination language to English (or whatever FastGettext.locale is)" do
19
+ Languages.translate_language("Ruso", :es).should == "Russian"
20
+ Languages.translate_language("русский", :ru).should == "Russian"
21
+ end
22
+
23
+ it "defaults source and destination language to English if not given" do
24
+ Languages.translate_language("Russian").should == "Russian"
25
+ FastGettext.locale = :es
26
+ Languages.translate_language("Russian").should == "ruso"
27
+ end
28
+
29
+ it "successfully translates locale codes that are and are not in the CLDR using the locale map" do
30
+ Languages.translate_language("Russian", :en, :'zh-cn').should == "俄文"
31
+ Languages.translate_language("Russian", :en, :'zh').should == "俄文"
32
+ end
33
+
34
+ it "should return nil if no translation was found" do
35
+ Languages.translate_language("Russian", :en, :blarg).should == nil
36
+ end
37
+ end
38
+
39
+ describe "#from_code_for_locale" do
40
+ it "should return the language in the correct locale for the given locale code (i.e. es in English should be Spanish)" do
41
+ Languages.from_code_for_locale(:es, :en).should == "Spanish"
42
+ Languages.from_code_for_locale(:en, :es).should == "inglés"
43
+ end
44
+ end
45
+
46
+ describe "#from_code" do
47
+ it "should return the language in the default locale for the given locale code" do
48
+ Languages.from_code(:es).should == "Spanish"
49
+ Languages.from_code(:ru).should == "Russian"
50
+ FastGettext.locale = :es
51
+ Languages.from_code(:es).should == "español"
52
+ end
53
+ end
54
+
55
+ describe "#all_for" do
56
+ it "should return a hash of all languages for the given language code" do
57
+ langs = Languages.all_for(:es)
58
+ langs.should be_a(Hash)
59
+ langs[:ru].should == "ruso"
60
+ end
61
+
62
+ it "should return an empty hash for an invalid language" do
63
+ langs = Languages.all_for(:blarg)
64
+ langs.should == {}
65
+ end
66
+ end
67
+
68
+ describe "#all" do
69
+ it "should use the default language to get the language hash" do
70
+ langs = Languages.all
71
+ langs.should be_a(Hash)
72
+ langs[:ru].should == "Russian"
73
+ langs[:de].should == "German"
74
+
75
+ FastGettext.locale = :es
76
+ langs = Languages.all
77
+ langs.should be_a(Hash)
78
+ langs[:ru].should == "ruso"
79
+ langs[:de].should == "alemán"
80
+ end
81
+ end
82
+ end
@@ -0,0 +1,44 @@
1
+ require File.join(File.dirname(__FILE__), %w[.. spec_helper])
2
+ include TwitterCldr::Shared
3
+
4
+ describe Resources do
5
+ before(:each) do
6
+ @resource = Resources.new
7
+ end
8
+
9
+ describe "#resource_for" do
10
+ it "loads the requested resource from disk only once" do
11
+ # note that it should convert the string "de" into a symbol
12
+ mock(@resource).data_for(:de, "racehorse").once { "german racehorse resource" }
13
+
14
+ # do it twice - the second one shouldn't call data_for
15
+ @resource.resource_for("de", "racehorse").should == "german racehorse resource"
16
+ @resource.resource_for("de", "racehorse").should == "german racehorse resource"
17
+ end
18
+ end
19
+
20
+ describe "#data_for" do
21
+ it "loads the correct file for the given locale and resource" do
22
+ mock(YAML).load("data") { { "key" => "value" } }
23
+ mock(File).read(File.join(File.dirname(File.dirname(File.dirname(File.expand_path(__FILE__)))), "resources", "de", "racehorse.yml")) { "data" }
24
+ @resource.resource_for("de", "racehorse").should == { :key => "value" }
25
+ end
26
+ end
27
+
28
+ describe "#deep_symbolize_keys" do
29
+ it "should work with a regular hash" do
30
+ result = @resource.send(:deep_symbolize_keys, { "twitter" => "rocks", "my" => "socks" })
31
+ result.should == { :twitter => "rocks", :my => "socks"}
32
+ end
33
+
34
+ it "should work with nested hashes" do
35
+ result = @resource.send(:deep_symbolize_keys, { "twitter" => { "rocks" => "my socks" } })
36
+ result.should == { :twitter => { :rocks => "my socks" } }
37
+ end
38
+
39
+ it "should work with nested hashes and arrays" do
40
+ result = @resource.send(:deep_symbolize_keys, { "twitter" => { "rocks_my" => [{ "socks" => "and mind" }, { "hard" => "core" }] } })
41
+ result.should == { :twitter => { :rocks_my => [{ :socks => "and mind" }, { :hard => "core" }] } }
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,31 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), %w[.. lib twitter_cldr]))
2
+ FIXTURE_DIR = File.expand_path(File.join(File.dirname(__FILE__), %w[fixtures]))
3
+
4
+ class FastGettext
5
+ class << self
6
+ def locale
7
+ @@locale || :en
8
+ end
9
+
10
+ def locale=(value)
11
+ @@locale = value
12
+ end
13
+ end
14
+ end
15
+
16
+ Spec::Runner.configure do |config|
17
+ config.mock_with :rr
18
+
19
+ config.before(:each) do
20
+ FastGettext.locale = :en
21
+ end
22
+ end
23
+
24
+ def check_token_list(got, expected)
25
+ got.size.should == expected.size
26
+ expected.each_with_index do |exp_hash, index|
27
+ exp_hash.each_pair do |exp_key, exp_val|
28
+ got[index].send(exp_key).should == exp_val
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,134 @@
1
+ require File.join(File.dirname(File.dirname(__FILE__)), "spec_helper")
2
+ include TwitterCldr::Tokenizers
3
+
4
+ # normally, base can't be instantiated, so we have to patch it here
5
+ module TwitterCldr
6
+ module Tokenizers
7
+ class Base
8
+ def init_resources; end
9
+ end
10
+ end
11
+ end
12
+
13
+ describe Base do
14
+ before(:each) do
15
+ @base = Base.new # do NOT do this in production - must use subclass
16
+ end
17
+
18
+ it "creating a new base without a locale should default to English, with a locale should not" do
19
+ @base.locale.should == :en
20
+ Base.new(:locale => :de).locale.should == :de
21
+ end
22
+
23
+ # tokenize_pattern is supposed to take a pattern found in the YAML resource files and break it into placeholders and plaintext.
24
+ # Placeholders are delimited by single and double curly braces, plaintext is everything else.
25
+ describe "#tokenize_pattern" do
26
+ context "with double curlies (path names, essentially)" do
27
+ it "should work with a placeholder only" do
28
+ @base.send(:tokenize_pattern, "{{place}}").should == [{ :value => "{{place}}", :type => :placeholder }]
29
+ end
30
+
31
+ it "should work with two placeholders separated by a space" do
32
+ @base.send(:tokenize_pattern, "{{first}} {{second}}").should == [{ :value => "{{first}}", :type => :placeholder },
33
+ { :value => " ", :type => :plaintext },
34
+ { :value => "{{second}}", :type => :placeholder }]
35
+ end
36
+
37
+ it "should work when surrounded by plaintext" do
38
+ @base.send(:tokenize_pattern, "being {{totally}} awesome").should == [{ :value => "being ", :type => :plaintext },
39
+ { :value => "{{totally}}", :type => :placeholder },
40
+ { :value => " awesome", :type => :plaintext }]
41
+ end
42
+ end
43
+
44
+ context "with single curlies (indexes)" do
45
+ it "should work with a placeholder only" do
46
+ @base.send(:tokenize_pattern, "{1}").should == [{ :value => "{1}", :type => :placeholder }]
47
+ end
48
+
49
+ it "should work with two placeholders separated by a space" do
50
+ @base.send(:tokenize_pattern, "{0} {1}").should == [{ :value => "{0}", :type => :placeholder },
51
+ { :value => " ", :type => :plaintext },
52
+ { :value => "{1}", :type => :placeholder }]
53
+ end
54
+
55
+ it "should work when surrounded by plaintext" do
56
+ @base.send(:tokenize_pattern, "only {1} dragon").should == [{ :value => "only ", :type => :plaintext },
57
+ { :value => "{1}", :type => :placeholder },
58
+ { :value => " dragon", :type => :plaintext }]
59
+ end
60
+ end
61
+ end
62
+
63
+ describe "#choose_placeholder" do
64
+ before(:each) do
65
+ @placeholders = [{ :name => "wallace", :object => "man" }, { :name => "gromit", :object => "dog" }]
66
+ end
67
+
68
+ it "should choose the correct named placeholder" do
69
+ @base.send(:choose_placeholder, "{{wallace}}", @placeholders).should == "man"
70
+ @base.send(:choose_placeholder, "{{gromit}}", @placeholders).should == "dog"
71
+ end
72
+
73
+ it "should choose the correct placeholder by array index" do
74
+ @base.send(:choose_placeholder, "{0}", @placeholders).should == "man"
75
+ @base.send(:choose_placeholder, "{1}", @placeholders).should == "dog"
76
+ end
77
+ end
78
+
79
+ describe "#expand_pattern" do
80
+ it "recursively calls expand_pattern if a symbol (keypath) is given" do
81
+ mock(@base).traverse(:'another.path') { "found_me" }
82
+ mock(@base).pattern_for("found_me") { "pattern_text" }
83
+ mock.proxy(@base).expand_pattern("pattern_text", :fake_type)
84
+ mock.proxy(@base).expand_pattern(:'another.path', :fake_type)
85
+ @base.send(:expand_pattern, :'another.path', :fake_type).should == [{ :value => "pattern_text", :type => :plaintext }]
86
+ end
87
+
88
+ it "expands placeholders as necessary" do
89
+ placeholder_obj = Object.new
90
+ mock(placeholder_obj).tokens(:type => :man) { ["token1", "token2"] }
91
+ @base.placeholders = [{ :name => "wallace", :object => placeholder_obj }]
92
+ @base.send(:expand_pattern, "{{wallace}} rules", :man).should == ["token1", "token2", { :type => :plaintext, :value => " rules" }]
93
+ end
94
+
95
+ it "doesn't choke if the placeholder can't be found" do
96
+ @base.placeholders = [{ :name => "gromit", :object => "dog" }]
97
+ @base.send(:expand_pattern, "{{wallace}} rules", :man).should == [{ :type => :plaintext, :value => " rules" }]
98
+ end
99
+ end
100
+
101
+ describe "#traverse" do
102
+ before(:each) do
103
+ @tree = { :admiral => { :captain => { :commander => { :lieutenant => "Found Me!" } } } }
104
+ end
105
+
106
+ it "should find the correct value in the hash" do
107
+ @base.send(:traverse, :'admiral.captain.commander.lieutenant', @tree).should == "Found Me!"
108
+ end
109
+
110
+ it "shouldn't choke if the path doesn't exist" do
111
+ @base.send(:traverse, :'admiral.captain.commander.lieutenant.ensign', @tree).should == nil
112
+ end
113
+ end
114
+
115
+ # Not to be confused with tokenize_pattern, which pulls out placeholders. Tokenize_format actually splits a completely
116
+ # expanded format string into whatever parts are defined by the subclass's token type and token splitter regexes.
117
+ describe "#tokenize_format" do
118
+ it "assigns the right token types to the tokens" do
119
+ stub(@base).token_splitter_regex { /([abc])/ }
120
+ stub(@base).token_type_regexes { [{ :type => :a, :regex => /a/ },
121
+ { :type => :b, :regex => /b/ },
122
+ { :type => :c, :regex => /c/ },
123
+ { :type => :plaintext, :regex => // }] }
124
+ tokens = @base.send(:tokenize_format, "a b c")
125
+ tokens.size.should == 5
126
+
127
+ tokens[0].value.should == "a"; tokens[0].type.should == :a
128
+ tokens[1].value.should == " "; tokens[1].type.should == :plaintext
129
+ tokens[2].value.should == "b"; tokens[2].type.should == :b
130
+ tokens[3].value.should == " "; tokens[3].type.should == :plaintext
131
+ tokens[4].value.should == "c"; tokens[4].type.should == :c
132
+ end
133
+ end
134
+ end
@@ -0,0 +1,36 @@
1
+ require File.join(File.dirname(File.dirname(File.dirname(__FILE__))), "spec_helper")
2
+ include TwitterCldr::Tokenizers
3
+
4
+ describe DateTokenizer do
5
+ describe "#tokens" do
6
+ it "should tokenize plaintext segments correctly (i.e. Spanish)" do
7
+ tokenizer = DateTokenizer.new(:locale => :es)
8
+ got = tokenizer.tokens(:type => :full)
9
+ expected = [{ :value => "EEEE", :type => :pattern },
10
+ { :value => " ", :type => :plaintext },
11
+ { :value => "d", :type => :pattern },
12
+ { :value => " ", :type => :plaintext },
13
+ { :value => "'de'", :type => :plaintext },
14
+ { :value => " ", :type => :plaintext },
15
+ { :value => "MMMM", :type => :pattern },
16
+ { :value => " ", :type => :plaintext },
17
+ { :value => "'de'", :type => :plaintext },
18
+ { :value => " ", :type => :plaintext },
19
+ { :value => "y", :type => :pattern }]
20
+ check_token_list(got, expected)
21
+ end
22
+
23
+ it "should tokenize patterns with non-latin characters correctly (i.e. Japanese)" do
24
+ tokenizer = DateTokenizer.new(:locale => :ja)
25
+ got = tokenizer.tokens(:type => :full)
26
+ expected = [{ :value => "y", :type => :pattern },
27
+ { :value => "年", :type => :plaintext },
28
+ { :value => "M", :type => :pattern },
29
+ { :value => "月", :type => :plaintext },
30
+ { :value => "d", :type => :pattern },
31
+ { :value => "日", :type => :plaintext },
32
+ { :value => "EEEE", :type => :pattern }]
33
+ check_token_list(got, expected)
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,52 @@
1
+ require File.join(File.dirname(File.dirname(File.dirname(__FILE__))), "spec_helper")
2
+ include TwitterCldr::Tokenizers
3
+
4
+ describe DateTimeTokenizer do
5
+ describe "#initialize" do
6
+ it "chooses gregorian as the calendar type if none is specified" do
7
+ DateTimeTokenizer.new.calendar_type.should == :gregorian
8
+ DateTimeTokenizer.new(:calendar_type => :julian).calendar_type.should == :julian
9
+ end
10
+
11
+ it "initializes individual date and time placeholder tokenizers" do
12
+ placeholders = DateTimeTokenizer.new.placeholders
13
+ placeholders[0][:name].should == :date
14
+ placeholders[0][:object].should be_a(DateTokenizer)
15
+ placeholders[1][:name].should == :time
16
+ placeholders[1][:object].should be_a(TimeTokenizer)
17
+ end
18
+ end
19
+
20
+ describe "#tokens" do
21
+ it "should choose the default date time path if no other type is specified" do
22
+ tokenizer = DateTimeTokenizer.new
23
+ mock.proxy(tokenizer.paths)[:default]
24
+ tokenizer.tokens
25
+ end
26
+
27
+ it "should expand date and time placeholders and return the correct list of tokens" do
28
+ tokenizer = DateTimeTokenizer.new(:locale => :es)
29
+ got = tokenizer.tokens(:type => :full)
30
+ expected = [{ :value => "HH", :type => :pattern },
31
+ { :value => ":", :type => :plaintext },
32
+ { :value => "mm", :type => :pattern },
33
+ { :value => ":", :type => :plaintext },
34
+ { :value => "ss", :type => :pattern },
35
+ { :value => " ", :type => :plaintext },
36
+ { :value => "zzzz", :type => :pattern },
37
+ { :value => " ", :type => :plaintext },
38
+ { :value => "EEEE", :type => :pattern },
39
+ { :value => " ", :type => :plaintext },
40
+ { :value => "d", :type => :pattern },
41
+ { :value => " ", :type => :plaintext },
42
+ { :value => "'de'", :type => :plaintext },
43
+ { :value => " ", :type => :plaintext },
44
+ { :value => "MMMM", :type => :pattern },
45
+ { :value => " ", :type => :plaintext },
46
+ { :value => "'de'", :type => :plaintext },
47
+ { :value => " ", :type => :plaintext },
48
+ { :value => "y", :type => :pattern }]
49
+ check_token_list(got, expected)
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,34 @@
1
+ require File.join(File.dirname(File.dirname(File.dirname(__FILE__))), "spec_helper")
2
+ include TwitterCldr::Tokenizers
3
+
4
+ describe DateTokenizer do
5
+ describe "#tokens" do
6
+ it "should tokenize a time string correctly (i.e. German)" do
7
+ tokenizer = TimeTokenizer.new(:locale => :de)
8
+ got = tokenizer.tokens(:type => :full)
9
+ expected = [{ :value => "HH", :type => :pattern },
10
+ { :value => ":", :type => :plaintext },
11
+ { :value => "mm", :type => :pattern },
12
+ { :value => ":", :type => :plaintext },
13
+ { :value => "ss", :type => :pattern },
14
+ { :value => " ", :type => :plaintext },
15
+ { :value => "zzzz", :type => :pattern }]
16
+ check_token_list(got, expected)
17
+ end
18
+
19
+ it "should tokenize patterns with non-latin characters correctly (i.e. Korean)" do
20
+ tokenizer = TimeTokenizer.new(:locale => :ko)
21
+ got = tokenizer.tokens(:type => :full)
22
+ expected = [{ :value => "a", :type => :pattern },
23
+ { :value => " ", :type => :plaintext },
24
+ { :value => "hh", :type => :pattern },
25
+ { :value => "시 ", :type => :plaintext },
26
+ { :value => "mm", :type => :pattern },
27
+ { :value => "분 ", :type => :plaintext },
28
+ { :value => "ss", :type => :pattern },
29
+ { :value => "초 ", :type => :plaintext },
30
+ { :value => "zzzz", :type => :pattern }]
31
+ check_token_list(got, expected)
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,44 @@
1
+ require File.join(File.dirname(File.dirname(__FILE__)), "spec_helper")
2
+ include TwitterCldr::Tokenizers
3
+
4
+ describe KeyPath do
5
+ describe "#dirname" do
6
+ it "should strip off the last element" do
7
+ KeyPath.dirname("castle.in.the.sky").should == "castle.in.the"
8
+ end
9
+
10
+ it "shouldn't choke if given an empty string" do
11
+ KeyPath.dirname("").should == ""
12
+ end
13
+ end
14
+
15
+ describe "#join" do
16
+ it "joins two args with two dots" do
17
+ KeyPath.join("seahawks.", ".rule").should == "seahawks.rule"
18
+ end
19
+
20
+ it "joins two args with one dot at the end of the first" do
21
+ KeyPath.join("seahawks.", "rule").should == "seahawks.rule"
22
+ end
23
+
24
+ it "joins two args with one dot at the beginning of the second" do
25
+ KeyPath.join("seahawks", ".rule").should == "seahawks.rule"
26
+ end
27
+
28
+ it "joins two args with no dots" do
29
+ KeyPath.join("seahawks", "rule").should == "seahawks.rule"
30
+ end
31
+ end
32
+
33
+ describe "#split_path" do
34
+ it "should split the path by dots" do
35
+ KeyPath.split_path("rain.in.spain").should == ["rain", "in", "spain"]
36
+ end
37
+ end
38
+
39
+ describe "#join_path" do
40
+ it "should join the path with dots" do
41
+ KeyPath.join_path(["rain", "in", "spain"]).should == "rain.in.spain"
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,60 @@
1
+ require File.join(File.dirname(File.dirname(File.dirname(__FILE__))), "spec_helper")
2
+ include TwitterCldr::Tokenizers
3
+
4
+ describe NumberTokenizer do
5
+ describe "#initialize" do
6
+ it "chooses decimal as the default type if no other type is specified" do
7
+ NumberTokenizer.new.type.should == :decimal
8
+ NumberTokenizer.new(:type => :percent).type.should == :percent
9
+ end
10
+ end
11
+
12
+ describe "#full_path_for" do
13
+ it "should fill in the type and return the full path to the requested format" do
14
+ NumberTokenizer.new.send(:full_path_for, :default).should == "numbers.formats.decimal.patterns.default"
15
+ end
16
+ end
17
+
18
+ describe "#tokens" do
19
+ it "ensures that positive and negative entries are created (as necessary)" do
20
+ tokenizer = NumberTokenizer.new(:locale => :tr)
21
+ tokenizer.tokens
22
+ root = tokenizer.resource[:numbers][:formats][:decimal][:patterns]
23
+ root.should include(:positive)
24
+ root.should include(:negative)
25
+ end
26
+
27
+ it "gets tokens for a latin language (i.e. Portuguese)" do
28
+ tokenizer = NumberTokenizer.new(:locale => :pt)
29
+ got = tokenizer.tokens
30
+ expected = [{ :value => "", :type => :pattern },
31
+ { :value => "#,##0.###", :type => :pattern }]
32
+ check_token_list(got, expected)
33
+ end
34
+
35
+ it "gets tokens for a non-latin language (i.e. Russian)" do
36
+ tokenizer = NumberTokenizer.new(:locale => :ru)
37
+ got = tokenizer.tokens
38
+ expected = [{ :value => "", :type => :pattern },
39
+ { :value => "#,##0.###", :type => :pattern }]
40
+ check_token_list(got, expected)
41
+ end
42
+
43
+ it "correctly parses suffixes (i.e. Russian currency)" do
44
+ tokenizer = NumberTokenizer.new(:locale => :ru, :type => :currency)
45
+ got = tokenizer.tokens
46
+ expected = [{ :value => "", :type => :pattern },
47
+ { :value => "#,##0.00", :type => :pattern },
48
+ { :value => " ¤", :type => :pattern }]
49
+ check_token_list(got, expected)
50
+ end
51
+
52
+ it "correctly parses prefixes (i.e. Italian currency)" do
53
+ tokenizer = NumberTokenizer.new(:locale => :it, :type => :currency)
54
+ got = tokenizer.tokens
55
+ expected = [{ :value => "¤ ", :type => :pattern },
56
+ { :value => "#,##0.00", :type => :pattern }]
57
+ check_token_list(got, expected)
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,18 @@
1
+ require File.join(File.dirname(File.dirname(__FILE__)), "spec_helper")
2
+ include TwitterCldr::Tokenizers
3
+
4
+ describe Token do
5
+ describe "#initialize" do
6
+ it "should set instance variables passed in the options hash" do
7
+ token = Token.new(:type => "my_type", :value => "my_value")
8
+ token.type.should == "my_type"
9
+ token.value.should == "my_value"
10
+ end
11
+ end
12
+
13
+ describe "#to_s" do
14
+ it "should return the token's value" do
15
+ Token.new(:value => "my_value").to_s.should == "my_value"
16
+ end
17
+ end
18
+ end