Permalink
Browse files

Short/long decimals working, tests written

  • Loading branch information...
1 parent 1c1f8eb commit 1b76e0a3782015d9cf6ba974bfbc7277f69d7d06 Cameron Dutro committed Nov 13, 2012
View
27 lib/twitter_cldr/formatters.rb
@@ -7,20 +7,23 @@ module TwitterCldr
module Formatters
autoload :Base, 'twitter_cldr/formatters/base'
- autoload :DateTimeFormatter, 'twitter_cldr/formatters/calendars/datetime_formatter'
- autoload :DateFormatter, 'twitter_cldr/formatters/calendars/date_formatter'
- autoload :TimeFormatter, 'twitter_cldr/formatters/calendars/time_formatter'
- autoload :TimespanFormatter, 'twitter_cldr/formatters/calendars/timespan_formatter'
+ autoload :DateTimeFormatter, 'twitter_cldr/formatters/calendars/datetime_formatter'
+ autoload :DateFormatter, 'twitter_cldr/formatters/calendars/date_formatter'
+ autoload :TimeFormatter, 'twitter_cldr/formatters/calendars/time_formatter'
+ autoload :TimespanFormatter, 'twitter_cldr/formatters/calendars/timespan_formatter'
- autoload :Numbers, 'twitter_cldr/formatters/numbers'
- autoload :NumberFormatter, 'twitter_cldr/formatters/numbers/number_formatter'
- autoload :DecimalFormatter, 'twitter_cldr/formatters/numbers/decimal_formatter'
- autoload :CurrencyFormatter, 'twitter_cldr/formatters/numbers/currency_formatter'
- autoload :PercentFormatter, 'twitter_cldr/formatters/numbers/percent_formatter'
+ autoload :Numbers, 'twitter_cldr/formatters/numbers'
+ autoload :NumberFormatter, 'twitter_cldr/formatters/numbers/number_formatter'
+ autoload :AbbreviatedNumberFormatter, 'twitter_cldr/formatters/numbers/abbreviated/abbreviated_number_formatter'
+ autoload :DecimalFormatter, 'twitter_cldr/formatters/numbers/decimal_formatter'
+ autoload :ShortDecimalFormatter, 'twitter_cldr/formatters/numbers/abbreviated/short_decimal_formatter'
+ autoload :LongDecimalFormatter, 'twitter_cldr/formatters/numbers/abbreviated/long_decimal_formatter'
+ autoload :CurrencyFormatter, 'twitter_cldr/formatters/numbers/currency_formatter'
+ autoload :PercentFormatter, 'twitter_cldr/formatters/numbers/percent_formatter'
- autoload :Plurals, 'twitter_cldr/formatters/plurals'
- autoload :PluralFormatter, 'twitter_cldr/formatters/plurals/plural_formatter'
+ autoload :Plurals, 'twitter_cldr/formatters/plurals'
+ autoload :PluralFormatter, 'twitter_cldr/formatters/plurals/plural_formatter'
- autoload :ListFormatter, 'twitter_cldr/formatters/list_formatter'
+ autoload :ListFormatter, 'twitter_cldr/formatters/list_formatter'
end
end
View
47 lib/twitter_cldr/formatters/numbers/abbreviated/abbreviated_number_formatter.rb
@@ -0,0 +1,47 @@
+# encoding: UTF-8
+
+# Copyright 2012 Twitter, Inc
+# http://www.apache.org/licenses/LICENSE-2.0
+
+module TwitterCldr
+ module Formatters
+ class AbbreviatedNumberFormatter < NumberFormatter
+ NUMBER_MAX = (10 ** 15)
+ NUMBER_MIN = 1000
+
+ def default_format_options_for(number)
+ { :precision => 0 }
+ end
+
+ def get_tokens(obj, options = {})
+ type = (obj < NUMBER_MAX) && (obj >= NUMBER_MIN) ? get_type : :decimal
+ format = type == get_type ? get_key(obj) : nil
+ opts = options.merge(
+ :sign => obj.abs == obj ? :positive : :negative,
+ :type => type,
+ :format => format
+ )
+ @tokenizer.tokens(opts)
+ end
+
+ protected
+
+ def get_type
+ :decimal
+ end
+
+ def get_key(number)
+ "1#{"0" * (number.to_i.to_s.size - 1)}".to_i
+ end
+
+ def transform_number(number)
+ if (number < NUMBER_MAX) && (number >= NUMBER_MIN)
+ sig_figs = ((number.to_i.to_s.size - 1) % 3)
+ number.to_s[0..sig_figs].to_i
+ else
+ number
+ end
+ end
+ end
+ end
+end
View
18 lib/twitter_cldr/formatters/numbers/abbreviated/long_decimal_formatter.rb
@@ -0,0 +1,18 @@
+# encoding: UTF-8
+
+# Copyright 2012 Twitter, Inc
+# http://www.apache.org/licenses/LICENSE-2.0
+
+module TwitterCldr
+ module Formatters
+ class LongDecimalFormatter < AbbreviatedNumberFormatter
+
+ protected
+
+ def get_type
+ :long_decimal
+ end
+
+ end
+ end
+end
View
18 lib/twitter_cldr/formatters/numbers/abbreviated/short_decimal_formatter.rb
@@ -0,0 +1,18 @@
+# encoding: UTF-8
+
+# Copyright 2012 Twitter, Inc
+# http://www.apache.org/licenses/LICENSE-2.0
+
+module TwitterCldr
+ module Formatters
+ class ShortDecimalFormatter < AbbreviatedNumberFormatter
+
+ protected
+
+ def get_type
+ :short_decimal
+ end
+
+ end
+ end
+end
View
13 lib/twitter_cldr/formatters/numbers/currency_formatter.rb
@@ -9,11 +9,6 @@ class CurrencyFormatter < NumberFormatter
DEFAULT_CURRENCY_SYMBOL = "$"
DEFAULT_PRECISION = 2
- def initialize(options = {})
- @tokenizer = TwitterCldr::Tokenizers::NumberTokenizer.new(:locale => self.extract_locale(options), :type => :currency)
- super
- end
-
def format(number, options = {})
if options[:currency]
currency ||= TwitterCldr::Shared::Currencies.for_code(options[:currency])
@@ -30,6 +25,14 @@ def default_format_options_for(number)
precision = precision_from(number)
{ :precision => precision == 0 ? DEFAULT_PRECISION : precision }
end
+
+ def get_tokens(obj, options = {})
+ opts = options.dup.merge(
+ :sign => obj.abs == obj ? :positive : :negative,
+ :type => :currency
+ )
+ @tokenizer.tokens(opts)
+ end
end
end
end
View
5 lib/twitter_cldr/formatters/numbers/decimal_formatter.rb
@@ -6,11 +6,6 @@
module TwitterCldr
module Formatters
class DecimalFormatter < NumberFormatter
- def initialize(options = {})
- @tokenizer = TwitterCldr::Tokenizers::NumberTokenizer.new(:locale => self.extract_locale(options), :type => :decimal)
- super
- end
-
def format(number, options = {})
super(number, options)
rescue TypeError, ArgumentError
View
2 lib/twitter_cldr/formatters/numbers/helpers/base.rb
@@ -10,7 +10,7 @@ class Base
def interpolate(string, value, orientation = :right)
value = value.to_s
length = value.length
- start = orientation == :left ? 0 : -length
+ start = orientation == :left ? 0 : -length
string = string.dup
string = string.ljust(length, '#') if string.length < length
View
15 lib/twitter_cldr/formatters/numbers/number_formatter.rb
@@ -11,13 +11,15 @@ class NumberFormatter < Base
DEFAULT_SYMBOLS = { :group => ',', :decimal => '.', :plus_sign => '+', :minus_sign => '-' }
def initialize(options = {})
+ @tokenizer = TwitterCldr::Tokenizers::NumberTokenizer.new(:locale => extract_locale(options))
@symbols = DEFAULT_SYMBOLS.merge(tokenizer.symbols)
end
def format(number, options = {})
opts = self.default_format_options_for(number).merge(options)
- prefix, suffix, integer_format, fraction_format = *partition_tokens(self.get_tokens(number, opts))
-
+ prefix, suffix, integer_format, fraction_format = *partition_tokens(get_tokens(number, opts))
+ number = transform_number(number)
+
int, fraction = parse_number(number, opts)
result = integer_format.apply(int, opts)
result << fraction_format.apply(fraction, opts) if fraction
@@ -26,6 +28,10 @@ def format(number, options = {})
protected
+ def transform_number(number)
+ number # noop for base class
+ end
+
def partition_tokens(tokens)
[tokens[0] || "",
tokens[2] || "",
@@ -34,7 +40,7 @@ def partition_tokens(tokens)
end
def parse_number(number, options = {})
- precision = options[:precision] || self.precision_from(number)
+ precision = options[:precision] || precision_from(number)
number = "%.#{precision}f" % round_to(number, precision).abs
number.split(".")
end
@@ -50,7 +56,8 @@ def precision_from(num)
end
def get_tokens(obj, options = {})
- obj.abs == obj ? @tokenizer.tokens(:sign => :positive) : @tokenizer.tokens(:sign => :negative)
+ opts = options.dup.merge(:sign => obj.abs == obj ? :positive : :negative)
+ @tokenizer.tokens(opts)
end
end
end
View
13 lib/twitter_cldr/formatters/numbers/percent_formatter.rb
@@ -8,18 +8,21 @@ module Formatters
class PercentFormatter < NumberFormatter
DEFAULT_PERCENT_SIGN = "%"
- def initialize(options = {})
- @tokenizer = TwitterCldr::Tokenizers::NumberTokenizer.new(:locale => self.extract_locale(options), :type => :percent)
- super
- end
-
def format(number, options = {})
super(number, options).gsub('¤', @tokenizer.symbols[:percent_sign] || DEFAULT_PERCENT_SIGN)
end
def default_format_options_for(number)
{ :precision => 0 }
end
+
+ def get_tokens(obj, options = {})
+ opts = options.dup.merge(
+ :sign => obj.abs == obj ? :positive : :negative,
+ :type => :percent
+ )
+ @tokenizer.tokens(opts)
+ end
end
end
end
View
12 lib/twitter_cldr/localized/localized_number.rb
@@ -7,8 +7,14 @@ module TwitterCldr
module Localized
class LocalizedNumber < LocalizedObject
- TYPES = [:decimal, :currency, :percent]
DEFAULT_TYPE = :decimal
+ TYPES = [
+ :decimal,
+ :short_decimal,
+ :long_decimal,
+ :currency,
+ :percent,
+ ]
attr_reader :type
@@ -28,7 +34,7 @@ def initialize(obj, locale, options = {})
end
def to_s(options = {})
- @formatter.format(@base_obj, options)
+ @formatter.format(@base_obj, options.merge(:type => @type))
end
def plural_rule
@@ -38,7 +44,7 @@ def plural_rule
protected
def formatter_const
- TwitterCldr::Formatters.const_get("#{@type.to_s.capitalize}Formatter")
+ TwitterCldr::Formatters.const_get("#{@type.to_s.split("_").map(&:capitalize).join}Formatter")
end
def to_type(target_type)
View
18 lib/twitter_cldr/tokenizers/base.rb
@@ -7,8 +7,8 @@ module TwitterCldr
module Tokenizers
class Base
attr_reader :resource, :locale
- attr_reader :token_splitter_regexes, :token_type_regexes, :paths, :format
- attr_accessor :type, :placeholders
+ attr_reader :token_splitter_regexes, :token_type_regexes, :paths
+ attr_accessor :type, :format, :placeholders
def initialize(options = {})
@locale = TwitterCldr.convert_locale(options[:locale] || TwitterCldr::DEFAULT_LOCALE)
@@ -49,13 +49,17 @@ def token_splitter_regex_for(type)
token_splitter_regexes[type] || token_splitter_regexes[:else]
end
- def tokens_for(path, type)
+ def tokens_for(path, additional_cache_key_params = [])
+ tokens_for_pattern(pattern_for(traverse(path)), path, additional_cache_key_params)
+ end
+
+ def tokens_for_pattern(pattern, path, additional_cache_key_params = [])
@@token_cache ||= {}
- cache_key = TwitterCldr::Utils.compute_cache_key(@locale, path.join('.'), type, format || "nil")
+ cache_key = TwitterCldr::Utils.compute_cache_key(@locale, path.join('.'), type, format || "nil", *additional_cache_key_params)
unless @@token_cache.include?(cache_key)
result = []
- tokens = expand_pattern(pattern_for(traverse(path)), type)
+ tokens = expand_pattern(pattern)
tokens.each do |token|
if token.is_a?(Token) || token.is_a?(CompositeToken)
@@ -116,10 +120,10 @@ def expand(current, haystack)
end
end
- def expand_pattern(format_str, type)
+ def expand_pattern(format_str)
if format_str.is_a?(Symbol)
# symbols mean another path was given
- expand_pattern(pattern_for(traverse(format_str.to_s.split('.').map(&:to_sym))), type)
+ expand_pattern(pattern_for(traverse(format_str.to_s.split('.').map(&:to_sym))))
else
parts = tokenize_pattern(format_str)
final = []
View
8 lib/twitter_cldr/tokenizers/calendars/datetime_tokenizer.rb
@@ -12,6 +12,8 @@ class DateTimeTokenizer < Base
def initialize(options = {})
@calendar_type = options[:calendar_type] || TwitterCldr::DEFAULT_CALENDAR_TYPE
+ @type = options[:type] || :default
+ @format = options[:format]
@token_splitter_regexes = {
:additional => Regexp.union(
@@ -43,9 +45,9 @@ def initialize(options = {})
end
def tokens(options = {})
- @type = options[:type] || :default
- @format = options[:format]
- tokens_for(full_path_for(paths[@type]), @type)
+ @type = options[:type] || @type || :default
+ @format = options[:format] || @format
+ tokens_for(full_path_for(paths[@type]))
end
def calendar
View
45 lib/twitter_cldr/tokenizers/numbers/number_tokenizer.rb
@@ -6,7 +6,7 @@
module TwitterCldr
module Tokenizers
class NumberTokenizer < Base
- VALID_TYPES = [:decimal, :percent, :currency]
+ VALID_TYPES = [:decimal, :percent, :currency, :short_decimal, :long_decimal]
TOKEN_SPLITTER_REGEX = /([^0*#,\.]*)([0#,\.]+)([^0*#,\.]*)$/
TOKEN_TYPE_REGEXES = {
:pattern => { :regex => /[0?#,\.]*/, :priority => 1 },
@@ -16,8 +16,6 @@ class NumberTokenizer < Base
def initialize(options = {})
super(options)
- @type = options[:type] || :decimal
-
@token_splitter_regexes = {
:else => TOKEN_SPLITTER_REGEX
}
@@ -30,40 +28,45 @@ def initialize(options = {})
@symbol_path = [:numbers, :symbols]
@paths = {
- :default => [:patterns, :default],
- :positive => [:patterns, :positive],
- :negative => [:patterns, :negative]
+ :default => [:decimal, :patterns],
+ :decimal => [:decimal, :patterns],
+ :long_decimal => [:decimal, :patterns, :long],
+ :short_decimal => [:decimal, :patterns, :short],
+ :currency => [:currency, :patterns],
+ :percent => [:percent, :patterns]
}
end
def tokens(options = {})
- unless traverse(full_path_for(:positive))
- key_path = full_path_for(:default)
-
- positive, negative = traverse(key_path).split(/;/)
+ @type = options[:type] || @type || :default
+ @format = options[:format] || @format || :default
- insert_point = traverse(key_path[0..-2])
- insert_point[:positive] = positive
+ path = full_path
+ positive, negative = traverse(path).split(/;/)
+ sign = options[:sign] || :positive
- if negative
- insert_point[:negative] = "#{symbols[:minus] || '-'}#{negative}"
+ pattern = case sign
+ when :negative
+ if negative
+ "#{symbols[:minus] || '-'}#{negative}"
+ else
+ "#{symbols[:minus] || '-'}#{positive}"
+ end
else
- insert_point[:negative] = "#{symbols[:minus] || '-'}#{positive}"
- end
+ positive
end
- sign = options[:sign] || :positive
- tokens_for(full_path_for(sign), nil)
+ tokens_for_pattern(pattern, path, [sign])
end
def symbols
- self.traverse(@symbol_path)
+ traverse(@symbol_path)
end
protected
- def full_path_for(path)
- @base_path + [@type] + paths[path]
+ def full_path
+ @base_path + paths[@type] + [@format]
end
def init_resources
View
83 spec/formatters/numbers/abbreviated/abbreviated_number_formatter_spec.rb
@@ -0,0 +1,83 @@
+# encoding: UTF-8
+
+# Copyright 2012 Twitter, Inc
+# http://www.apache.org/licenses/LICENSE-2.0
+
+require 'spec_helper'
+require 'pry'
+require 'pry-nav'
+
+include TwitterCldr::Formatters
+
+describe AbbreviatedNumberFormatter do
+ before(:each) do
+ @formatter = AbbreviatedNumberFormatter.new(:locale => :en)
+ end
+
+ describe "#transform_number" do
+ it "chops off the number to the necessary number of sig figs" do
+ @formatter.send(:transform_number, 10 ** 3).should == 1
+ @formatter.send(:transform_number, 10 ** 4).should == 10
+ @formatter.send(:transform_number, 10 ** 5).should == 100
+ @formatter.send(:transform_number, 10 ** 6).should == 1
+ @formatter.send(:transform_number, 10 ** 7).should == 10
+ @formatter.send(:transform_number, 10 ** 8).should == 100
+ @formatter.send(:transform_number, 10 ** 9).should == 1
+ @formatter.send(:transform_number, 10 ** 10).should == 10
+ @formatter.send(:transform_number, 10 ** 11).should == 100
+ @formatter.send(:transform_number, 10 ** 12).should == 1
+ @formatter.send(:transform_number, 10 ** 13).should == 10
+ @formatter.send(:transform_number, 10 ** 14).should == 100
+ end
+
+ it "returns the original number if greater than 10^15" do
+ @formatter.send(:transform_number, 10 ** 15).should == 10 ** 15
+ end
+
+ it "returns the original number if less than 10^3" do
+ @formatter.send(:transform_number, 999).should == 999
+ end
+ end
+
+ describe "#get_key" do
+ it "builds a power-of-ten key based on the number of digits in the input" do
+ (3..15).each { |i| @formatter.send(:get_key, "1337#{"0" * (i - 3)}").should == 10 ** i }
+ end
+ end
+
+ describe "#get_tokens" do
+ before(:each) do
+ stub(@formatter).get_type { :awesome_type }
+ end
+
+ it "gets tokens for a valid number (between 10^3 and 10^15)" do
+ mock(@formatter.tokenizer).tokens({
+ :sign => :positive,
+ :type => :awesome_type,
+ :format => 10 ** 4
+ }) { "I'm just right!" }
+
+ @formatter.get_tokens(12345).should == "I'm just right!"
+ end
+
+ it "returns tokens for decimals if the number is too large" do
+ mock(@formatter.tokenizer).tokens({
+ :sign => :positive,
+ :type => :decimal,
+ :format => nil
+ }) { "I'm too big!" }
+
+ @formatter.get_tokens(1234567891011122).should == "I'm too big!"
+ end
+
+ it "returns tokens for decimals if the number is too small" do
+ mock(@formatter.tokenizer).tokens({
+ :sign => :positive,
+ :type => :decimal,
+ :format => nil
+ }) { "I'm too small!" }
+
+ @formatter.get_tokens(123).should == "I'm too small!"
+ end
+ end
+end
View
37 spec/formatters/numbers/abbreviated/long_decimal_formatter_spec.rb
@@ -0,0 +1,37 @@
+# encoding: UTF-8
+
+# Copyright 2012 Twitter, Inc
+# http://www.apache.org/licenses/LICENSE-2.0
+
+require 'spec_helper'
+
+include TwitterCldr::Formatters
+
+describe LongDecimalFormatter do
+ before(:each) do
+ @formatter = LongDecimalFormatter.new(:locale => :en)
+ end
+
+ it "formats valid numbers correctly (from 10^3 - 10^15)" do
+ @formatter.format(10 ** 3).should match_normalized("1 thousand")
+ @formatter.format(10 ** 4).should match_normalized("10 thousand")
+ @formatter.format(10 ** 5).should match_normalized("100 thousand")
+ @formatter.format(10 ** 6).should match_normalized("1 million")
+ @formatter.format(10 ** 7).should match_normalized("10 million")
+ @formatter.format(10 ** 8).should match_normalized("100 million")
+ @formatter.format(10 ** 9).should match_normalized("1 billion")
+ @formatter.format(10 ** 10).should match_normalized("10 billion")
+ @formatter.format(10 ** 11).should match_normalized("100 billion")
+ @formatter.format(10 ** 12).should match_normalized("1 trillion")
+ @formatter.format(10 ** 13).should match_normalized("10 trillion")
+ @formatter.format(10 ** 14).should match_normalized("100 trillion")
+ end
+
+ it "formats the number as if it were a straight decimal if it exceeds 10^15" do
+ @formatter.format(10**15).should == "1,000,000,000,000,000"
+ end
+
+ it "formats the number as if it were a straight decimal if it's less than 1000" do
+ @formatter.format(500).should == "500"
+ end
+end
View
37 spec/formatters/numbers/abbreviated/short_decimal_formatter_spec.rb
@@ -0,0 +1,37 @@
+# encoding: UTF-8
+
+# Copyright 2012 Twitter, Inc
+# http://www.apache.org/licenses/LICENSE-2.0
+
+require 'spec_helper'
+
+include TwitterCldr::Formatters
+
+describe ShortDecimalFormatter do
+ before(:each) do
+ @formatter = ShortDecimalFormatter.new(:locale => :en)
+ end
+
+ it "formats valid numbers correctly (from 10^3 - 10^15)" do
+ @formatter.format(10 ** 3).should match_normalized("1K")
+ @formatter.format(10 ** 4).should match_normalized("10K")
+ @formatter.format(10 ** 5).should match_normalized("100K")
+ @formatter.format(10 ** 6).should match_normalized("1M")
+ @formatter.format(10 ** 7).should match_normalized("10M")
+ @formatter.format(10 ** 8).should match_normalized("100M")
+ @formatter.format(10 ** 9).should match_normalized("1B")
+ @formatter.format(10 ** 10).should match_normalized("10B")
+ @formatter.format(10 ** 11).should match_normalized("100B")
+ @formatter.format(10 ** 12).should match_normalized("1T")
+ @formatter.format(10 ** 13).should match_normalized("10T")
+ @formatter.format(10 ** 14).should match_normalized("100T")
+ end
+
+ it "formats the number as if it were a straight decimal if it exceeds 10^15" do
+ @formatter.format(10**15).should == "1,000,000,000,000,000"
+ end
+
+ it "formats the number as if it were a straight decimal if it's less than 1000" do
+ @formatter.format(500).should == "500"
+ end
+end
View
40 spec/localized/localized_number_spec.rb
@@ -71,12 +71,12 @@
let(:number) { LocalizedNumber.new(10, :en) }
it 'should default precision to zero' do
- mock.proxy(number.formatter).format(number.base_obj, {})
+ mock.proxy(number.formatter).format(number.base_obj, { :type => :decimal })
number.to_s.should == "10"
end
it 'should not overwrite precision when explicitly passed' do
- mock.proxy(number.formatter).format(number.base_obj, :precision => 2)
+ mock.proxy(number.formatter).format(number.base_obj, :precision => 2, :type => :decimal)
number.to_s(:precision => 2).should == "10.00"
end
end
@@ -85,12 +85,12 @@
let(:number) { LocalizedNumber.new(10, :en, :type => :currency) }
it "should default to a precision of 2" do
- mock.proxy(number.formatter).format(number.base_obj, :precision => 2)
+ mock.proxy(number.formatter).format(number.base_obj, :precision => 2, :type => :currency)
number.to_s(:precision => 2).should == "$10.00"
end
it 'should not overwrite precision when explicitly passed' do
- mock.proxy(number.formatter).format(number.base_obj, :precision => 1)
+ mock.proxy(number.formatter).format(number.base_obj, :precision => 1, :type => :currency)
number.to_s(:precision => 1).should == "$10.0"
end
end
@@ -99,15 +99,43 @@
let(:number) { LocalizedNumber.new(10, :en, :type => :percent) }
it "should default to a precision of 0" do
- mock.proxy(number.formatter).format(number.base_obj, {})
+ mock.proxy(number.formatter).format(number.base_obj, { :type => :percent })
number.to_s.should == "10%"
end
it 'should not overwrite precision when explicitly passed' do
- mock.proxy(number.formatter).format(number.base_obj, :precision => 1)
+ mock.proxy(number.formatter).format(number.base_obj, :precision => 1, :type => :percent)
number.to_s(:precision => 1).should == "10.0%"
end
end
+
+ context 'short decimals' do
+ let(:number) { LocalizedNumber.new(1000, :en, :type => :short_decimal) }
+
+ it "should default to a precision of 0" do
+ mock.proxy(number.formatter).format(number.base_obj, { :type => :short_decimal })
+ number.to_s.should == "1K"
+ end
+
+ it 'should not overwrite precision when explicitly passed' do
+ mock.proxy(number.formatter).format(number.base_obj, :precision => 1, :type => :short_decimal)
+ number.to_s(:precision => 1).should == "1.0K"
+ end
+ end
+
+ context 'long decimals' do
+ let(:number) { LocalizedNumber.new(1000, :en, :type => :long_decimal) }
+
+ it "should default to a precision of 0" do
+ mock.proxy(number.formatter).format(number.base_obj, { :type => :long_decimal })
+ number.to_s.should == "1 thousand"
+ end
+
+ it 'should not overwrite precision when explicitly passed' do
+ mock.proxy(number.formatter).format(number.base_obj, :precision => 1, :type => :long_decimal)
+ number.to_s(:precision => 1).should == "1.0 thousand"
+ end
+ end
end
describe '#plural_rule' do
View
32 spec/tokenizers/base_spec.rb
@@ -15,7 +15,7 @@ def init_resources; end
end
end
-describe Base do
+describe TwitterCldr::Tokenizers::Base do
before(:each) do
@base = TwitterCldr::Tokenizers::Base.new # do NOT do this in production - must use subclass
end
@@ -86,23 +86,26 @@ def init_resources; end
describe "#expand_pattern" do
it "recursively calls expand_pattern if a symbol (keypath) is given" do
+ @base.type = :fake_type
mock(@base).traverse([:another, :path]) { "found_me" }
mock(@base).pattern_for("found_me") { "pattern_text" }
- mock.proxy(@base).expand_pattern("pattern_text", :fake_type)
- mock.proxy(@base).expand_pattern(:'another.path', :fake_type)
- @base.send(:expand_pattern, :'another.path', :fake_type).should == [{ :value => "pattern_text", :type => :plaintext }]
+ mock.proxy(@base).expand_pattern("pattern_text")
+ mock.proxy(@base).expand_pattern(:'another.path')
+ @base.send(:expand_pattern, :'another.path').should == [{ :value => "pattern_text", :type => :plaintext }]
end
it "expands placeholders as necessary" do
placeholder_obj = Object.new
mock(placeholder_obj).tokens(:type => :man) { ["token1", "token2"] }
@base.placeholders = [{ :name => "wallace", :object => placeholder_obj }]
- @base.send(:expand_pattern, "{{wallace}} rules", :man).should == ["token1", "token2", { :type => :plaintext, :value => " rules" }]
+ @base.type = :man
+ @base.send(:expand_pattern, "{{wallace}} rules").should == ["token1", "token2", { :type => :plaintext, :value => " rules" }]
end
it "doesn't choke if the placeholder can't be found" do
@base.placeholders = [{ :name => "gromit", :object => "dog" }]
- @base.send(:expand_pattern, "{{wallace}} rules", :man).should == [{ :type => :plaintext, :value => " rules" }]
+ @base.type = :man
+ @base.send(:expand_pattern, "{{wallace}} rules").should == [{ :type => :plaintext, :value => " rules" }]
end
end
@@ -113,34 +116,37 @@ def init_resources; end
before(:each) do
stub(@base).traverse([:fake_key]) { "fake_pattern" }
stub(@base).pattern_for("fake_pattern") { "fake_expandable_pattern" }
- stub(@base).expand_pattern("fake_expandable_pattern", "fake_type") { [token1, token2] }
+ stub(@base).expand_pattern("fake_expandable_pattern") { [token1, token2] }
end
it "caches tokens" do
- result = @base.send(:tokens_for, [:fake_key], "fake_type")
+ @base.type = "fake_type"
+ result = @base.send(:tokens_for, [:fake_key])
result[0].value.should == "token1"
result[1].value.should == "token2"
@base.class.send(:class_variable_get, :'@@token_cache')["en|fake_key|fake_type|nil".hash].should == result
- result_again = @base.send(:tokens_for, [:fake_key], "fake_type")
+ @base.type = "fake_type"
+ result_again = @base.send(:tokens_for, [:fake_key])
result_again.object_id.should == result.object_id
end
it "caches tokens per language" do
- result_en = @base.send(:tokens_for, [:fake_key], "fake_type")
+ @base.type = "fake_type"
+ result_en = @base.send(:tokens_for, [:fake_key])
result_en[0].value.should == "token1"
result_en[1].value.should == "token2"
@base.class.send(:class_variable_get, :'@@token_cache')["en|fake_key|fake_type|nil".hash].should == result_en
- result_en2 = @base.send(:tokens_for, [:fake_key], "fake_type")
+ result_en2 = @base.send(:tokens_for, [:fake_key])
result_en2.object_id.should == result_en.object_id
@base.instance_variable_set(:'@locale', :pt)
- result_pt = @base.send(:tokens_for, [:fake_key], "fake_type")
+ result_pt = @base.send(:tokens_for, [:fake_key])
result_pt[0].value.should == "token1"
result_pt[1].value.should == "token2"
@base.class.send(:class_variable_get, :'@@token_cache')["pt|fake_key|fake_type|nil".hash].should == result_pt
result_pt.object_id.should_not == result_en.object_id
- result_pt2 = @base.send(:tokens_for, [:fake_key], "fake_type")
+ result_pt2 = @base.send(:tokens_for, [:fake_key])
result_pt2.object_id.should == result_pt.object_id
result_pt2.object_id.should_not == result_en.object_id
result_pt2.object_id.should_not == result_en2.object_id
View
2 spec/tokenizers/calendars/additional_date_format_selector_spec.rb
@@ -98,7 +98,7 @@
it "returns the next closest match (lowest score) if an exact match can't be found" do
selector.find_closest("MMMMd").should == "MMMd"
selector.find_closest("mHs").should == "Hms"
- selector.find_closest("Ehd").should == "Ehm"
+ selector.find_closest("Ehds").should == "Ehms"
end
it "returns nil if an empty pattern is given" do
View
30 spec/tokenizers/numbers/number_tokenizer_spec.rb
@@ -8,28 +8,16 @@
include TwitterCldr::Tokenizers
describe NumberTokenizer do
- describe "#initialize" do
- it "chooses decimal as the default type if no other type is specified" do
- NumberTokenizer.new.type.should == :decimal
- NumberTokenizer.new(:type => :percent).type.should == :percent
- end
- end
-
- describe "#full_path_for" do
+ describe "#full_path" do
it "should fill in the type and return the full path to the requested format" do
- NumberTokenizer.new.send(:full_path_for, :default).should == [:numbers, :formats, :decimal, :patterns, :default]
+ tokenizer = NumberTokenizer.new
+ tokenizer.type = :default
+ tokenizer.format = :default
+ tokenizer.send(:full_path).should == [:numbers, :formats, :decimal, :patterns, :default]
end
end
describe "#tokens" do
- it "ensures that positive and negative entries are created (as necessary)" do
- tokenizer = NumberTokenizer.new(:locale => :tr)
- tokenizer.tokens
- root = tokenizer.resource[:numbers][:formats][:decimal][:patterns]
- root.should include(:positive)
- root.should include(:negative)
- end
-
it "gets tokens for a latin language (i.e. Portuguese)" do
tokenizer = NumberTokenizer.new(:locale => :pt)
got = tokenizer.tokens
@@ -47,17 +35,17 @@
end
it "correctly parses suffixes (i.e. Russian currency)" do
- tokenizer = NumberTokenizer.new(:locale => :ru, :type => :currency)
- got = tokenizer.tokens
+ tokenizer = NumberTokenizer.new(:locale => :ru)
+ got = tokenizer.tokens(:type => :currency)
expected = [{ :value => "", :type => :pattern },
{ :value => "#,##0.00", :type => :pattern },
{ :value => " ¤", :type => :pattern }]
check_token_list(got, expected)
end
it "correctly parses prefixes (i.e. Italian currency)" do
- tokenizer = NumberTokenizer.new(:locale => :it, :type => :currency)
- got = tokenizer.tokens
+ tokenizer = NumberTokenizer.new(:locale => :it)
+ got = tokenizer.tokens(:type => :currency)
expected = [{ :value => "¤ ", :type => :pattern },
{ :value => "#,##0.00", :type => :pattern }]
check_token_list(got, expected)

0 comments on commit 1b76e0a

Please sign in to comment.