money 6.10.1 → 6.11.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 +4 -4
- data/.travis.yml +9 -7
- data/AUTHORS +3 -0
- data/CHANGELOG.md +13 -0
- data/README.md +2 -1
- data/config/currency_non_iso.json +2 -2
- data/lib/money/bank/variable_exchange.rb +4 -4
- data/lib/money/currency.rb +11 -28
- data/lib/money/money/arithmetic.rb +11 -9
- data/lib/money/money/{formatting.rb → formatter.rb} +111 -152
- data/lib/money/money/formatting_rules.rb +71 -0
- data/lib/money/money.rb +43 -28
- data/lib/money/version.rb +1 -1
- data/money.gemspec +2 -2
- data/spec/currency_spec.rb +26 -0
- data/spec/money/arithmetic_spec.rb +28 -1
- data/spec/money/formatting_spec.rb +34 -29
- data/spec/money_spec.rb +25 -8
- data/spec/spec_helper.rb +2 -0
- data/spec/support/shared_examples/money_examples.rb +14 -0
- metadata +10 -7
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA1:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: 8de2a6b8bf58ff5719f33d9db889ae722fa39b41
         | 
| 4 | 
            +
              data.tar.gz: 713995a09dfac0042e598c153f3d7dffa54e06d7
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: 86cd80fd6278138aa30cdf281e92bfc369035fe7122d98f78ebdd3662810fe7ead3a252e7dea8f40f6600df6c23134f2038e8f8a685fd3065306ef06b81a8f6b
         | 
| 7 | 
            +
              data.tar.gz: e8ed3c0961bbb92ab3cb5523620f08fab61c1c9741819bf2f892c039fd8d5b550843113a71b984dc249ebdb5aa9cbf2f0291b813085c940648f647cb6764f404
         | 
    
        data/.travis.yml
    CHANGED
    
    | @@ -1,22 +1,24 @@ | |
| 1 | 
            +
            ---
         | 
| 1 2 | 
             
            language: ruby
         | 
| 2 3 | 
             
            sudo: false
         | 
| 3 4 | 
             
            rvm:
         | 
| 4 5 | 
             
              - 1.9.3
         | 
| 5 | 
            -
              - 2.0 | 
| 6 | 
            +
              - 2.0
         | 
| 6 7 | 
             
              - 2.1.10
         | 
| 7 | 
            -
              - 2.2. | 
| 8 | 
            -
              - 2.3. | 
| 9 | 
            -
              - 2.4. | 
| 10 | 
            -
              -  | 
| 8 | 
            +
              - 2.2.10
         | 
| 9 | 
            +
              - 2.3.7
         | 
| 10 | 
            +
              - 2.4.4
         | 
| 11 | 
            +
              - 2.5.1
         | 
| 12 | 
            +
              - rbx-3
         | 
| 11 13 | 
             
              - jruby-9.0.5.0
         | 
| 12 | 
            -
              - jruby-9.1. | 
| 14 | 
            +
              - jruby-9.1.16.0
         | 
| 13 15 | 
             
              - ruby-head
         | 
| 14 16 | 
             
              - jruby-head
         | 
| 15 17 | 
             
            matrix:
         | 
| 16 18 | 
             
              allow_failures:
         | 
| 17 19 | 
             
                - rvm: ruby-head
         | 
| 18 20 | 
             
                - rvm: jruby-head
         | 
| 19 | 
            -
                - rvm: rbx- | 
| 21 | 
            +
                - rvm: rbx-3
         | 
| 20 22 | 
             
              fast_finish: true
         | 
| 21 23 | 
             
            before_install:
         | 
| 22 24 | 
             
              - gem update bundler
         | 
    
        data/AUTHORS
    CHANGED
    
    | @@ -43,6 +43,7 @@ George Millo | |
| 43 43 | 
             
            Hakan Ensari
         | 
| 44 44 | 
             
            Hongli Lai
         | 
| 45 45 | 
             
            Ilia Lobsanov
         | 
| 46 | 
            +
            Ivan Shamatov
         | 
| 46 47 | 
             
            Ingo Wichmann
         | 
| 47 48 | 
             
            Jacob Atzen
         | 
| 48 49 | 
             
            James Cotterill
         | 
| @@ -112,6 +113,7 @@ Thomas Weymuth | |
| 112 113 | 
             
            Ticean Bennett
         | 
| 113 114 | 
             
            Tien Nguyen
         | 
| 114 115 | 
             
            Tim Hart
         | 
| 116 | 
            +
            Tim Krins
         | 
| 115 117 | 
             
            Tobias Luetke
         | 
| 116 118 | 
             
            Tobias Schmidt
         | 
| 117 119 | 
             
            Tom Lianza
         | 
| @@ -125,3 +127,4 @@ Yuri Sidorov | |
| 125 127 | 
             
            Yuusuke Takizawa
         | 
| 126 128 | 
             
            Zubin Henner
         | 
| 127 129 | 
             
            Бродяной Александр
         | 
| 130 | 
            +
            Nicolay Hvidsten
         | 
    
        data/CHANGELOG.md
    CHANGED
    
    | @@ -1,5 +1,18 @@ | |
| 1 1 | 
             
            # Changelog
         | 
| 2 2 |  | 
| 3 | 
            +
            ## 6.11.0
         | 
| 4 | 
            +
            - Support i18n 1.0
         | 
| 5 | 
            +
            - Update yard dependency to 0.9.11
         | 
| 6 | 
            +
            - Support for ruby 2.5.0
         | 
| 7 | 
            +
            - Add inheritance for currency definitions
         | 
| 8 | 
            +
            - Added new symbol for bitcoin denomination
         | 
| 9 | 
            +
            - Specify custom rounding precision when using `infinite_precision`
         | 
| 10 | 
            +
            - Allow splits with sums greater than 1
         | 
| 11 | 
            +
            - Prevent arithmetic methods from loosing reference to the bank
         | 
| 12 | 
            +
            - Fix coerced zero numeric subtraction
         | 
| 13 | 
            +
            - Fix south asian formatting to support whole numbers
         | 
| 14 | 
            +
            - Refactor formatting logic
         | 
| 15 | 
            +
             | 
| 3 16 | 
             
            ## 6.10.1
         | 
| 4 17 | 
             
            - Fix an issue with Money.empty memoization
         | 
| 5 18 |  | 
    
        data/README.md
    CHANGED
    
    | @@ -312,8 +312,9 @@ def marshal_dump; end | |
| 312 312 | 
             
            The following example implements an `ActiveRecord` store to save exchange rates to a database.
         | 
