PageRenderTime 42ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 0ms

/vendor/gems/money-2.1.5/lib/money/money.rb

https://github.com/turn2/apocryphal_antelope
Ruby | 299 lines | 136 code | 36 blank | 127 comment | 24 complexity | d296d8a564b6d9fdab761f2b6f76c978 MD5 | raw file
  1. require 'money/variable_exchange_bank'
  2. # Represents an amount of money in a certain currency.
  3. class Money
  4. include Comparable
  5. attr_reader :cents, :currency, :bank
  6. class << self
  7. # Each Money object is associated to a bank object, which is responsible
  8. # for currency exchange. This property allows one to specify the default
  9. # bank object.
  10. #
  11. # bank1 = MyBank.new
  12. # bank2 = MyOtherBank.new
  13. #
  14. # Money.default_bank = bank1
  15. # money1 = Money.new(10)
  16. # money1.bank # => bank1
  17. #
  18. # Money.default_bank = bank2
  19. # money2 = Money.new(10)
  20. # money2.bank # => bank2
  21. # money1.bank # => bank1
  22. #
  23. # The default value for this property is an instance if VariableExchangeBank.
  24. # It allows one to specify custom exchange rates:
  25. #
  26. # Money.default_bank.add_rate("USD", "CAD", 1.24515)
  27. # Money.default_bank.add_rate("CAD", "USD", 0.803115)
  28. # Money.us_dollar(100).exchange_to("CAD") # => Money.ca_dollar(124)
  29. # Money.ca_dollar(100).exchange_to("USD") # => Money.us_dollar(80)
  30. attr_accessor :default_bank
  31. # The default currency, which is used when <tt>Money.new</tt> is called
  32. # without an explicit currency argument. The default value is "USD".
  33. attr_accessor :default_currency
  34. end
  35. self.default_bank = VariableExchangeBank.instance
  36. self.default_currency = "USD"
  37. # Create a new money object with value 0.
  38. def self.empty(currency = default_currency)
  39. Money.new(0, currency)
  40. end
  41. # Creates a new Money object of the given value, using the Canadian dollar currency.
  42. def self.ca_dollar(cents)
  43. Money.new(cents, "CAD")
  44. end
  45. # Creates a new Money object of the given value, using the American dollar currency.
  46. def self.us_dollar(cents)
  47. Money.new(cents, "USD")
  48. end
  49. # Creates a new Money object of the given value, using the Euro currency.
  50. def self.euro(cents)
  51. Money.new(cents, "EUR")
  52. end
  53. def self.add_rate(from_currency, to_currency, rate)
  54. Money.default_bank.add_rate(from_currency, to_currency, rate)
  55. end
  56. # Creates a new money object.
  57. # Money.new(100)
  58. #
  59. # Alternativly you can use the convinience methods like
  60. # Money.ca_dollar and Money.us_dollar
  61. def initialize(cents, currency = Money.default_currency, bank = Money.default_bank)
  62. @cents = cents.round
  63. if currency.is_a?(Hash)
  64. # Earlier versions of Money wrongly documented the constructor as being able
  65. # to accept something like this:
  66. #
  67. # Money.new(50, :currency => "USD")
  68. #
  69. # We retain compatibility here.
  70. @currency = currency[:currency] || Money.default_currency
  71. else
  72. @currency = currency
  73. end
  74. @bank = bank
  75. end
  76. # Do two money objects equal? Only works if both objects are of the same currency
  77. def ==(other_money)
  78. cents == other_money.cents && bank.same_currency?(currency, other_money.currency)
  79. end
  80. def <=>(other_money)
  81. if bank.same_currency?(currency, other_money.currency)
  82. cents <=> other_money.cents
  83. else
  84. cents <=> other_money.exchange_to(currency).cents
  85. end
  86. end
  87. def +(other_money)
  88. if currency == other_money.currency
  89. Money.new(cents + other_money.cents, other_money.currency)
  90. else
  91. Money.new(cents + other_money.exchange_to(currency).cents, currency)
  92. end
  93. end
  94. def -(other_money)
  95. if currency == other_money.currency
  96. Money.new(cents - other_money.cents, other_money.currency)
  97. else
  98. Money.new(cents - other_money.exchange_to(currency).cents, currency)
  99. end
  100. end
  101. # get the cents value of the object
  102. def cents
  103. @cents
  104. end
  105. # multiply money by fixnum
  106. def *(fixnum)
  107. Money.new(cents * fixnum, currency)
  108. end
  109. # divide money by fixnum
  110. def /(fixnum)
  111. Money.new(cents / fixnum, currency)
  112. end
  113. # Test if the money amount is zero
  114. def zero?
  115. cents == 0
  116. end
  117. # Creates a formatted price string according to several rules. The following
  118. # options are supported: :display_free, :with_currency, :no_cents, :symbol
  119. # and :html.
  120. #
  121. # === +:display_free+
  122. #
  123. # Whether a zero amount of money should be formatted of "free" or as the
  124. # supplied string.
  125. #
  126. # Money.us_dollar(0).format(:display_free => true) => "free"
  127. # Money.us_dollar(0).format(:display_free => "gratis") => "gratis"
  128. # Money.us_dollar(0).format => "$0.00"
  129. #
  130. # === +:with_currency+
  131. #
  132. # Whether the currency name should be appended to the result string.
  133. #
  134. # Money.ca_dollar(100).format => "$1.00"
  135. # Money.ca_dollar(100).format(:with_currency => true) => "$1.00 CAD"
  136. # Money.us_dollar(85).format(:with_currency => true) => "$0.85 USD"
  137. #
  138. # === +:no_cents+
  139. #
  140. # Whether cents should be omitted.
  141. #
  142. # Money.ca_dollar(100).format(:no_cents => true) => "$1"
  143. # Money.ca_dollar(599).format(:no_cents => true) => "$5"
  144. #
  145. # Money.ca_dollar(570).format(:no_cents => true, :with_currency => true) => "$5 CAD"
  146. # Money.ca_dollar(39000).format(:no_cents => true) => "$390"
  147. #
  148. # === +:symbol+
  149. #
  150. # Whether a money symbol should be prepended to the result string. The default is true.
  151. # This method attempts to pick a symbol that's suitable for the given currency.
  152. #
  153. # Money.new(100, "USD") => "$1.00"
  154. # Money.new(100, "GBP") => "£1.00"
  155. # Money.new(100, "EUR") => "€1.00"
  156. #
  157. # # Same thing.
  158. # Money.new(100, "USD").format(:symbol => true) => "$1.00"
  159. # Money.new(100, "GBP").format(:symbol => true) => "£1.00"
  160. # Money.new(100, "EUR").format(:symbol => true) => "€1.00"
  161. #
  162. # You can specify a false expression or an empty string to disable prepending
  163. # a money symbol:
  164. #
  165. # Money.new(100, "USD").format(:symbol => false) => "1.00"
  166. # Money.new(100, "GBP").format(:symbol => nil) => "1.00"
  167. # Money.new(100, "EUR").format(:symbol => "") => "1.00"
  168. #
  169. #
  170. # If the symbol for the given currency isn't known, then it will default
  171. # to "$" as symbol:
  172. #
  173. # Money.new(100, "AWG").format(:symbol => true) => "$1.00"
  174. #
  175. # You can specify a string as value to enforce using a particular symbol:
  176. #
  177. # Money.new(100, "AWG").format(:symbol => "ƒ") => "ƒ1.00"
  178. #
  179. # === +:html+
  180. #
  181. # Whether the currency should be HTML-formatted. Only useful in combination with +:with_currency+.
  182. #
  183. # Money.ca_dollar(570).format(:html => true, :with_currency => true)
  184. # => "$5.70 <span class=\"currency\">CAD</span>"
  185. def format(*rules)
  186. # support for old format parameters
  187. rules = normalize_formatting_rules(rules)
  188. if cents == 0
  189. if rules[:display_free].respond_to?(:to_str)
  190. return rules[:display_free]
  191. elsif rules[:display_free]
  192. return "free"
  193. end
  194. end
  195. if rules.has_key?(:symbol)
  196. if rules[:symbol] === true
  197. symbol = SYMBOLS[currency] || "$"
  198. elsif rules[:symbol]
  199. symbol = rules[:symbol]
  200. else
  201. symbol = ""
  202. end
  203. else
  204. symbol = SYMBOLS[currency] || "$"
  205. end
  206. if rules[:no_cents]
  207. formatted = sprintf("#{symbol}%d", cents.to_f / 100)
  208. else
  209. formatted = sprintf("#{symbol}%.2f", cents.to_f / 100)
  210. end
  211. # Commify ("10000" => "10,000")
  212. formatted.gsub!(/(\d)(?=\d{3}+(?:\.|$))(\d{3}\..*)?/,'\1,\2')
  213. if rules[:with_currency]
  214. formatted << " "
  215. formatted << '<span class="currency">' if rules[:html]
  216. formatted << currency
  217. formatted << '</span>' if rules[:html]
  218. end
  219. formatted
  220. end
  221. # Returns the amount of money as a string.
  222. #
  223. # Money.ca_dollar(100).to_s => "1.00"
  224. def to_s
  225. sprintf("%.2f", cents / 100.00)
  226. end
  227. # Recieve the amount of this money object in another currency.
  228. def exchange_to(other_currency)
  229. Money.new(@bank.exchange(self.cents, currency, other_currency), other_currency)
  230. end
  231. # Recieve a money object with the same amount as the current Money object
  232. # in american dollar
  233. def as_us_dollar
  234. exchange_to("USD")
  235. end
  236. # Recieve a money object with the same amount as the current Money object
  237. # in canadian dollar
  238. def as_ca_dollar
  239. exchange_to("CAD")
  240. end
  241. # Recieve a money object with the same amount as the current Money object
  242. # in euro
  243. def as_euro
  244. exchange_to("EUR")
  245. end
  246. # Conversation to self
  247. def to_money
  248. self
  249. end
  250. private
  251. def normalize_formatting_rules(rules)
  252. if rules.size == 1
  253. rules = rules.pop
  254. rules = { rules => true } if rules.is_a?(Symbol)
  255. else
  256. rules = rules.inject({}) do |h,s|
  257. h[s] = true
  258. h
  259. end
  260. end
  261. rules
  262. end
  263. end