bd_money 0.0.8 → 0.0.9

Sign up to get free protection for your applications and to get access to all the features.
data/README.rdoc CHANGED
@@ -59,14 +59,24 @@ There is a rails extension that makes it easier to store money values in the dat
59
59
  validates_numericality_of :price, :greater_than => 0
60
60
  end
61
61
 
62
- This assumes that there is a price (decimal highly recommended) column in the database. You can also specify the
63
- :precision and :round_mode option for more fine control of the results.
62
+ This assumes that there is a price (decimal highly recommended) column in the database.
63
+
64
+ You can also specify the :precision, :round_mode and :format options for more fine control of the results. If you don't
65
+ specify the :precision option it will try to guess it out of the scale column definition (recommended). Precision is
66
+ important since the values will get rounded on every change internally to stay consistent with the database.
64
67
 
65
68
  class Loan < ActiveRecord::Base
66
- money :amount, :round_mode => :half_up
67
- money :apr, :precision => 5, :round_mode => :floor
69
+ money :amount, :round_mode => :half_up, :format => :no_cents
70
+ money :apr, :precision => 5, :round_mode => :floor, :format => :no_commas
68
71
  end
69
72
 
73
+ loan = Loan.create! :amount => '325.75', :apr => '0.01234'
74
+ loan.amount #=> 325.75
75
+ loan.amount.formatted #=> $ 325.75
76
+ loan.apr #=> 0.0123
77
+ loan.apr.formatted #=> $ 0.01
78
+ loan.apr.formatted(:precision => 5, :unit => "", :spacer => "") #=> 0.01234
79
+
70
80
  You can set the attribute to a String, Fixnum, or Float and it will call #to_money to
71
81
  convert it to a Money object. This makes it convenient for using money fields in forms.
72
82
 
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.0.8
1
+ 0.0.9
data/bd_money.gemspec CHANGED
@@ -5,7 +5,7 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{bd_money}
8
- s.version = "0.0.8"
8
+ s.version = "0.0.9"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Adrian Madrid"]
@@ -14,17 +14,17 @@ class Money
14
14
  } unless const_defined?(:ROUND_MODES)
15
15
 
16
16
  FORMATS = {
17
- :default => { :unit => "$", :spacer => " ", :delimiter => ",", :separator => ".", :precision => 2 },
18
- :no_cents => { :unit => "$", :spacer => " ", :delimiter => ",", :separator => ".", :precision => 0 },
19
- :no_commas => { :unit => "$", :spacer => " ", :delimiter => "", :separator => ".", :precision => 2 },
17
+ :default => { :unit => "$", :spacer => " ", :delimiter => ",", :separator => ".", :precision => 2, :last => "" },
18
+ :no_cents => { :unit => "$", :spacer => " ", :delimiter => ",", :separator => ".", :precision => 0, :last => "" },
19
+ :no_commas => { :unit => "$", :spacer => " ", :delimiter => "", :separator => ".", :precision => 2, :last => "" },
20
+ :general => { :unit => "", :spacer => "", :delimiter => "", :separator => ".", :precision => 2, :last => "" },
20
21
  } unless const_defined?(:FORMATS)
21
22
 
22
23
  REMOVE_RE = %r{[$,_ ]} unless const_defined?(:REMOVE_RE)
23
24
  VALID_RE = %r{^(-)?(\d)+(\.\d{1,30}(e-\d{1,10})?)?$} unless const_defined?(:VALID_RE)
24
25
 
25
- YAML_TYPE_CLASS = 'npadv.com,2012-03-12' unless const_defined?(:YAML_TYPE_CLASS)
26
- YAML_TYPE_MODE = 'money' unless const_defined?(:YAML_TYPE_MODE)
27
- YAML_TYPE_FULL = "#{YAML_TYPE_CLASS}/#{YAML_TYPE_MODE}" unless const_defined?(:YAML_TYPE_FULL)
26
+ YAML_TYPE_ROOT = 'npadv.com,2012-03-12' unless const_defined?(:YAML_TYPE_ROOT)
27
+ YAML_TYPE_NAME = 'money' unless const_defined?(:YAML_TYPE_NAME)
28
28
 
29
29
  include Comparable
30
30
 
@@ -79,8 +79,8 @@ class Money
79
79
  @format || self.class.format
80
80
  end
81
81
 
82
- def convert(value)
83
- self.class.convert value
82
+ def convert(value, this_precision = precision, this_round_mode = round_mode)
83
+ self.class.convert value, this_precision, this_round_mode
84
84
  end
85
85
 
86
86
  def eql?(other)
@@ -187,15 +187,16 @@ class Money
187
187
  spacer = options[:spacer] || defaults[:spacer]
188
188
  delimiter = options[:delimiter] || defaults[:delimiter]
189
189
  separator = options[:separator] || defaults[:separator]
190
- precision = options[:precision] || defaults[:precision]
191
190
  separator = '' if precision == 0
191
+ precision = options[:precision] || defaults[:precision]
192
+ last = options[:last] || defaults[:last]
192
193
 
193
194
  number = to_s precision
194
195
  begin
195
196
  parts = number.to_s.split('.')
196
197
  parts[0].gsub!(/(\d)(?=(\d\d\d)+(?!\d))/, "\\1#{delimiter}")
197
198
  number = parts.join(separator)
198
- "#{unit}#{spacer}#{number}"
199
+ "#{unit}#{spacer}#{number}#{last}"
199
200
  rescue
200
201
  number
201
202
  end
@@ -215,7 +216,7 @@ class Money
215
216
  end
216
217
 
217
218
  def to_yaml_type