| 313 313 |  | 
| 314 314 | 
             
            ```ruby
         | 
| 315 | 
            -
            #  | 
| 315 | 
            +
            # rails g model exchange_rate from:string to:string rate:float
         | 
| 316 316 |  | 
| 317 | 
            +
            # for Rails 5 replace ActiveRecord::Base with ApplicationRecord
         | 
| 317 318 | 
             
            class ExchangeRate < ActiveRecord::Base
         | 
| 318 319 | 
             
              def self.get_rate(from_iso_code, to_iso_code)
         | 
| 319 320 | 
             
                rate = find_by(:from => from_iso_code, :to => to_iso_code)
         | 
| @@ -3,12 +3,12 @@ | |
| 3 3 | 
             
                "priority": 100,
         | 
| 4 4 | 
             
                "iso_code": "BTC",
         | 
| 5 5 | 
             
                "name": "Bitcoin",
         | 
| 6 | 
            -
                "symbol": " | 
| 6 | 
            +
                "symbol": "₿",
         | 
| 7 7 | 
             
                "alternate_symbols": [],
         | 
| 8 8 | 
             
                "subunit": "Satoshi",
         | 
| 9 9 | 
             
                "subunit_to_unit": 100000000,
         | 
| 10 10 | 
             
                "symbol_first": true,
         | 
| 11 | 
            -
                "html_entity": "",
         | 
| 11 | 
            +
                "html_entity": "₿",
         | 
| 12 12 | 
             
                "decimal_mark": ".",
         | 
| 13 13 | 
             
                "thousands_separator": ",",
         | 
| 14 14 | 
             
                "iso_numeric": "",
         | 
| @@ -119,14 +119,14 @@ class Money | |
| 119 119 | 
             
                  end
         | 
| 120 120 |  | 
| 121 121 | 
             
                  def calculate_fractional(from, to_currency)
         | 
| 122 | 
            -
                    BigDecimal | 
| 123 | 
            -
                      BigDecimal | 
| 124 | 
            -
                      BigDecimal | 
| 122 | 
            +
                    BigDecimal(from.fractional.to_s) / (
         | 
| 123 | 
            +
                      BigDecimal(from.currency.subunit_to_unit.to_s) /
         | 
| 124 | 
            +
                      BigDecimal(to_currency.subunit_to_unit.to_s)
         | 
| 125 125 | 
             
                    )
         | 
| 126 126 | 
             
                  end
         | 
| 127 127 |  | 
| 128 128 | 
             
                  def exchange(fractional, rate, &block)
         | 
| 129 | 
            -
                    ex = fractional * BigDecimal | 
| 129 | 
            +
                    ex = fractional * BigDecimal(rate.to_s)
         | 
| 130 130 | 
             
                    if block_given?
         | 
| 131 131 | 
             
                      yield ex
         | 
| 132 132 | 
             
                    elsif @rounding_method
         | 
    
        data/lib/money/currency.rb
    CHANGED
    
    | @@ -173,6 +173,15 @@ class Money | |
| 173 173 | 
             
                    @stringified_keys = stringify_keys
         | 
| 174 174 | 
             
                  end
         | 
| 175 175 |  | 
| 176 | 
            +
                  # Inherit a new currency from existing one
         | 
| 177 | 
            +
                  #
         | 
| 178 | 
            +
                  # @param parent_iso_code [String] the international 3-letter code as defined
         | 
| 179 | 
            +
                  # @param curr [Hash] See {register} method for hash structure 
         | 
| 180 | 
            +
                  def inherit(parent_iso_code, curr)
         | 
| 181 | 
            +
                    parent_iso_code = parent_iso_code.downcase.to_sym
         | 
| 182 | 
            +
                    curr = @table.fetch(parent_iso_code, {}).merge(curr)
         | 
| 183 | 
            +
                    register(curr)
         | 
| 184 | 
            +
                  end
         | 
| 176 185 |  | 
| 177 186 | 
             
                  # Unregister a currency.
         | 
| 178 187 | 
             
                  #
         | 
| @@ -399,38 +408,12 @@ class Money | |
| 399 408 | 
             
                #
         | 
| 400 409 | 
             
                # @return [Integer]
         | 
| 401 410 | 
             
                def exponent
         | 
| 402 | 
            -
                  Math.log10( | 
| 403 | 
            -
                end
         | 
| 404 | 
            -
             | 
| 405 | 
            -
                # Cache decimal places for subunit_to_unit values. Common ones pre-cached.
         | 
| 406 | 
            -
                def self.decimal_places_cache
         | 
| 407 | 
            -
                  @decimal_places_cache ||= {1 => 0, 10 => 1, 100 => 2, 1000 => 3}
         | 
| 408 | 
            -
                end
         | 
| 409 | 
            -
             | 
| 410 | 
            -
                # The number of decimal places needed.
         | 
| 411 | 
            -
                #
         | 
| 412 | 
            -
                # @return [Integer]
         | 
| 413 | 
            -
                def decimal_places
         | 
| 414 | 
            -
                  cache[subunit_to_unit] ||= calculate_decimal_places(subunit_to_unit)
         | 
| 411 | 
            +
                  Math.log10(subunit_to_unit).round
         | 
| 415 412 | 
             
                end
         | 
| 413 | 
            +
                alias decimal_places exponent
         | 
| 416 414 |  | 
| 417 415 | 
             
                private
         | 
| 418 416 |  | 
| 419 | 
            -
                def cache
         | 
| 420 | 
            -
                  self.class.decimal_places_cache
         | 
| 421 | 
            -
                end
         | 
| 422 | 
            -
             | 
| 423 | 
            -
                # If we need to figure out how many decimal places we need we
         | 
| 424 | 
            -
                # use repeated integer division.
         | 
| 425 | 
            -
                def calculate_decimal_places(num)
         | 
| 426 | 
            -
                  i = 1
         | 
| 427 | 
            -
                  while num >= 10
         | 
| 428 | 
            -
                    num /= 10
         | 
| 429 | 
            -
                    i += 1 if num >= 10
         | 
| 430 | 
            -
                  end
         | 
| 431 | 
            -
                  i
         | 
| 432 | 
            -
                end
         | 
| 433 | 
            -
             | 
| 434 417 | 
             
                def initialize_data!
         | 
| 435 418 | 
             
                  data = self.class.table[@id]
         | 
| 436 419 | 
             
                  @alternate_symbols     = data[:alternate_symbols]
         | 
| @@ -16,7 +16,7 @@ class Money | |
| 16 16 | 
             
                # @example
         | 
| 17 17 | 
             
                #    - Money.new(100) #=> #<Money @fractional=-100>
         | 
| 18 18 | 
             
                def -@
         | 
| 19 | 
            -
                  self.class.new(-fractional, currency)
         | 
| 19 | 
            +
                  self.class.new(-fractional, currency, bank)
         | 
| 20 20 | 
             
                end
         | 
| 21 21 |  | 
| 22 22 | 
             
                # Checks whether two Money objects have the same currency and the same
         | 
| @@ -125,11 +125,13 @@ class Money | |
| 125 125 | 
             
                [:+, :-].each do |op|
         | 
| 126 126 | 
             
                  define_method(op) do |other|
         | 
| 127 127 | 
             
                    unless other.is_a?(Money)
         | 
| 128 | 
            -
                       | 
| 128 | 
            +
                      if other.zero?
         | 
| 129 | 
            +
                        return other.is_a?(CoercedNumeric) ? Money.empty.public_send(op, self) : self
         | 
| 130 | 
            +
                      end
         | 
| 129 131 | 
             
                      raise TypeError
         | 
| 130 132 | 
             
                    end
         | 
| 131 133 | 
             
                    other = other.exchange_to(currency)
         | 
| 132 | 
            -
                    self.class.new(fractional.public_send(op, other.fractional), currency)
         | 
| 134 | 
            +
                    self.class.new(fractional.public_send(op, other.fractional), currency, bank)
         | 
| 133 135 | 
             
                  end
         | 
| 134 136 | 
             
                end
         | 
| 135 137 |  | 
| @@ -150,7 +152,7 @@ class Money | |
| 150 152 | 
             
                def *(value)
         | 
| 151 153 | 
             
                  value = value.value if value.is_a?(CoercedNumeric)
         | 
| 152 154 | 
             
                  if value.is_a? Numeric
         | 
| 153 | 
            -
                    self.class.new(fractional * value, currency)
         | 
| 155 | 
            +
                    self.class.new(fractional * value, currency, bank)
         | 
| 154 156 | 
             
                  else
         | 
| 155 157 | 
             
                    raise TypeError, "Can't multiply a #{self.class.name} by a #{value.class.name}'s value"
         | 
| 156 158 | 
             
                  end
         | 
| @@ -176,7 +178,7 @@ class Money | |
| 176 178 | 
             
                    fractional / as_d(value.exchange_to(currency).fractional).to_f
         | 
| 177 179 | 
             
                  else
         | 
| 178 180 | 
             
                    raise TypeError, 'Can not divide by Money' if value.is_a?(CoercedNumeric)
         | 
| 179 | 
            -
                    self.class.new(fractional / as_d(value), currency)
         | 
| 181 | 
            +
                    self.class.new(fractional / as_d(value), currency, bank)
         | 
| 180 182 | 
             
                  end
         | 
| 181 183 | 
             
                end
         | 
| 182 184 |  | 
| @@ -214,13 +216,13 @@ class Money | |
| 214 216 | 
             
                def divmod_money(val)
         | 
| 215 217 | 
             
                  cents = val.exchange_to(currency).cents
         | 
| 216 218 | 
             
                  quotient, remainder = fractional.divmod(cents)
         | 
| 217 | 
            -
                  [quotient, self.class.new(remainder, currency)]
         | 
| 219 | 
            +
                  [quotient, self.class.new(remainder, currency, bank)]
         | 
| 218 220 | 
             
                end
         | 
| 219 221 | 
             
                private :divmod_money
         | 
| 220 222 |  | 
| 221 223 | 
             
                def divmod_other(val)
         | 
| 222 224 | 
             
                  quotient, remainder = fractional.divmod(as_d(val))
         | 
| 223 | 
            -
                  [self.class.new(quotient, currency), self.class.new(remainder, currency)]
         | 
| 225 | 
            +
                  [self.class.new(quotient, currency, bank), self.class.new(remainder, currency, bank)]
         | 
| 224 226 | 
             
                end
         | 
| 225 227 | 
             
                private :divmod_other
         | 
| 226 228 |  | 
| @@ -264,7 +266,7 @@ class Money | |
| 264 266 | 
             
                  if (fractional < 0 && val < 0) || (fractional > 0 && val > 0)
         | 
| 265 267 | 
             
                    self.modulo(val)
         | 
| 266 268 | 
             
                  else
         | 
| 267 | 
            -
                    self.modulo(val) - (val.is_a?(Money) ? val : self.class.new(val, currency))
         | 
| 269 | 
            +
                    self.modulo(val) - (val.is_a?(Money) ? val : self.class.new(val, currency, bank))
         | 
| 268 270 | 
             
                  end
         | 
| 269 271 | 
             
                end
         | 
| 270 272 |  | 
| @@ -275,7 +277,7 @@ class Money | |
| 275 277 | 
             
                # @example
         | 
| 276 278 | 
             
                #   Money.new(-100).abs #=> #<Money @fractional=100>
         | 
| 277 279 | 
             
                def abs
         | 
| 278 | 
            -
                  self.class.new(fractional.abs, currency)
         | 
| 280 | 
            +
                  self.class.new(fractional.abs, currency, bank)
         | 
| 279 281 | 
             
                end
         | 
| 280 282 |  | 
| 281 283 | 
             
                # Test if the money amount is zero.
         | 
| @@ -1,6 +1,8 @@ | |
| 1 1 | 
             
            # encoding: UTF-8
         | 
| 2 | 
            +
            require 'money/money/formatting_rules'
         | 
| 3 | 
            +
             | 
| 2 4 | 
             
            class Money
         | 
| 3 | 
            -
               | 
| 5 | 
            +
              class Formatter
         | 
| 4 6 | 
             
                # Creates a formatted price string according to several rules.
         | 
| 5 7 | 
             
                #
         | 
| 6 8 | 
             
                # @param [Hash] rules The options used to format the string.
         | 
| @@ -198,66 +200,27 @@ class Money | |
| 198 200 | 
             
                # Note that the default rules can be defined through {Money.default_formatting_rules} hash.
         | 
| 199 201 | 
             
                #
         | 
| 200 202 | 
             
                # @see Money.default_formatting_rules Money.default_formatting_rules for more information.
         | 
| 201 | 
            -
                def  | 
| 202 | 
            -
                   | 
| 203 | 
            -
                   | 
| 204 | 
            -
             | 
| 205 | 
            -
             | 
| 206 | 
            -
                  rules = localize_formatting_rules(rules)
         | 
| 207 | 
            -
                  rules = translate_formatting_rules(rules) if rules[:translate]
         | 
| 208 | 
            -
             | 
| 209 | 
            -
                  thousands_separator = self.thousands_separator
         | 
| 210 | 
            -
                  decimal_mark = self.decimal_mark
         | 
| 211 | 
            -
             | 
| 212 | 
            -
                  escaped_decimal_mark = Regexp.escape(decimal_mark)
         | 
| 213 | 
            -
             | 
| 214 | 
            -
                  if fractional == 0
         | 
| 215 | 
            -
                    if rules[:display_free].respond_to?(:to_str)
         | 
| 216 | 
            -
                      return rules[:display_free]
         | 
| 217 | 
            -
                    elsif rules[:display_free]
         | 
| 218 | 
            -
                      return "free"
         | 
| 219 | 
            -
                    end
         | 
| 220 | 
            -
                  end
         | 
| 221 | 
            -
             | 
| 222 | 
            -
                  symbol_value = symbol_value_from(rules)
         | 
| 223 | 
            -
             | 
| 224 | 
            -
                  formatted = self.abs.to_s
         | 
| 203 | 
            +
                def initialize(money, *rules)
         | 
| 204 | 
            +
                  @money = money
         | 
| 205 | 
            +
                  @currency = money.currency
         | 
| 206 | 
            +
                  @rules = FormattingRules.new(@currency, *rules)
         | 
| 207 | 
            +
                end
         | 
| 225 208 |  | 
| 226 | 
            -
             | 
| 227 | 
            -
             | 
| 228 | 
            -
                    formatted = ((BigDecimal(formatted) * currency.subunit_to_unit).round / BigDecimal(currency.subunit_to_unit.to_s)).to_s("F")
         | 
| 229 | 
            -
                    formatted.gsub!(/\..*/) do |decimal_part|
         | 
| 230 | 
            -
                      decimal_part << '0' while decimal_part.length < (currency.decimal_places + 1)
         | 
| 231 | 
            -
                      decimal_part
         | 
| 232 | 
            -
                    end
         | 
| 233 | 
            -
                    formatted.gsub!(/\./, decimal_mark) unless '.' == decimal_mark
         | 
| 234 | 
            -
                  end
         | 
| 209 | 
            +
                def to_s
         | 
| 210 | 
            +
                  return free_text if show_free_text?
         | 
| 235 211 |  | 
| 236 | 
            -
                   | 
| 212 | 
            +
                  whole_part, decimal_part = extract_whole_and_decimal_parts
         | 
| 237 213 |  | 
| 238 | 
            -
                   | 
| 239 | 
            -
             | 
| 240 | 
            -
                   | 
| 214 | 
            +
                  # Format whole and decimal parts separately
         | 
| 215 | 
            +
                  decimal_part = format_decimal_part(decimal_part)
         | 
| 216 | 
            +
                  whole_part = format_whole_part(whole_part)
         | 
| 241 217 |  | 
| 242 | 
            -
                  #  | 
| 243 | 
            -
                   | 
| 244 | 
            -
                    formatted = formatted.sub(/(#{escaped_decimal_mark})(\d*[1-9])?0+\z/, '\1\2').sub(/#{escaped_decimal_mark}\z/, '')
         | 
| 245 | 
            -
                  end
         | 
| 246 | 
            -
                  has_decimal_value = !!(formatted =~ /#{escaped_decimal_mark}/)
         | 
| 218 | 
            +
                  # Assemble the final formatted amount
         | 
| 219 | 
            +
                  formatted = [whole_part, decimal_part].compact.join(decimal_mark)
         | 
| 247 220 |  | 
| 248 | 
            -
                   | 
| 249 | 
            -
                  # Determine thousands_separator
         | 
| 250 | 
            -
                  if rules.has_key?(:thousands_separator)
         | 
| 251 | 
            -
                    thousands_separator_value = rules[:thousands_separator] || ''
         | 
| 252 | 
            -
                  end
         | 
| 221 | 
            +
                  sign = money.negative? ? '-' : ''
         | 
| 253 222 |  | 
| 254 | 
            -
                   | 
| 255 | 
            -
                  formatted.gsub!(regexp_format(formatted, rules, decimal_mark, symbol_value),
         | 
| 256 | 
            -
                                  "\\1#{thousands_separator_value}")
         | 
| 257 | 
            -
             | 
| 258 | 
            -
                  symbol_position = symbol_position_from(rules)
         | 
| 259 | 
            -
             | 
| 260 | 
            -
                  if rules[:sign_positive] == true && self.positive?
         | 
| 223 | 
            +
                  if rules[:sign_positive] == true && money.positive?
         | 
| 261 224 | 
             
                    sign = '+'
         | 
| 262 225 | 
             
                  end
         | 
| 263 226 |  | 
| @@ -266,8 +229,11 @@ class Money | |
| 266 229 | 
             
                    sign = ''
         | 
| 267 230 | 
             
                  end
         | 
| 268 231 |  | 
| 232 | 
            +
                  symbol_value = symbol_value_from(rules)
         | 
| 233 | 
            +
             | 
| 269 234 | 
             
                  if symbol_value && !symbol_value.empty?
         | 
| 270 235 | 
             
                    symbol_value = "<span class=\"currency_symbol\">#{symbol_value}</span>" if rules[:html_wrap_symbol]
         | 
| 236 | 
            +
                    symbol_position = symbol_position_from(rules)
         | 
| 271 237 |  | 
| 272 238 | 
             
                    formatted = if symbol_position == :before
         | 
| 273 239 | 
             
                      symbol_space = rules[:symbol_before_without_space] === false ? " " : ""
         | 
| @@ -280,8 +246,6 @@ class Money | |
| 280 246 | 
             
                    formatted="#{sign_before}#{sign}#{formatted}"
         | 
| 281 247 | 
             
                  end
         | 
| 282 248 |  | 
| 283 | 
            -
                  apply_decimal_mark_from_rules(formatted, rules) if has_decimal_value
         | 
| 284 | 
            -
             | 
| 285 249 | 
             
                  if rules[:with_currency]
         | 
| 286 250 | 
             
                    formatted << " "
         | 
| 287 251 | 
             
                    formatted << '<span class="currency">' if rules[:html]
         | 
| @@ -292,11 +256,19 @@ class Money | |
| 292 256 | 
             
                end
         | 
| 293 257 |  | 
| 294 258 | 
             
                def thousands_separator
         | 
| 295 | 
            -
                   | 
| 259 | 
            +
                  if rules.has_key?(:thousands_separator)
         | 
| 260 | 
            +
                    rules[:thousands_separator] || ''
         | 
| 261 | 
            +
                  else
         | 
| 262 | 
            +
                    i18n_format_for(:thousands_separator, :delimiter, ',')
         | 
| 263 | 
            +
                  end
         | 
| 296 264 | 
             
                end
         | 
| 297 265 |  | 
| 298 266 | 
             
                def decimal_mark
         | 
| 299 | 
            -
                   | 
| 267 | 
            +
                  if rules.has_key?(:decimal_mark)
         | 
| 268 | 
            +
                    rules[:decimal_mark] || '.'
         | 
| 269 | 
            +
                  else
         | 
| 270 | 
            +
                    i18n_format_for(:decimal_mark, :separator, '.')
         | 
| 271 | 
            +
                  end
         | 
| 300 272 | 
             
                end
         | 
| 301 273 |  | 
| 302 274 | 
             
                alias_method :delimiter, :thousands_separator
         | 
| @@ -304,8 +276,57 @@ class Money | |
| 304 276 |  | 
| 305 277 | 
             
                private
         | 
| 306 278 |  | 
| 279 | 
            +
                attr_reader :money, :currency, :rules
         | 
| 280 | 
            +
             | 
| 281 | 
            +
                def show_free_text?
         | 
| 282 | 
            +
                  money.zero? && rules[:display_free]
         | 
| 283 | 
            +
                end
         | 
| 284 | 
            +
             | 
| 285 | 
            +
                def free_text
         | 
| 286 | 
            +
                  rules[:display_free].respond_to?(:to_str) ? rules[:display_free] : 'free'
         | 
| 287 | 
            +
                end
         | 
| 288 | 
            +
             | 
| 289 | 
            +
                def format_whole_part(value)
         | 
| 290 | 
            +
                  # Determine thousands_separator
         | 
| 291 | 
            +
                  thousands_separator_value = if rules.has_key?(:thousands_separator)
         | 
| 292 | 
            +
                                                rules[:thousands_separator] || ''
         | 
| 293 | 
            +
                                              else
         | 
| 294 | 
            +
                                                thousands_separator
         | 
| 295 | 
            +
                                              end
         | 
| 296 | 
            +
             | 
| 297 | 
            +
                  # Apply thousands_separator
         | 
| 298 | 
            +
                  value.gsub regexp_format, "\\1#{thousands_separator_value}"
         | 
| 299 | 
            +
                end
         | 
| 300 | 
            +
             | 
| 301 | 
            +
                def extract_whole_and_decimal_parts
         | 
| 302 | 
            +
                  fractional = money.fractional.abs
         | 
| 303 | 
            +
             | 
| 304 | 
            +
                  # Round the infinite precision part if needed
         | 
| 305 | 
            +
                  fractional = fractional.round if rules[:rounded_infinite_precision]
         | 
| 306 | 
            +
             | 
| 307 | 
            +
                  # Translate subunits into units
         | 
| 308 | 
            +
                  fractional_units = BigDecimal(fractional) / currency.subunit_to_unit
         | 
| 309 | 
            +
             | 
| 310 | 
            +
                  # Split the result and return whole and decimal parts separately
         | 
| 311 | 
            +
                  fractional_units.to_s('F').split('.')
         | 
| 312 | 
            +
                end
         | 
| 313 | 
            +
             | 
| 314 | 
            +
                def format_decimal_part(value)
         | 
| 315 | 
            +
                  return nil if currency.decimal_places == 0
         | 
| 316 | 
            +
                  return nil if rules[:no_cents]
         | 
| 317 | 
            +
                  return nil if rules[:no_cents_if_whole] && value.to_i == 0
         | 
| 318 | 
            +
             | 
| 319 | 
            +
                  # Pad value, making up for missing zeroes at the end
         | 
| 320 | 
            +
                  value = value.ljust(currency.decimal_places, '0')
         | 
| 321 | 
            +
             | 
| 322 | 
            +
                  # Drop trailing zeros if needed
         | 
| 323 | 
            +
                  value.gsub!(/0*$/, '') if rules[:drop_trailing_zeros]
         | 
| 324 | 
            +
             | 
| 325 | 
            +
                  value.empty? ? nil : value
         | 
| 326 | 
            +
                end
         | 
| 327 | 
            +
             | 
| 307 328 | 
             
                def i18n_format_for(method, name, character)
         | 
| 308 | 
            -
                  if  | 
| 329 | 
            +
                  if Money.use_i18n
         | 
| 309 330 | 
             
                    begin
         | 
| 310 331 | 
             
                      I18n.t name, :scope => "number.currency.format", :raise => true
         | 
| 311 332 | 
             
                    rescue I18n::MissingTranslationData
         | 
| @@ -316,111 +337,49 @@ class Money | |
| 316 337 | 
             
                  end
         | 
| 317 338 | 
             
                end
         | 
| 318 339 |  | 
| 319 | 
            -
                 | 
| 320 | 
            -
             | 
| 321 | 
            -
             | 
| 322 | 
            -
             | 
| 323 | 
            -
                # @return [Hash]
         | 
| 324 | 
            -
                def normalize_formatting_rules(rules)
         | 
| 325 | 
            -
                  if rules.size == 0
         | 
| 326 | 
            -
                    rules = {}
         | 
| 327 | 
            -
                  elsif rules.size == 1
         | 
| 328 | 
            -
                    rules = rules.pop
         | 
| 329 | 
            -
                    rules = { rules => true } if rules.is_a?(Symbol)
         | 
| 330 | 
            -
                  end
         | 
| 331 | 
            -
                  if !rules.include?(:decimal_mark) && rules.include?(:separator)
         | 
| 332 | 
            -
                    rules[:decimal_mark] = rules[:separator]
         | 
| 333 | 
            -
                  end
         | 
| 334 | 
            -
                  if !rules.include?(:thousands_separator) && rules.include?(:delimiter)
         | 
| 335 | 
            -
                    rules[:thousands_separator] = rules[:delimiter]
         | 
| 336 | 
            -
                  end
         | 
| 337 | 
            -
                  rules
         | 
| 338 | 
            -
                end
         | 
| 339 | 
            -
             | 
| 340 | 
            -
                # Applies decimal mark from rules to formatted
         | 
| 341 | 
            -
                #
         | 
| 342 | 
            -
                # @param [String] formatted
         | 
| 343 | 
            -
                # @param [Hash]   rules
         | 
| 344 | 
            -
                def apply_decimal_mark_from_rules(formatted, rules)
         | 
| 345 | 
            -
                  if rules.has_key?(:decimal_mark) && rules[:decimal_mark] &&
         | 
| 346 | 
            -
                    rules[:decimal_mark] != decimal_mark
         | 
| 347 | 
            -
             | 
| 348 | 
            -
                    regexp_decimal = Regexp.escape(decimal_mark)
         | 
| 349 | 
            -
                    formatted.sub!(/(.*)(#{regexp_decimal})(.*)\Z/,
         | 
| 350 | 
            -
                                   "\\1#{rules[:decimal_mark]}\\3")
         | 
| 351 | 
            -
                  end
         | 
| 352 | 
            -
                end
         | 
| 353 | 
            -
              end
         | 
| 354 | 
            -
             | 
| 355 | 
            -
              def default_formatting_rules
         | 
| 356 | 
            -
                self.class.default_formatting_rules || {}
         | 
| 357 | 
            -
              end
         | 
| 358 | 
            -
             | 
| 359 | 
            -
              def regexp_format(formatted, rules, decimal_mark, symbol_value)
         | 
| 360 | 
            -
                regexp_decimal = Regexp.escape(decimal_mark)
         | 
| 361 | 
            -
                if rules[:south_asian_number_formatting]
         | 
| 362 | 
            -
                  /(\d+?)(?=(\d\d)+(\d)(?:\.))/
         | 
| 363 | 
            -
                else
         | 
| 364 | 
            -
                  # Symbols may contain decimal marks (E.g "դր.")
         | 
| 365 | 
            -
                  if formatted.sub(symbol_value.to_s, "") =~ /#{regexp_decimal}/
         | 
| 366 | 
            -
                    /(\d)(?=(?:\d{3})+(?:#{regexp_decimal}))/
         | 
| 340 | 
            +
                def regexp_format
         | 
| 341 | 
            +
                  if rules[:south_asian_number_formatting]
         | 
| 342 | 
            +
                    # from http://blog.revathskumar.com/2014/11/regex-comma-seperated-indian-currency-format.html
         | 
| 343 | 
            +
                    /(\d+?)(?=(\d\d)+(\d)(?!\d))(\.\d+)?/
         | 
| 367 344 | 
             
                  else
         | 
| 368 345 | 
             
                    /(\d)(?=(?:\d{3})+(?:[^\d]{1}|$))/
         | 
| 369 346 | 
             
                  end
         | 
| 370 347 | 
             
                end
         | 
| 371 | 
            -
              end
         | 
| 372 | 
            -
             | 
| 373 | 
            -
              def translate_formatting_rules(rules)
         | 
| 374 | 
            -
                begin
         | 
| 375 | 
            -
                  rules[:symbol] = I18n.t currency.iso_code, :scope => "number.currency.symbol", :raise => true
         | 
| 376 | 
            -
                rescue I18n::MissingTranslationData
         | 
| 377 | 
            -
                  # Do nothing
         | 
| 378 | 
            -
                end
         | 
| 379 | 
            -
                rules
         | 
| 380 | 
            -
              end
         | 
| 381 348 |  | 
| 382 | 
            -
             | 
| 383 | 
            -
             | 
| 384 | 
            -
             | 
| 385 | 
            -
             | 
| 386 | 
            -
             | 
| 387 | 
            -
             | 
| 388 | 
            -
             | 
| 389 | 
            -
             | 
| 390 | 
            -
             | 
| 391 | 
            -
             | 
| 392 | 
            -
                if rules.has_key?(:symbol)
         | 
| 393 | 
            -
                  if rules[:symbol] === true
         | 
| 394 | 
            -
                    if rules[:disambiguate] && currency.disambiguate_symbol
         | 
| 395 | 
            -
                      currency.disambiguate_symbol
         | 
| 349 | 
            +
                def symbol_value_from(rules)
         | 
| 350 | 
            +
                  if rules.has_key?(:symbol)
         | 
| 351 | 
            +
                    if rules[:symbol] === true
         | 
| 352 | 
            +
                      if rules[:disambiguate] && currency.disambiguate_symbol
         | 
| 353 | 
            +
                        currency.disambiguate_symbol
         | 
| 354 | 
            +
                      else
         | 
| 355 | 
            +
                        money.symbol
         | 
| 356 | 
            +
                      end
         | 
| 357 | 
            +
                    elsif rules[:symbol]
         | 
| 358 | 
            +
                      rules[:symbol]
         | 
| 396 359 | 
             
                    else
         | 
| 397 | 
            -
                       | 
| 360 | 
            +
                      ""
         | 
| 398 361 | 
             
                    end
         | 
| 399 | 
            -
                  elsif rules[: | 
| 400 | 
            -
                     | 
| 362 | 
            +
                  elsif rules[:html]
         | 
| 363 | 
            +
                    currency.html_entity == '' ? currency.symbol : currency.html_entity
         | 
| 364 | 
            +
                  elsif rules[:disambiguate] && currency.disambiguate_symbol
         | 
| 365 | 
            +
                    currency.disambiguate_symbol
         | 
| 401 366 | 
             
                  else
         | 
| 402 | 
            -
                     | 
| 367 | 
            +
                    money.symbol
         | 
| 403 368 | 
             
                  end
         | 
| 404 | 
            -
                elsif rules[:html]
         | 
| 405 | 
            -
                  currency.html_entity == '' ? currency.symbol : currency.html_entity
         | 
| 406 | 
            -
                elsif rules[:disambiguate] && currency.disambiguate_symbol
         | 
| 407 | 
            -
                  currency.disambiguate_symbol
         | 
| 408 | 
            -
                else
         | 
| 409 | 
            -
                  symbol
         | 
| 410 369 | 
             
                end
         | 
| 411 | 
            -
              end
         | 
| 412 370 |  | 
| 413 | 
            -
             | 
| 414 | 
            -
             | 
| 415 | 
            -
             | 
| 416 | 
            -
             | 
| 371 | 
            +
                def symbol_position_from(rules)
         | 
| 372 | 
            +
                  if rules.has_key?(:symbol_position)
         | 
| 373 | 
            +
                    if [:before, :after].include?(rules[:symbol_position])
         | 
| 374 | 
            +
                      return rules[:symbol_position]
         | 
| 375 | 
            +
                    else
         | 
| 376 | 
            +
                      raise ArgumentError, ":symbol_position must be ':before' or ':after'"
         | 
| 377 | 
            +
                    end
         | 
| 378 | 
            +
                  elsif currency.symbol_first?
         | 
| 379 | 
            +
                    :before
         | 
| 417 380 | 
             
                  else
         | 
| 418 | 
            -
                     | 
| 381 | 
            +
                    :after
         | 
| 419 382 | 
             
                  end
         | 
| 420 | 
            -
                elsif currency.symbol_first?
         | 
| 421 | 
            -
                  :before
         | 
| 422 | 
            -
                else
         | 
| 423 | 
            -
                  :after
         | 
| 424 383 | 
             
                end
         | 
| 425 384 | 
             
              end
         | 
| 426 385 | 
             
            end
         | 
| @@ -0,0 +1,71 @@ | |
| 1 | 
            +
            # encoding: UTF-8
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            class Money
         | 
| 4 | 
            +
              class FormattingRules
         | 
| 5 | 
            +
                def initialize(currency, *raw_rules)
         | 
| 6 | 
            +
                  @currency = currency
         | 
| 7 | 
            +
             | 
| 8 | 
            +
                  # support for old format parameters
         | 
| 9 | 
            +
                  @rules = normalize_formatting_rules(raw_rules)
         | 
| 10 | 
            +
             | 
| 11 | 
            +
                  @rules = default_formatting_rules.merge(@rules)
         | 
| 12 | 
            +
                  @rules = localize_formatting_rules(@rules)
         | 
| 13 | 
            +
                  @rules = translate_formatting_rules(@rules) if @rules[:translate]
         | 
| 14 | 
            +
                end
         | 
| 15 | 
            +
             | 
| 16 | 
            +
                def [](key)
         | 
| 17 | 
            +
                  @rules[key]
         | 
| 18 | 
            +
                end
         | 
| 19 | 
            +
             | 
| 20 | 
            +
                def has_key?(key)
         | 
| 21 | 
            +
                  @rules.has_key? key
         | 
| 22 | 
            +
                end
         | 
| 23 | 
            +
             | 
| 24 | 
            +
                private
         | 
| 25 | 
            +
             | 
| 26 | 
            +
                attr_reader :currency
         | 
| 27 | 
            +
             | 
| 28 | 
            +
                # Cleans up formatting rules.
         | 
| 29 | 
            +
                #
         | 
| 30 | 
            +
                # @param [Hash] rules
         | 
| 31 | 
            +
                #
         | 
| 32 | 
            +
                # @return [Hash]
         | 
| 33 | 
            +
                def normalize_formatting_rules(rules)
         | 
| 34 | 
            +
                  if rules.size == 0
         | 
| 35 | 
            +
                    rules = {}
         | 
| 36 | 
            +
                  elsif rules.size == 1
         | 
| 37 | 
            +
                    rules = rules.pop
         | 
| 38 | 
            +
                    rules = { rules => true } if rules.is_a?(Symbol)
         | 
| 39 | 
            +
                  end
         | 
| 40 | 
            +
                  if !rules.include?(:decimal_mark) && rules.include?(:separator)
         | 
| 41 | 
            +
                    rules[:decimal_mark] = rules[:separator]
         | 
| 42 | 
            +
                  end
         | 
| 43 | 
            +
                  if !rules.include?(:thousands_separator) && rules.include?(:delimiter)
         | 
| 44 | 
            +
                    rules[:thousands_separator] = rules[:delimiter]
         | 
| 45 | 
            +
                  end
         | 
| 46 | 
            +
                  rules
         | 
| 47 | 
            +
                end
         | 
| 48 | 
            +
             | 
| 49 | 
            +
                def default_formatting_rules
         | 
| 50 | 
            +
                  Money.default_formatting_rules || {}
         | 
| 51 | 
            +
                end
         | 
| 52 | 
            +
             | 
| 53 | 
            +
                def translate_formatting_rules(rules)
         | 
| 54 | 
            +
                  begin
         | 
| 55 | 
            +
                    rules[:symbol] = I18n.t currency.iso_code, :scope => "number.currency.symbol", :raise => true
         | 
| 56 | 
            +
                  rescue I18n::MissingTranslationData
         | 
| 57 | 
            +
                    # Do nothing
         | 
| 58 | 
            +
                  end
         | 
| 59 | 
            +
                  rules
         | 
| 60 | 
            +
                end
         | 
| 61 | 
            +
             | 
| 62 | 
            +
                def localize_formatting_rules(rules)
         | 
| 63 | 
            +
                  if currency.iso_code == "JPY" && I18n.locale == :ja
         | 
| 64 | 
            +
                    rules[:symbol] = "円" unless rules[:symbol] == false
         | 
| 65 | 
            +
                    rules[:symbol_position] = :after
         | 
| 66 | 
            +
                    rules[:symbol_after_without_space] = true
         | 
| 67 | 
            +
                  end
         | 
| 68 | 
            +
                  rules
         | 
| 69 | 
            +
                end
         | 
| 70 | 
            +
              end
         | 
| 71 | 
            +
            end
         | 
    
        data/lib/money/money.rb
    CHANGED
    
    | @@ -3,7 +3,7 @@ require "money/bank/variable_exchange" | |
| 3 3 | 
             
            require "money/bank/single_currency"
         | 
| 4 4 | 
             
            require "money/money/arithmetic"
         | 
| 5 5 | 
             
            require "money/money/constructors"
         | 
| 6 | 
            -
            require "money/money/ | 
| 6 | 
            +
            require "money/money/formatter"
         | 
| 7 7 |  | 
| 8 8 | 
             
            # "Money is any object or record that is generally accepted as payment for
         | 
| 9 9 | 
             
            # goods and services and repayment of debts in a given socio-economic context
         | 
| @@ -17,7 +17,6 @@ require "money/money/formatting" | |
| 17 17 | 
             
            class Money
         | 
| 18 18 | 
             
              include Comparable
         | 
| 19 19 | 
             
              include Money::Arithmetic
         | 
| 20 | 
            -
              include Money::Formatting
         | 
| 21 20 | 
             
              extend Constructors
         | 
| 22 21 |  | 
| 23 22 | 
             
              # Raised when smallest denomination of a currency is not defined
         | 
| @@ -177,7 +176,7 @@ class Money | |
| 177 176 | 
             
              #
         | 
| 178 177 | 
             
              # @example
         | 
| 179 178 | 
             
              #   fee = Money.rounding_mode(BigDecimal::ROUND_HALF_UP) do
         | 
| 180 | 
            -
              #     Money.new(1200) * BigDecimal | 
| 179 | 
            +
              #     Money.new(1200) * BigDecimal('0.029')
         | 
| 181 180 | 
             
              #   end
         | 
| 182 181 | 
             
              def self.rounding_mode(mode=nil)
         | 
| 183 182 | 
             
                if mode.nil?
         | 
| @@ -271,7 +270,7 @@ class Money | |
| 271 270 | 
             
              # @return [BigDecimal]
         | 
| 272 271 | 
             
              #
         | 
| 273 272 | 
             
              # @example
         | 
| 274 | 
            -
              #   Money.new(1_00, "USD").dollars   # => BigDecimal | 
| 273 | 
            +
              #   Money.new(1_00, "USD").dollars   # => BigDecimal("1.00")
         | 
| 275 274 | 
             
              #
         | 
| 276 275 | 
             
              # @see #amount
         | 
| 277 276 | 
             
              # @see #to_d
         | 
| @@ -286,7 +285,7 @@ class Money | |
| 286 285 | 
             
              # @return [BigDecimal]
         | 
| 287 286 | 
             
              #
         | 
| 288 287 | 
             
              # @example
         | 
| 289 | 
            -
              #   Money.new(1_00, "USD").amount    # => BigDecimal | 
| 288 | 
            +
              #   Money.new(1_00, "USD").amount    # => BigDecimal("1.00")
         | 
| 290 289 | 
             
              #
         | 
| 291 290 | 
             
              # @see #to_d
         | 
| 292 291 | 
             
              # @see #fractional
         | 
| @@ -358,10 +357,10 @@ class Money | |
| 358 357 | 
             
                        if fraction == ""
         | 
| 359 358 | 
             
                          unit
         | 
| 360 359 | 
             
                        else
         | 
| 361 | 
            -
                          "#{unit}#{decimal_mark}#{fraction}"
         | 
| 360 | 
            +
                          "#{unit}#{currency.decimal_mark}#{fraction}"
         | 
| 362 361 | 
             
                        end
         | 
| 363 362 | 
             
                      else
         | 
| 364 | 
            -
                        "#{unit}#{decimal_mark}#{pad_subunit(subunit)}#{fraction}"
         | 
| 363 | 
            +
                        "#{unit}#{currency.decimal_mark}#{pad_subunit(subunit)}#{fraction}"
         | 
| 365 364 | 
             
                      end
         | 
| 366 365 |  | 
| 367 366 | 
             
                fractional < 0 ? "-#{str}" : str
         | 
| @@ -372,7 +371,7 @@ class Money | |
| 372 371 | 
             
              # @return [BigDecimal]
         | 
| 373 372 | 
             
              #
         | 
| 374 373 | 
             
              # @example
         | 
| 375 | 
            -
              #   Money.us_dollar(1_00).to_d #=> BigDecimal | 
| 374 | 
            +
              #   Money.us_dollar(1_00).to_d #=> BigDecimal("1.00")
         | 
| 376 375 | 
             
              def to_d
         | 
| 377 376 | 
             
                as_d(fractional) / as_d(currency.subunit_to_unit)
         | 
| 378 377 | 
             
              end
         | 
| @@ -478,22 +477,17 @@ class Money | |
| 478 477 | 
             
              # be distributed round-robin amongst the parties. This means that parties
         | 
| 479 478 | 
             
              # listed first will likely receive more pennies than ones that are listed later
         | 
| 480 479 | 
             
              #
         | 
| 481 | 
            -
              # @param [Array<Numeric>] splits [ | 
| 480 | 
            +
              # @param [Array<Numeric>] splits [2, 1, 1] to give twice as much to party1 as party2 or party3
         | 
| 481 | 
            +
              #   which results in 50% of the cash to party1, 25% to party2, and 25% to party3.
         | 
| 482 482 | 
             
              #
         | 
| 483 483 | 
             
              # @return [Array<Money>]
         | 
| 484 484 | 
             
              #
         | 
| 485 485 | 
             
              # @example
         | 
| 486 486 | 
             
              #   Money.new(5,   "USD").allocate([0.3, 0.7])         #=> [Money.new(2), Money.new(3)]
         | 
| 487 | 
            -
              #   Money.new(100, "USD").allocate([ | 
| 487 | 
            +
              #   Money.new(100, "USD").allocate([1, 1, 1]) #=> [Money.new(34), Money.new(33), Money.new(33)]
         | 
| 488 488 | 
             
              #
         | 
| 489 489 | 
             
              def allocate(splits)
         | 
| 490 | 
            -
                 | 
| 491 | 
            -
             | 
| 492 | 
            -
                if (allocations - BigDecimal("1")) > Float::EPSILON
         | 
| 493 | 
            -
                  raise ArgumentError, "splits add to more then 100%"
         | 
| 494 | 
            -
                end
         | 
| 495 | 
            -
             | 
| 496 | 
            -
                amounts, left_over = amounts_from_splits(allocations, splits)
         | 
| 490 | 
            +
                amounts, left_over = amounts_from_splits(splits)
         | 
| 497 491 |  | 
| 498 492 | 
             
                unless self.class.infinite_precision
         | 
| 499 493 | 
             
                  delta = left_over > 0 ? 1 : -1
         | 
| @@ -537,21 +531,47 @@ class Money | |
| 537 531 | 
             
              # @see
         | 
| 538 532 | 
             
              #   Money.infinite_precision
         | 
| 539 533 | 
             
              #
         | 
| 540 | 
            -
              def round(rounding_mode = self.class.rounding_mode)
         | 
| 534 | 
            +
              def round(rounding_mode = self.class.rounding_mode, rounding_precision = 0)
         | 
| 541 535 | 
             
                if self.class.infinite_precision
         | 
| 542 | 
            -
                  self.class.new(fractional.round( | 
| 536 | 
            +
                  self.class.new(fractional.round(rounding_precision, rounding_mode), self.currency)
         | 
| 543 537 | 
             
                else
         | 
| 544 538 | 
             
                  self
         | 
| 545 539 | 
             
                end
         | 
| 546 540 | 
             
              end
         | 
| 547 541 |  | 
| 542 | 
            +
              # Creates a formatted price string according to several rules.
         | 
| 543 | 
            +
              #
         | 
| 544 | 
            +
              # @param [Hash] See Money::Formatter for the list of formatting options
         | 
| 545 | 
            +
              #
         | 
| 546 | 
            +
              # @return [String]
         | 
| 547 | 
            +
              #
         | 
| 548 | 
            +
              def format(*rules)
         | 
| 549 | 
            +
                Money::Formatter.new(self, *rules).to_s
         | 
| 550 | 
            +
              end
         | 
| 551 | 
            +
             | 
| 552 | 
            +
              # Returns a thousands separator according to the locale
         | 
| 553 | 
            +
              #
         | 
| 554 | 
            +
              # @return [String]
         | 
| 555 | 
            +
              #
         | 
| 556 | 
            +
              def thousands_separator
         | 
| 557 | 
            +
                Money::Formatter.new(self, {}).thousands_separator
         | 
| 558 | 
            +
              end
         | 
| 559 | 
            +
             | 
| 560 | 
            +
              # Returns a decimal mark according to the locale
         | 
| 561 | 
            +
              #
         | 
| 562 | 
            +
              # @return [String]
         | 
| 563 | 
            +
              #
         | 
| 564 | 
            +
              def decimal_mark
         | 
| 565 | 
            +
                Money::Formatter.new(self, {}).decimal_mark
         | 
| 566 | 
            +
              end
         | 
| 567 | 
            +
             | 
| 548 568 | 
             
              private
         | 
| 549 569 |  | 
| 550 570 | 
             
              def as_d(num)
         | 
| 551 571 | 
             
                if num.respond_to?(:to_d)
         | 
| 552 572 | 
             
                  num.is_a?(Rational) ? num.to_d(self.class.conversion_precision) : num.to_d
         | 
| 553 573 | 
             
                else
         | 
| 554 | 
            -
                  BigDecimal | 
| 574 | 
            +
                  BigDecimal(num.to_s.empty? ? 0 : num.to_s)
         | 
| 555 575 | 
             
                end
         | 
| 556 576 | 
             
              end
         | 
| 557 577 |  | 
| @@ -578,16 +598,11 @@ class Money | |
| 578 598 | 
             
              end
         | 
| 579 599 |  | 
| 580 600 | 
             
              def pad_subunit(subunit)
         | 
| 581 | 
            -
                 | 
| 582 | 
            -
                padding = "0" * cnt
         | 
| 583 | 
            -
                "#{padding}#{subunit}"[-1 * cnt, cnt]
         | 
| 584 | 
            -
              end
         | 
| 585 | 
            -
             | 
| 586 | 
            -
              def allocations_from_splits(splits)
         | 
| 587 | 
            -
                splits.inject(0) { |sum, n| sum + n }
         | 
| 601 | 
            +
                subunit.rjust(currency.decimal_places, '0')
         | 
| 588 602 | 
             
              end
         | 
| 589 603 |  | 
| 590 | 
            -
              def amounts_from_splits( | 
| 604 | 
            +
              def amounts_from_splits(splits)
         | 
| 605 | 
            +
                allocations = splits.inject(0, :+)
         | 
| 591 606 | 
             
                left_over = fractional
         | 
| 592 607 |  | 
| 593 608 | 
             
                amounts = splits.map do |ratio|
         | 
    
        data/lib/money/version.rb
    CHANGED
    
    
    
        data/money.gemspec
    CHANGED
    
    | @@ -14,12 +14,12 @@ Gem::Specification.new do |s| | |
| 14 14 | 
             
              s.description = "A Ruby Library for dealing with money and currency conversion."
         | 
| 15 15 | 
             
              s.license     = "MIT"
         | 
| 16 16 |  | 
| 17 | 
            -
              s.add_dependency 'i18n', [">= 0.6.4", '< 1. | 
| 17 | 
            +
              s.add_dependency 'i18n', [">= 0.6.4", '< 1.1']
         | 
| 18 18 |  | 
| 19 19 | 
             
              s.add_development_dependency "bundler", "~> 1.3"
         | 
| 20 20 | 
             
              s.add_development_dependency "rake"
         | 
| 21 21 | 
             
              s.add_development_dependency "rspec", "~> 3.4.0"
         | 
| 22 | 
            -
              s.add_development_dependency "yard", "~> 0. | 
| 22 | 
            +
              s.add_development_dependency "yard", "~> 0.9.11"
         | 
| 23 23 | 
             
              s.add_development_dependency "kramdown", "~> 1.1"
         | 
| 24 24 |  | 
| 25 25 | 
             
              s.files         = `git ls-files`.split($/)
         | 
    
        data/spec/currency_spec.rb
    CHANGED
    
    | @@ -115,6 +115,32 @@ class Money | |
| 115 115 | 
             
                end
         | 
| 116 116 |  | 
| 117 117 |  | 
| 118 | 
            +
                describe ".inherit" do
         | 
| 119 | 
            +
                  after do
         | 
| 120 | 
            +
                    Currency.unregister(iso_code: "XXX") if Currency.find("XXX")
         | 
| 121 | 
            +
                    Currency.unregister(iso_code: "YYY") if Currency.find("YYY")
         | 
| 122 | 
            +
                  end
         | 
| 123 | 
            +
             | 
| 124 | 
            +
                  it "inherit a new currency" do
         | 
| 125 | 
            +
                    Currency.register(
         | 
| 126 | 
            +
                      iso_code: "XXX",
         | 
| 127 | 
            +
                      name: "Golden Doubloon",
         | 
| 128 | 
            +
                      symbol: "%",
         | 
| 129 | 
            +
                      subunit_to_unit: 100
         | 
| 130 | 
            +
                    )
         | 
| 131 | 
            +
                    Currency.inherit("XXX",
         | 
| 132 | 
            +
                      iso_code: "YYY",
         | 
| 133 | 
            +
                      symbol: "@"
         | 
| 134 | 
            +
                    )
         | 
| 135 | 
            +
                    new_currency = Currency.find("YYY")
         | 
| 136 | 
            +
                    expect(new_currency).not_to be_nil
         | 
| 137 | 
            +
                    expect(new_currency.name).to eq "Golden Doubloon"
         | 
| 138 | 
            +
                    expect(new_currency.symbol).to eq "@"
         | 
| 139 | 
            +
                    expect(new_currency.subunit_to_unit).to eq 100
         | 
| 140 | 
            +
                  end
         | 
| 141 | 
            +
                end
         | 
| 142 | 
            +
             | 
| 143 | 
            +
             | 
| 118 144 | 
             
                describe ".unregister" do
         | 
| 119 145 | 
             
                  it "unregisters a currency" do
         | 
| 120 146 | 
             
                    Currency.register(iso_code: "XXX")
         | 
| @@ -12,6 +12,8 @@ describe Money do | |
| 12 12 | 
             
                  special_money_class = Class.new(Money)
         | 
| 13 13 | 
             
                  expect(- special_money_class.new(10_00)).to be_a special_money_class
         | 
| 14 14 | 
             
                end
         | 
| 15 | 
            +
             | 
| 16 | 
            +
                it_behaves_like 'instance with custom bank', :-@
         | 
| 15 17 | 
             
              end
         | 
| 16 18 |  | 
| 17 19 | 
             
              describe "#==" do
         | 
| @@ -49,7 +51,7 @@ describe Money do | |
| 49 51 | 
             
                it 'allows comparison with zero' do
         | 
| 50 52 | 
             
                  expect(Money.new(0, :usd)).to eq 0
         | 
| 51 53 | 
             
                  expect(Money.new(0, :usd)).to eq 0.0
         | 
| 52 | 
            -
                  expect(Money.new(0, :usd)).to eq BigDecimal | 
| 54 | 
            +
                  expect(Money.new(0, :usd)).to eq BigDecimal(0)
         | 
| 53 55 | 
             
                  expect(Money.new(1, :usd)).to_not eq 0
         | 
| 54 56 | 
             
                end
         | 
| 55 57 |  | 
| @@ -215,6 +217,8 @@ describe Money do | |
| 215 217 | 
             
                  special_money_class = Class.new(Money)
         | 
| 216 218 | 
             
                  expect(special_money_class.new(10_00, "USD") + Money.new(90, "USD")).to be_a special_money_class
         | 
| 217 219 | 
             
                end
         | 
| 220 | 
            +
             | 
| 221 | 
            +
                it_behaves_like 'instance with custom bank', :+, Money.new(1)
         | 
| 218 222 | 
             
              end
         | 
| 219 223 |  | 
| 220 224 | 
             
              describe "#-" do
         | 
| @@ -236,6 +240,8 @@ describe Money do | |
| 236 240 | 
             
                  special_money_class = Class.new(Money)
         | 
| 237 241 | 
             
                  expect(special_money_class.new(10_00, "USD") - Money.new(90, "USD")).to be_a special_money_class
         | 
| 238 242 | 
             
                end
         | 
| 243 | 
            +
             | 
| 244 | 
            +
                it_behaves_like 'instance with custom bank', :-, Money.new(1)
         | 
| 239 245 | 
             
              end
         | 
| 240 246 |  | 
| 241 247 | 
             
              describe "#*" do
         | 
| @@ -267,6 +273,8 @@ describe Money do | |
| 267 273 | 
             
                  special_money_class = Class.new(Money)
         | 
| 268 274 | 
             
                  expect(special_money_class.new(10_00, "USD") * 2).to be_a special_money_class
         | 
| 269 275 | 
             
                end
         | 
| 276 | 
            +
             | 
| 277 | 
            +
                it_behaves_like 'instance with custom bank', :*, 1
         | 
| 270 278 | 
             
              end
         | 
| 271 279 |  | 
| 272 280 | 
             
              describe "#/" do
         | 
| @@ -363,6 +371,8 @@ describe Money do | |
| 363 371 | 
             
                    end
         | 
| 364 372 | 
             
                  end
         | 
| 365 373 | 
             
                end
         | 
| 374 | 
            +
             | 
| 375 | 
            +
                it_behaves_like 'instance with custom bank', :/, 1
         | 
| 366 376 | 
             
              end
         | 
| 367 377 |  | 
| 368 378 | 
             
              describe "#div" do
         | 
| @@ -479,6 +489,9 @@ describe Money do | |
| 479 489 | 
             
                  special_money_class = Class.new(Money)
         | 
| 480 490 | 
             
                  expect(special_money_class.new(10_00, "USD").divmod(special_money_class.new(4_00)).last).to be_a special_money_class
         | 
| 481 491 | 
             
                end
         | 
| 492 | 
            +
             | 
| 493 | 
            +
                it_behaves_like 'instance with custom bank', :divmod, Money.new(1)
         | 
| 494 | 
            +
                it_behaves_like 'instance with custom bank', :divmod, 1
         | 
| 482 495 | 
             
              end
         | 
| 483 496 |  | 
| 484 497 | 
             
              describe "#modulo" do
         | 
| @@ -571,6 +584,8 @@ describe Money do | |
| 571 584 | 
             
                    expect(t[:a].remainder(t[:b])).to eq t[:c]
         | 
| 572 585 | 
             
                  end
         | 
| 573 586 | 
             
                end
         | 
| 587 | 
            +
             | 
| 588 | 
            +
                it_behaves_like 'instance with custom bank', :remainder, -1
         | 
| 574 589 | 
             
              end
         | 
| 575 590 |  | 
| 576 591 | 
             
              describe "#abs" do
         | 
| @@ -584,6 +599,8 @@ describe Money do | |
| 584 599 | 
             
                  special_money_class = Class.new(Money)
         | 
| 585 600 | 
             
                  expect(special_money_class.new(-1).abs).to be_a special_money_class
         | 
| 586 601 | 
             
                end
         | 
| 602 | 
            +
             | 
| 603 | 
            +
                it_behaves_like 'instance with custom bank', :abs
         | 
| 587 604 | 
             
              end
         | 
| 588 605 |  | 
| 589 606 | 
             
              describe "#zero?" do
         | 
| @@ -637,6 +654,16 @@ describe Money do | |
| 637 654 | 
             
                  }.to raise_exception(TypeError)
         | 
| 638 655 | 
             
                end
         | 
| 639 656 |  | 
| 657 | 
            +
                it "allows subtraction from numeric zero" do
         | 
| 658 | 
            +
                  result = 0 - Money.new(4, 'USD')
         | 
| 659 | 
            +
                  expect(result).to eq Money.new(-4, 'USD')
         | 
| 660 | 
            +
                end
         | 
| 661 | 
            +
             | 
| 662 | 
            +
                it "allows addition from numeric zero" do
         | 
| 663 | 
            +
                  result = 0 + Money.new(4, 'USD')
         | 
| 664 | 
            +
                  expect(result).to eq Money.new(4, 'USD')
         | 
| 665 | 
            +
                end
         | 
| 666 | 
            +
             | 
| 640 667 | 
             
                it "treats multiplication as commutative" do
         | 
| 641 668 | 
             
                  expect {
         | 
| 642 669 | 
             
                    2 * Money.new(2, 'USD')
         | 
| @@ -265,7 +265,7 @@ describe Money, "formatting" do | |
| 265 265 | 
             
                    expect(Money.new(10000, "VUV").format(:no_cents_if_whole => true, :symbol => false)).to eq "10,000"
         | 
| 266 266 | 
             
                    expect(Money.new(10034, "VUV").format(:no_cents_if_whole => true, :symbol => false)).to eq "10,034"
         | 
| 267 267 | 
             
                    expect(Money.new(10000, "MGA").format(:no_cents_if_whole => true, :symbol => false)).to eq "2,000"
         | 
| 268 | 
            -
                    expect(Money.new(10034, "MGA").format(:no_cents_if_whole => true, :symbol => false)).to eq "2,006. | 
| 268 | 
            +
                    expect(Money.new(10034, "MGA").format(:no_cents_if_whole => true, :symbol => false)).to eq "2,006.8"
         | 
| 269 269 | 
             
                    expect(Money.new(10000, "VND").format(:no_cents_if_whole => true, :symbol => false)).to eq "10.000"
         | 
| 270 270 | 
             
                    expect(Money.new(10034, "VND").format(:no_cents_if_whole => true, :symbol => false)).to eq "10.034"
         | 
| 271 271 | 
             
                    expect(Money.new(10000, "USD").format(:no_cents_if_whole => true, :symbol => false)).to eq "100"
         | 
| @@ -278,7 +278,7 @@ describe Money, "formatting" do | |
| 278 278 | 
             
                    expect(Money.new(10000, "VUV").format(:no_cents_if_whole => false, :symbol => false)).to eq "10,000"
         | 
| 279 279 | 
             
                    expect(Money.new(10034, "VUV").format(:no_cents_if_whole => false, :symbol => false)).to eq "10,034"
         | 
| 280 280 | 
             
                    expect(Money.new(10000, "MGA").format(:no_cents_if_whole => false, :symbol => false)).to eq "2,000.0"
         | 
| 281 | 
            -
                    expect(Money.new(10034, "MGA").format(:no_cents_if_whole => false, :symbol => false)).to eq "2,006. | 
| 281 | 
            +
                    expect(Money.new(10034, "MGA").format(:no_cents_if_whole => false, :symbol => false)).to eq "2,006.8"
         | 
| 282 282 | 
             
                    expect(Money.new(10000, "VND").format(:no_cents_if_whole => false, :symbol => false)).to eq "10.000"
         | 
| 283 283 | 
             
                    expect(Money.new(10034, "VND").format(:no_cents_if_whole => false, :symbol => false)).to eq "10.034"
         | 
| 284 284 | 
             
                    expect(Money.new(10000, "USD").format(:no_cents_if_whole => false, :symbol => false)).to eq "100.00"
         | 
| @@ -405,6 +405,11 @@ describe Money, "formatting" do | |
| 405 405 | 
             
                    expect(Money.new(1000000000, 'INDIAN_BAR').format(:south_asian_number_formatting => true, :symbol => false)).to eq "1,00,000.0000"
         | 
| 406 406 | 
             
                    expect(Money.new(10000000).format(:south_asian_number_formatting => true)).to eq "$1,00,000.00"
         | 
| 407 407 | 
             
                  end
         | 
| 408 | 
            +
             | 
| 409 | 
            +
                  specify "(:south_asian_number_formatting => true and no_cents_if_whole => true) works as documented" do
         | 
| 410 | 
            +
                    expect(Money.new(10000000, 'INR').format(:south_asian_number_formatting => true, :symbol => false, :no_cents_if_whole => true)).to eq "1,00,000"
         | 
| 411 | 
            +
                    expect(Money.new(1000000000, 'INDIAN_BAR').format(:south_asian_number_formatting => true, :symbol => false, :no_cents_if_whole => true)).to eq "1,00,000"
         | 
| 412 | 
            +
                  end
         | 
| 408 413 | 
             
                end
         | 
| 409 414 |  | 
| 410 415 | 
             
                describe ":thousands_separator option" do
         | 
| @@ -556,23 +561,23 @@ describe Money, "formatting" do | |
| 556 561 |  | 
| 557 562 | 
             
                describe ":rounded_infinite_precision option", :infinite_precision do
         | 
| 558 563 | 
             
                  it "does round fractional when set to true" do
         | 
| 559 | 
            -
                    expect(Money.new(BigDecimal | 
| 560 | 
            -
                    expect(Money.new(BigDecimal | 
| 561 | 
            -
                    expect(Money.new(BigDecimal | 
| 562 | 
            -
                    expect(Money.new(BigDecimal | 
| 563 | 
            -
                    expect(Money.new(BigDecimal | 
| 564 | 
            -
                    expect(Money.new(BigDecimal | 
| 565 | 
            -
                    expect(Money.new(BigDecimal | 
| 564 | 
            +
                    expect(Money.new(BigDecimal('12.1'), "USD").format(:rounded_infinite_precision => true)).to eq "$0.12"
         | 
| 565 | 
            +
                    expect(Money.new(BigDecimal('12.5'), "USD").format(:rounded_infinite_precision => true)).to eq "$0.13"
         | 
| 566 | 
            +
                    expect(Money.new(BigDecimal('123.1'), "BHD").format(:rounded_infinite_precision => true)).to eq "ب.د0.123"
         | 
| 567 | 
            +
                    expect(Money.new(BigDecimal('123.5'), "BHD").format(:rounded_infinite_precision => true)).to eq "ب.د0.124"
         | 
| 568 | 
            +
                    expect(Money.new(BigDecimal('100.1'), "USD").format(:rounded_infinite_precision => true)).to eq "$1.00"
         | 
| 569 | 
            +
                    expect(Money.new(BigDecimal('109.5'), "USD").format(:rounded_infinite_precision => true)).to eq "$1.10"
         | 
| 570 | 
            +
                    expect(Money.new(BigDecimal('1.7'), "MGA").format(:rounded_infinite_precision => true)).to eq "Ar0.4"
         | 
| 566 571 | 
             
                  end
         | 
| 567 572 |  | 
| 568 573 | 
             
                  it "does not round fractional when set to false" do
         | 
| 569 | 
            -
                    expect(Money.new(BigDecimal | 
| 570 | 
            -
                    expect(Money.new(BigDecimal | 
| 571 | 
            -
                    expect(Money.new(BigDecimal | 
| 572 | 
            -
                    expect(Money.new(BigDecimal | 
| 573 | 
            -
                    expect(Money.new(BigDecimal | 
| 574 | 
            -
                    expect(Money.new(BigDecimal | 
| 575 | 
            -
                    expect(Money.new(BigDecimal | 
| 574 | 
            +
                    expect(Money.new(BigDecimal('12.1'), "USD").format(:rounded_infinite_precision => false)).to eq "$0.121"
         | 
| 575 | 
            +
                    expect(Money.new(BigDecimal('12.5'), "USD").format(:rounded_infinite_precision => false)).to eq "$0.125"
         | 
| 576 | 
            +
                    expect(Money.new(BigDecimal('123.1'), "BHD").format(:rounded_infinite_precision => false)).to eq "ب.د0.1231"
         | 
| 577 | 
            +
                    expect(Money.new(BigDecimal('123.5'), "BHD").format(:rounded_infinite_precision => false)).to eq "ب.د0.1235"
         | 
| 578 | 
            +
                    expect(Money.new(BigDecimal('100.1'), "USD").format(:rounded_infinite_precision => false)).to eq "$1.001"
         | 
| 579 | 
            +
                    expect(Money.new(BigDecimal('109.5'), "USD").format(:rounded_infinite_precision => false)).to eq "$1.095"
         | 
| 580 | 
            +
                    expect(Money.new(BigDecimal('1.7'), "MGA").format(:rounded_infinite_precision => false)).to eq "Ar0.34"
         | 
| 576 581 | 
             
                  end
         | 
| 577 582 |  | 
| 578 583 | 
             
                  describe "with i18n = false" do
         | 
| @@ -585,13 +590,13 @@ describe Money, "formatting" do | |
| 585 590 | 
             
                    end
         | 
| 586 591 |  | 
| 587 592 | 
             
                    it 'does round fractional when set to true' do
         | 
| 588 | 
            -
                      expect(Money.new(BigDecimal | 
| 589 | 
            -
                      expect(Money.new(BigDecimal | 
| 590 | 
            -
                      expect(Money.new(BigDecimal | 
| 591 | 
            -
                      expect(Money.new(BigDecimal | 
| 593 | 
            +
                      expect(Money.new(BigDecimal('12.1'), "EUR").format(:rounded_infinite_precision => true)).to eq "€0,12"
         | 
| 594 | 
            +
                      expect(Money.new(BigDecimal('12.5'), "EUR").format(:rounded_infinite_precision => true)).to eq "€0,13"
         | 
| 595 | 
            +
                      expect(Money.new(BigDecimal('100.1'), "EUR").format(:rounded_infinite_precision => true)).to eq "€1,00"
         | 
| 596 | 
            +
                      expect(Money.new(BigDecimal('109.5'), "EUR").format(:rounded_infinite_precision => true)).to eq "€1,10"
         | 
| 592 597 |  | 
| 593 | 
            -
                      expect(Money.new(BigDecimal | 
| 594 | 
            -
                      expect(Money.new(BigDecimal | 
| 598 | 
            +
                      expect(Money.new(BigDecimal('100012.1'), "EUR").format(:rounded_infinite_precision => true)).to eq "€1.000,12"
         | 
| 599 | 
            +
                      expect(Money.new(BigDecimal('100012.5'), "EUR").format(:rounded_infinite_precision => true)).to eq "€1.000,13"
         | 
| 595 600 | 
             
                    end
         | 
| 596 601 | 
             
                  end
         | 
| 597 602 |  | 
| @@ -612,13 +617,13 @@ describe Money, "formatting" do | |
| 612 617 | 
             
                    end
         | 
| 613 618 |  | 
| 614 619 | 
             
                    it 'does round fractional when set to true' do
         | 
| 615 | 
            -
                      expect(Money.new(BigDecimal | 
| 616 | 
            -
                      expect(Money.new(BigDecimal | 
| 617 | 
            -
                      expect(Money.new(BigDecimal | 
| 618 | 
            -
                      expect(Money.new(BigDecimal | 
| 619 | 
            -
                      expect(Money.new(BigDecimal | 
| 620 | 
            -
                      expect(Money.new(BigDecimal | 
| 621 | 
            -
                      expect(Money.new(BigDecimal | 
| 620 | 
            +
                      expect(Money.new(BigDecimal('12.1'), "USD").format(:rounded_infinite_precision => true)).to eq "$0,12"
         | 
| 621 | 
            +
                      expect(Money.new(BigDecimal('12.5'), "USD").format(:rounded_infinite_precision => true)).to eq "$0,13"
         | 
| 622 | 
            +
                      expect(Money.new(BigDecimal('123.1'), "BHD").format(:rounded_infinite_precision => true)).to eq "ب.د0,123"
         | 
| 623 | 
            +
                      expect(Money.new(BigDecimal('123.5'), "BHD").format(:rounded_infinite_precision => true)).to eq "ب.د0,124"
         | 
| 624 | 
            +
                      expect(Money.new(BigDecimal('100.1'), "USD").format(:rounded_infinite_precision => true)).to eq "$1,00"
         | 
| 625 | 
            +
                      expect(Money.new(BigDecimal('109.5'), "USD").format(:rounded_infinite_precision => true)).to eq "$1,10"
         | 
| 626 | 
            +
                      expect(Money.new(BigDecimal('1'), "MGA").format(:rounded_infinite_precision => true)).to eq "Ar0,2"
         | 
| 622 627 | 
             
                    end
         | 
| 623 628 | 
             
                  end
         | 
| 624 629 | 
             
                end
         | 
    
        data/spec/money_spec.rb
    CHANGED
    
    | @@ -591,6 +591,18 @@ YAML | |
| 591 591 | 
             
                  expect(moneys[1]).to eq Money.us_dollar(3)
         | 
| 592 592 | 
             
                end
         | 
| 593 593 |  | 
| 594 | 
            +
                it "handles small splits" do
         | 
| 595 | 
            +
                  moneys = Money.us_dollar(5).allocate([0.03, 0.07])
         | 
| 596 | 
            +
                  expect(moneys[0]).to eq Money.us_dollar(2)
         | 
| 597 | 
            +
                  expect(moneys[1]).to eq Money.us_dollar(3)
         | 
| 598 | 
            +
                end
         | 
| 599 | 
            +
             | 
| 600 | 
            +
                it "handles large splits" do
         | 
| 601 | 
            +
                  moneys = Money.us_dollar(5).allocate([3, 7])
         | 
| 602 | 
            +
                  expect(moneys[0]).to eq Money.us_dollar(2)
         | 
| 603 | 
            +
                  expect(moneys[1]).to eq Money.us_dollar(3)
         | 
| 604 | 
            +
                end
         | 
| 605 | 
            +
             | 
| 594 606 | 
             
                it "does not lose pennies" do
         | 
| 595 607 | 
             
                  moneys = Money.us_dollar(100).allocate([0.333, 0.333, 0.333])
         | 
| 596 608 | 
             
                  expect(moneys[0].cents).to eq 34
         | 
| @@ -607,7 +619,7 @@ YAML | |
| 607 619 | 
             
                end
         | 
| 608 620 |  | 
| 609 621 | 
             
                it "handles mixed split types" do
         | 
| 610 | 
            -
                  splits = [Rational(1, 4), 0.25, 0.25, BigDecimal | 
| 622 | 
            +
                  splits = [Rational(1, 4), 0.25, 0.25, BigDecimal('0.25')]
         | 
| 611 623 | 
             
                  moneys = Money.us_dollar(100).allocate(splits)
         | 
| 612 624 | 
             
                  moneys.each do |money|
         | 
| 613 625 | 
             
                    expect(money.cents).to eq 25
         | 
| @@ -618,9 +630,9 @@ YAML | |
| 618 630 | 
             
                  it "does not lose pennies" do
         | 
| 619 631 | 
             
                    moneys = Money.us_dollar(-100).allocate([0.333, 0.333, 0.333])
         | 
| 620 632 |  | 
| 621 | 
            -
                    expect(moneys[0].cents).to eq | 
| 622 | 
            -
                    expect(moneys[1].cents).to eq | 
| 623 | 
            -
                    expect(moneys[2].cents).to eq | 
| 633 | 
            +
                    expect(moneys[0].cents).to eq(-34)
         | 
| 634 | 
            +
                    expect(moneys[1].cents).to eq(-33)
         | 
| 635 | 
            +
                    expect(moneys[2].cents).to eq(-33)
         | 
| 624 636 | 
             
                  end
         | 
| 625 637 |  | 
| 626 638 | 
             
                  it "allocates the same way as positive amounts" do
         | 
| @@ -631,10 +643,6 @@ YAML | |
| 631 643 | 
             
                  end
         | 
| 632 644 | 
             
                end
         | 
| 633 645 |  | 
| 634 | 
            -
                it "requires total to be less then 1" do
         | 
| 635 | 
            -
                  expect { Money.us_dollar(0.05).allocate([0.5, 0.6]) }.to raise_error(ArgumentError)
         | 
| 636 | 
            -
                end
         | 
| 637 | 
            -
             | 
| 638 646 | 
             
                it "keeps subclasses intact" do
         | 
| 639 647 | 
             
                  special_money_class = Class.new(Money)
         | 
| 640 648 | 
             
                  expect(special_money_class.new(005).allocate([1]).first).to be_a special_money_class
         | 
| @@ -733,6 +741,15 @@ YAML | |
| 733 741 | 
             
                      expect(rounded).to be_a special_money_class
         | 
| 734 742 | 
             
                    end
         | 
| 735 743 | 
             
                  end
         | 
| 744 | 
            +
             | 
| 745 | 
            +
                  context "when using a specific rounding precision" do
         | 
| 746 | 
            +
                    let(:money) { Money.new(15.7526, 'NZD') }
         | 
| 747 | 
            +
             | 
| 748 | 
            +
                    it "uses the provided rounding precision" do
         | 
| 749 | 
            +
                      rounded = money.round(BigDecimal::ROUND_DOWN, 3)
         | 
| 750 | 
            +
                      expect(rounded.fractional).to eq 15.752
         | 
| 751 | 
            +
                    end
         | 
| 752 | 
            +
                  end
         | 
| 736 753 | 
             
                end
         | 
| 737 754 | 
             
              end
         | 
| 738 755 |  | 
    
        data/spec/spec_helper.rb
    CHANGED
    
    
| @@ -0,0 +1,14 @@ | |
| 1 | 
            +
            RSpec.shared_examples 'instance with custom bank' do |operation, value|
         | 
| 2 | 
            +
              let(:custom_bank) { Money::Bank::VariableExchange.new }
         | 
| 3 | 
            +
              let(:instance) { Money.new(1, :usd, custom_bank) }
         | 
| 4 | 
            +
             | 
| 5 | 
            +
              subject { value ? instance.send(operation, value) : instance.send(operation) }
         | 
| 6 | 
            +
             | 
| 7 | 
            +
              it "returns custom bank from new instance" do
         | 
| 8 | 
            +
                new_money_instances = Array(subject).select { |el| el.is_a?(Money) }
         | 
| 9 | 
            +
             | 
| 10 | 
            +
                new_money_instances.each do |money_instance|
         | 
| 11 | 
            +
                  expect(money_instance.bank).to eq(custom_bank)
         | 
| 12 | 
            +
                end
         | 
| 13 | 
            +
              end
         | 
| 14 | 
            +
            end
         | 
    
        metadata
    CHANGED
    
    | @@ -1,14 +1,14 @@ | |
| 1 1 | 
             
            --- !ruby/object:Gem::Specification
         | 
| 2 2 | 
             
            name: money
         | 
| 3 3 | 
             
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            -
              version: 6. | 
| 4 | 
            +
              version: 6.11.0
         | 
| 5 5 | 
             
            platform: ruby
         | 
| 6 6 | 
             
            authors:
         | 
| 7 7 | 
             
            - Shane Emmons
         | 
| 8 8 | 
             
            autorequire: 
         | 
| 9 9 | 
             
            bindir: bin
         | 
| 10 10 | 
             
            cert_chain: []
         | 
| 11 | 
            -
            date:  | 
| 11 | 
            +
            date: 2018-04-08 00:00:00.000000000 Z
         | 
| 12 12 | 
             
            dependencies:
         | 
| 13 13 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 14 14 | 
             
              name: i18n
         | 
| @@ -19,7 +19,7 @@ dependencies: | |
| 19 19 | 
             
                    version: 0.6.4
         | 
| 20 20 | 
             
                - - "<"
         | 
| 21 21 | 
             
                  - !ruby/object:Gem::Version
         | 
| 22 | 
            -
                    version: '1. | 
| 22 | 
            +
                    version: '1.1'
         | 
| 23 23 | 
             
              type: :runtime
         | 
| 24 24 | 
             
              prerelease: false
         | 
| 25 25 | 
             
              version_requirements: !ruby/object:Gem::Requirement
         | 
| @@ -29,7 +29,7 @@ dependencies: | |
| 29 29 | 
             
                    version: 0.6.4
         | 
| 30 30 | 
             
                - - "<"
         | 
| 31 31 | 
             
                  - !ruby/object:Gem::Version
         | 
| 32 | 
            -
                    version: '1. | 
| 32 | 
            +
                    version: '1.1'
         | 
| 33 33 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 34 34 | 
             
              name: bundler
         | 
| 35 35 | 
             
              requirement: !ruby/object:Gem::Requirement
         | 
| @@ -78,14 +78,14 @@ dependencies: | |
| 78 78 | 
             
                requirements:
         | 
| 79 79 | 
             
                - - "~>"
         | 
| 80 80 | 
             
                  - !ruby/object:Gem::Version
         | 
| 81 | 
            -
                    version:  | 
| 81 | 
            +
                    version: 0.9.11
         | 
| 82 82 | 
             
              type: :development
         | 
| 83 83 | 
             
              prerelease: false
         | 
| 84 84 | 
             
              version_requirements: !ruby/object:Gem::Requirement
         | 
| 85 85 | 
             
                requirements:
         | 
| 86 86 | 
             
                - - "~>"
         | 
| 87 87 | 
             
                  - !ruby/object:Gem::Version
         | 
| 88 | 
            -
                    version:  | 
| 88 | 
            +
                    version: 0.9.11
         | 
| 89 89 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 90 90 | 
             
              name: kramdown
         | 
| 91 91 | 
             
              requirement: !ruby/object:Gem::Requirement
         | 
| @@ -131,7 +131,8 @@ files: | |
| 131 131 | 
             
            - lib/money/money.rb
         | 
| 132 132 | 
             
            - lib/money/money/arithmetic.rb
         | 
| 133 133 | 
             
            - lib/money/money/constructors.rb
         | 
| 134 | 
            -
            - lib/money/money/ | 
| 134 | 
            +
            - lib/money/money/formatter.rb
         | 
| 135 | 
            +
            - lib/money/money/formatting_rules.rb
         | 
| 135 136 | 
             
            - lib/money/rates_store/memory.rb
         | 
| 136 137 | 
             
            - lib/money/version.rb
         | 
| 137 138 | 
             
            - money.gemspec
         | 
| @@ -147,6 +148,7 @@ files: | |
| 147 148 | 
             
            - spec/money_spec.rb
         | 
| 148 149 | 
             
            - spec/rates_store/memory_spec.rb
         | 
| 149 150 | 
             
            - spec/spec_helper.rb
         | 
| 151 | 
            +
            - spec/support/shared_examples/money_examples.rb
         | 
| 150 152 | 
             
            homepage: https://rubymoney.github.io/money
         | 
| 151 153 | 
             
            licenses:
         | 
| 152 154 | 
             
            - MIT
         | 
| @@ -184,3 +186,4 @@ test_files: | |
| 184 186 | 
             
            - spec/money_spec.rb
         | 
| 185 187 | 
             
            - spec/rates_store/memory_spec.rb
         | 
| 186 188 | 
             
            - spec/spec_helper.rb
         | 
| 189 | 
            +
            - spec/support/shared_examples/money_examples.rb
         |