scrooge 0.1

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.
@@ -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
+