218
- "!#{YAML_TYPE_FULL}"
219
+ "!#{YAML_TYPE_ROOT}/#{YAML_TYPE_NAME}"
219
220
  end
220
221
 
221
222
  def to_yaml(options = { })
@@ -258,9 +259,8 @@ class Money
258
259
  @format || :default
259
260
  end
260
261
 
261
- def convert(value)
262
- return value if value.is_a?(Money)
263
- new value
262
+ def convert(value, precision = nil, round_mode = nil)
263
+ new value, precision, round_mode
264
264
  end
265
265
 
266
266
  def clean(value)
@@ -275,6 +275,6 @@ class Money
275
275
 
276
276
  end
277
277
 
278
- YAML::add_domain_type(Money::YAML_TYPE_CLASS, Money::YAML_TYPE_MODE) do |_, map|
278
+ YAML::add_domain_type(Money::YAML_TYPE_ROOT, Money::YAML_TYPE_NAME) do |_, map|
279
279
  Money.new map['amount'], map['precision'], map['round_mode'], map['format']
280
280
  end
@@ -27,16 +27,22 @@ module ActiveRecord #:nodoc:
27
27
  def money(*names)
28
28
  options = names.extract_options!
29
29
  names.each do |name|
30
+ if options[:precision]
31
+ this_precision = options[:precision]
32
+ else
33
+ db_column = columns.select { |x| x.name == name.to_s }.first
34
+ this_precision = (db_column && db_column.respond_to?(:scale)) ? db_column.scale : nil
35
+ end
30
36
  define_method "#{name}=" do |value|
31
37
  if value.present?
32
- self[name] = ::Money.new(value, options[:precision], options[:round_mode]).amount
38
+ self[name] = ::Money.new(value, this_precision, options[:round_mode], options[:format]).round.amount
33
39
  else
34
40
  self[name] = nil
35
41
  end
36
42
  end
37
43
  define_method "#{name}" do
38
44
  return nil unless self[name].present?
39
- ::Money.new self[name], options[:precision], options[:round_mode]
45
+ ::Money.new self[name], this_precision, options[:round_mode], options[:format]
40
46
  end
41
47
  end
42
48
  end
data/spec/rails_spec.rb CHANGED
@@ -21,22 +21,25 @@ end
21
21
  class BetterLoanExample < ActiveRecord::Base
22
22
  set_table_name "money_examples"
23
23
 
24
- money :amount, :precision => 2, :round_mode => :half_up
25
- money :apr, :precision => 5, :round_mode => :floor
24
+ money :amount, :round_mode => :half_up, :format => :no_cents
25
+ money :apr, :precision => 4, :round_mode => :floor, :format => :no_commas
26
26
  end
27
27
 
28
28
  describe Money do
29
29
  describe "default settings" do
30
- it "should allow dynamic finders to work with money objects" do
31
- record = DefaultLoanExample.create! :amount => '325.75', :apr => '0.01234'
32
- DefaultLoanExample.find_by_amount(0.to_money).should be_nil
33
- found = DefaultLoanExample.find_by_amount('325.75'.to_money)
34
- found.should == record
35
- found.amount.should be_a(Money)
36
- found.amount.to_s.should == '325.75'
37
- found.apr.should be_a(Money)
38
- found.apr.to_s.should == '0.01'
39
- end
30
+ before(:all) { @record = BetterLoanExample.create! :amount => '325.75', :apr => '0.01234' }
31
+ subject { BetterLoanExample.find_by_amount('325.75'.to_money) }
32
+ it { BetterLoanExample.find_by_amount(0.to_money).should be_nil }
33
+ it { subject.id.should == @record.id }
34
+ it { subject.amount.should be_a(Money) }
35
+ it { subject.amount.to_s.should == '325.75' }
36
+ it { subject.amount.format.should == :no_cents }
37
+ it { subject.amount.formatted.should == '$ 325.75' }
38
+ it { subject.apr.should be_a(Money) }
39
+ it { subject.apr.to_s.should == '0.0123' }
40
+ it { subject.apr.format.should == :no_commas }
41
+ it { subject.apr.formatted.should == '$ 0.01' }
42
+ it { subject.apr.formatted(:precision => 3, :unit => "", :spacer => "").should == '0.012' }
40
43
  end
41
44
  describe "custom settings" do
42
45
  it "should allow dynamic finders to work with money objects" do
@@ -47,7 +50,7 @@ describe Money do
47
50
  found.amount.should be_a(Money)
48
51
  found.amount.to_s.should == '123.45'
49
52
  found.apr.should be_a(Money)
50
- found.apr.to_s.should == '0.01234'
53
+ found.apr.to_s.should == '0.0123'
51
54
  end
52
55
  end
53
56
  describe "setter method" do
@@ -72,5 +75,11 @@ describe Money do
72
75
  me.update_attribute :amount, nil
73
76
  me.amount.should be_nil
74
77
  end
78
+
79
+ describe "should round numbers to the column's' precision" do
80
+ subject { BetterLoanExample.new :amount => 300, :apr => 0.123456789 }
81
+ it { subject.amount.amount.to_s('F').should == '300.0' }
82
+ it { subject.apr.amount.to_s('F').should == '0.1234' }
83
+ end
75
84
  end
76
85
  end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bd_money
3
3
  version: !ruby/object:Gem::Version
4
- hash: 15
4
+ hash: 13
5
5
  prerelease:
6
6
  segments:
7
7
  - 0
8
8
  - 0
9
- - 8
10
- version: 0.0.8
9
+ - 9
10
+ version: 0.0.9
11
11
  platform: ruby
12
12
  authors:
13
13
  - Adrian Madrid