scrooge 0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1 @@
1
+ dist/*
data/README ADDED
@@ -0,0 +1,92 @@
1
+ Scrooge
2
+ =========
3
+
4
+ Make it easy to store money values in an ActiveRecord model, avoiding the
5
+ annoying floating point math. The idea is to store the monetary values as
6
+ the amount of cents in the database to avoid the math.
7
+
8
+ class Product < ActiveRecord::Base
9
+ attr_cents :price
10
+ end
11
+
12
+ product = Product.new(:price => 10.99)
13
+ product.price #=> #<Scrooge::Money @cents="1099">
14
+
15
+ The Scrooge::Money objects will act as a Numeric in all regards, so you can
16
+ do math with other numbers easily.
17
+
18
+ The `products` table should have an integer column `price_in_cents` for
19
+ this to work.
20
+
21
+ Calculations
22
+ ------------
23
+
24
+ If you need aggregated calculations on your model, you can use the provided
25
+ method Numeric#as_cents, which converts a number to a Scrooge::Money instance,
26
+ assuming that the number is already the number of cents. For example:
27
+
28
+ class Sale < ActiveRecord::Base
29
+ belongs_to :product
30
+ attr_cents :value
31
+ end
32
+
33
+ class Product < ActiveRecord::Base
34
+ has_many :sales
35
+
36
+ def gross_sales
37
+ sales.sum(:value_in_cents).as_cents
38
+ end
39
+ end
40
+
41
+ product = Product.create
42
+ product.sales.create(:value => 20)
43
+ product.sales.create(:value => 20.5)
44
+ product.sales.create(:value => 25)
45
+
46
+ product.gross_sales #=> #<Scrooge::Money @cents="6550">
47
+ product.gross_sales == 65.5 #=> true
48
+
49
+ Why?
50
+ ====
51
+
52
+ Because we only needed this, and most of the gems that do this stuff are too
53
+ damn big and have a ton of un-needed functionality.
54
+
55
+ Install
56
+ =======
57
+
58
+ gem install scrooge
59
+
60
+ Then, in order to require it, if you want the ActiveRecord helper methods:
61
+
62
+ require "scrooge/active_record"
63
+
64
+ Or:
65
+
66
+ config.gem "scrooge"
67
+
68
+ License
69
+ ======
70
+
71
+ (The MIT License)
72
+
73
+ Copyright (c) 2010 Nicolas Sanguinetti, http://nicolassanguinetti.info
74
+
75
+ Permission is hereby granted, free of charge, to any person obtaining
76
+ a copy of this software and associated documentation files (the
77
+ 'Software'), to deal in the Software without restriction, including
78
+ without limitation the rights to use, copy, modify, merge, publish,
79
+ distribute, sublicense, and/or sell copies of the Software, and to
80
+ permit persons to whom the Software is furnished to do so, subject to
81
+ the following conditions:
82
+
83
+ The above copyright notice and this permission notice shall be
84
+ included in all copies or substantial portions of the Software.
85
+
86
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
87
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
88
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
89
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
90
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
91
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
92
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,91 @@
1
+ module Scrooge
2
+ VERSION = "0.1"
3
+
4
+ class Money
5
+ include Comparable
6
+
7
+ def initialize(cents)
8
+ @cents = cents.to_i
9
+ end
10
+
11
+ def to_i
12
+ to_f.to_i
13
+ end
14
+
15
+ def to_f
16
+ to_cents / 100.0
17
+ end
18
+
19
+ def to_money
20
+ self
21
+ end
22
+
23
+ def to_cents
24
+ @cents
25
+ end
26
+
27
+ def <=>(other)
28
+ to_cents <=> other.to_money.to_cents
29
+ end
30
+
31
+ def +@
32
+ self
33
+ end
34
+
35
+ def -@
36
+ Money.new(-to_cents)
37
+ end
38
+
39
+ def +(other)
40
+ Money.new(to_cents + other.to_money.to_cents)
41
+ end
42
+
43
+ def -(other)
44
+ self + -other
45
+ end
46
+
47
+ def *(other)
48
+ Money.new(to_cents * other)
49
+ end
50
+
51
+ def /(other)
52
+ Money.new(to_cents / other)
53
+ end
54
+
55
+ def coerce(other)
56
+ [other.to_money, self]
57
+ end
58
+
59
+ def method_missing(method, *args, &block)
60
+ to_f.send(method, *args, &block)
61
+ end
62
+
63
+ def respond_to?(method, include_private=false)
64
+ to_f.respond_to?(method, include_private)
65
+ end
66
+
67
+ def to_s
68
+ to_f.to_s
69
+ end
70
+ end
71
+ end
72
+
73
+ class Numeric
74
+ def to_money
75
+ Scrooge::Money.new(100 * self)
76
+ end
77
+
78
+ def as_cents
79
+ Scrooge::Money.new(self)
80
+ end
81
+ end
82
+
83
+ class String
84
+ def to_money
85
+ to_f.to_money
86
+ end
87
+
88
+ def as_cents
89
+ to_i.as_cents
90
+ end
91
+ end
@@ -0,0 +1,14 @@
1
+ require "scrooge"
2
+
3
+ module Scrooge
4
+ module ActiveRecord
5
+ def attr_cents(*names)
6
+ names.each do |name|
7
+ composed_of name, :class_name => "Scrooge::Money",
8
+ :mapping => ["#{name}_in_cents", "to_cents"],
9
+ :converter => lambda {|value| (value || 0).to_money },
10
+ :constructor => lambda {|value| value.to_f.as_cents }
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,2 @@
1
+ require "scrooge/active_record"
2
+ ActiveRecord::Base.extend Scrooge::ActiveRecord
@@ -0,0 +1,26 @@
1
+ Gem::Specification.new do |s|
2
+ s.name = "scrooge"
3
+ s.version = "0.1"
4
+ s.date = "2010-01-19"
5
+
6
+ s.description = "Class to serialize money into the database, works out of the box with ActiveRecord"
7
+ s.summary = "Scrooge will keep all your money safe. Or at least in the database."
8
+ s.homepage = "http://github.com/foca/centipede"
9
+
10
+ s.authors = ["Nicolás Sanguinetti"]
11
+ s.email = "contacto@nicolassanguinetti.info"
12
+
13
+ s.require_paths = ["lib"]
14
+ s.has_rdoc = true
15
+
16
+ s.files = %w[
17
+ .gitignore
18
+ README
19
+ scrooge.gemspec
20
+ lib/scrooge.rb
21
+ lib/scrooge/active_record.rb
22
+ rails/init.rb
23
+ spec/scrooge_spec.rb
24
+ ]
25
+ end
26
+
@@ -0,0 +1,69 @@
1
+ require "centipede"
2
+ require "spec"
3
+
4
+ include Centipede
5
+
6
+ describe Centipede::Money do
7
+ subject { Money.new(175) }
8
+
9
+ it "can be interpreted as an integer" do
10
+ subject.to_i.should == 1
11
+ end
12
+
13
+ it "can be interpreted as a float" do
14
+ subject.to_f.should == 1.75
15
+ end
16
+
17
+ it "can be zero" do
18
+ subject.should_not be_zero
19
+ Money.new(0).should be_zero
20
+ end
21
+
22
+ describe "doing arithmetic operations" do
23
+ it "can add another number" do
24
+ (subject + 2.00).should == 3.75
25
+ end
26
+
27
+ it "can be added to another number" do
28
+ (2.00 + subject).should == 3.75
29
+ end
30
+
31
+ it "can be substracted from a number" do
32
+ (2.00 - subject).should == 0.25
33
+ end
34
+
35
+ it "can substract a number" do
36
+ (subject - 1.00).should == 0.75
37
+ end
38
+
39
+ it "can be multiplied by a number" do
40
+ (subject * 2.0).should == 3.50
41
+ end
42
+
43
+ it "can be divided by a number" do
44
+ (subject / 2.0).should == 0.875
45
+ end
46
+ end
47
+
48
+ describe "extending core classes" do
49
+ it "allows to convert integers to money objects" do
50
+ 2.to_money.should == Money.new(200)
51
+ end
52
+
53
+ it "allows converting floats to money objects" do
54
+ 2.5.to_money.should == Money.new(250)
55
+ end
56
+
57
+ it "allows interpreting numbers as amount of cents" do
58
+ (1500.as_cents).should == 15
59
+ end
60
+
61
+ it "can interpet a string as a money value" do
62
+ "123.5".to_money.should == Money.new(12350)
63
+ end
64
+
65
+ it "can interpet a string as a number of cents" do
66
+ "12345".as_cents.should == Money.new(12345)
67
+ end
68
+ end
69
+ end
metadata ADDED
@@ -0,0 +1,61 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: scrooge
3
+ version: !ruby/object:Gem::Version
4
+ version: "0.1"
5
+ platform: ruby
6
+ authors:
7
+ - "Nicol\xC3\xA1s Sanguinetti"
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2010-01-19 00:00:00 -02:00
13
+ default_executable:
14
+ dependencies: []
15
+
16
+ description: Class to serialize money into the database, works out of the box with ActiveRecord
17
+ email: contacto@nicolassanguinetti.info
18
+ executables: []
19
+
20
+ extensions: []
21
+
22
+ extra_rdoc_files: []
23
+
24
+ files:
25
+ - .gitignore
26
+ - README
27
+ - scrooge.gemspec
28
+ - lib/scrooge.rb
29
+ - lib/scrooge/active_record.rb
30
+ - rails/init.rb
31
+ - spec/scrooge_spec.rb
32
+ has_rdoc: true
33
+ homepage: http://github.com/foca/centipede
34
+ licenses: []
35
+
36
+ post_install_message:
37
+ rdoc_options: []
38
+
39
+ require_paths:
40
+ - lib
41
+ required_ruby_version: !ruby/object:Gem::Requirement
42
+ requirements:
43
+ - - ">="
44
+ - !ruby/object:Gem::Version
45
+ version: "0"
46
+ version:
47
+ required_rubygems_version: !ruby/object:Gem::Requirement
48
+ requirements:
49
+ - - ">="
50
+ - !ruby/object:Gem::Version
51
+ version: "0"
52
+ version:
53
+ requirements: []
54
+
55
+ rubyforge_project:
56
+ rubygems_version: 1.3.5
57
+ signing_key:
58
+ specification_version: 3
59
+ summary: Scrooge will keep all your money safe. Or at least in the database.
60
+ test_files: []
61
+