spook_and_puff_money 0.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (4) hide show
  1. data/MIT-LICENSE +20 -0
  2. data/README.md +7 -0
  3. data/lib/spook_and_puff/money.rb +249 -0
  4. metadata +98 -0
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright 2013 Spook and Puff
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,7 @@
1
+ # SpookAndPuff::Money
2
+
3
+ This is yet another Ruby class made to represent money. This one is dead simple. It doesn't integrate with any frameworks, it simply enforces precison by ensuring all operands -- for methods like +, -, / etc. -- are BigDecimals.
4
+
5
+ It also provides a few other conveniences like formatting.
6
+
7
+ It is primarily intended for our own projects, but is offered here as an open sourced project, because.
@@ -0,0 +1,249 @@
1
+ require 'bigdecimal'
2
+
3
+ # The main Spook and Puff module which namespaces our projects. Yay?
4
+ module SpookAndPuff
5
+ # The money class represents monetary values with a precision of up to seven
6
+ # digits. When used as part of a comparison or mathmatical operation it
7
+ # always ensures the other operand is coerced into a BigDecimal. This ensures
8
+ # the precision is maintained.
9
+ class Money
10
+ include Comparable
11
+
12
+ # Stores the raw BigDecimal instance that a Money instance wraps.
13
+ attr_reader :raw
14
+
15
+ # Initializes the money class from a BigDecimal instance.
16
+ #
17
+ # @param [BigDecimal, String] value
18
+ #
19
+ # @return self
20
+ #
21
+ # @raise TypeError
22
+ #
23
+ # @todo This potentially should only handle BigDecimal, Money and String
24
+ def initialize(value)
25
+ @raw = case value
26
+ when BigDecimal then value.round(7)
27
+ when String then BigDecimal.new(value).round(7)
28
+ else raise TypeError.new("Money can only be initalized with a BigDecimal or String not #{value.class}.")
29
+ end
30
+ end
31
+
32
+ # Value comparison.
33
+ #
34
+ # @param [Money, Numeric, String] other
35
+ #
36
+ # @return Money
37
+ #
38
+ # @raise ArgumentError
39
+ def ==(other)
40
+ @raw == for_comparison(other)
41
+ end
42
+
43
+ # @param [Money, Numeric, String] other
44
+ #
45
+ # @return Money
46
+ #
47
+ # @raise ArgumentError
48
+ def <=>(other)
49
+ @raw <=> for_comparison(other)
50
+ end
51
+
52
+ # Multiplication. Numerics and strings only.
53
+ #
54
+ # @param [Integer, Fixnum, String] other
55
+ #
56
+ # @return Money
57
+ #
58
+ # @raise ArgumentError
59
+ def *(other)
60
+ Money.new(@raw * coerce(other))
61
+ end
62
+
63
+ # Division. Numerics and strings only.
64
+ #
65
+ # @param [Integer, Fixnum, String] other
66
+ #
67
+ # @return Money
68
+ #
69
+ # @raise ArgumentError
70
+ def /(other)
71
+ Money.new(@raw / coerce(other))
72
+ end
73
+
74
+ # Minus.
75
+ #
76
+ # @param [Money, Numeric, String] other
77
+ #
78
+ # @return Money
79
+ #
80
+ # @raise ArgumentError
81
+ def -(other)
82
+ Money.new(@raw - for_operation(other, 'subtraction'))
83
+ end
84
+
85
+ # Add.
86
+ #
87
+ # @param [Money, Numeric, String] other
88
+ #
89
+ # @return Money
90
+ #
91
+ # @raise ArgumentError
92
+ def +(other)
93
+ Money.new(@raw + for_operation(other, 'addition'))
94
+ end
95
+
96
+ # Unary minus. This negates the money value
97
+ #
98
+ # @return Money
99
+ def -@
100
+ Money.new(-@raw)
101
+ end
102
+
103
+ # Unary plus. Just returns the reciever.
104
+ #
105
+ # @return Money
106
+ def +@
107
+ self
108
+ end
109
+
110
+ # Returns a new Money instance with the absolute value.
111
+ #
112
+ # @return Money
113
+ def abs
114
+ Money.new(@raw.abs)
115
+ end
116
+
117
+ # Returns a BigDecimal representation of the value in cents.
118
+ #
119
+ # @return BigDecimal
120
+ def cents
121
+ @raw * BigDecimal.new('100')
122
+ end
123
+
124
+ # Returns the raw BigDecimal value.
125
+ #
126
+ # @return BigDecimal
127
+ def to_big_decimal
128
+ @raw
129
+ end
130
+
131
+ # Checks for zero value.
132
+ #
133
+ # @return [true, false]
134
+ def zero?
135
+ @raw == 0
136
+ end
137
+
138
+ # Checks to see if the value is positive i.e. non-negative, non-zero.
139
+ #
140
+ # @return [true, false]
141
+ def positive?
142
+ @raw > 0
143
+ end
144
+
145
+ # Checks to see if the value is positive.
146
+ #
147
+ # @return [true, false]
148
+ def non_negative?
149
+ @raw > -1
150
+ end
151
+
152
+ # Checks to see if the value is less than zero.
153
+ #
154
+ # @return [true, false]
155
+ def negative?
156
+ @raw < 0
157
+ end
158
+
159
+ # Calculates an amount based on the provided percentage.
160
+ #
161
+ # @param [Numeric, String] percentage
162
+ #
163
+ # @return Money
164
+ #
165
+ # @raise TypeError
166
+ def percent(percentage)
167
+ Money.new(@raw * (coerce(percentage) / BigDecimal.new('100')))
168
+ end
169
+
170
+ # Calculates the proportion of the provided amount as a percentage.
171
+ #
172
+ # @param SpookAndPuff::Money amount
173
+ #
174
+ # @return BigDecimal
175
+ #
176
+ # @raise TypeError
177
+ def proportion(amount)
178
+ amount.raw / @raw * BigDecimal('100')
179
+ end
180
+
181
+ # Rounds to the specified places; defaults to two.
182
+ #
183
+ # @param Integer places
184
+ #
185
+ # @return Money
186
+ def round(places = 2)
187
+ Money.new(@raw.round(places))
188
+ end
189
+
190
+ # Returns a currency formatted string.
191
+ #
192
+ # @return String
193
+ def to_s
194
+ "$%.2f" % @raw.round(2)
195
+ end
196
+
197
+ private
198
+
199
+ # Grabs the raw value of a Money instance, erroring with a message
200
+ # about comparison if it's the wrong type.
201
+ #
202
+ # @param SpookAndPuff::Money other
203
+ #
204
+ # @return BigDecimal
205
+ #
206
+ # @raise ArgumentError
207
+ def for_comparison(other)
208
+ unless other.is_a?(Money)
209
+ raise ArgumentError.new("#{other.class} cannot be compared with SpookAndPuff::Money")
210
+ end
211
+
212
+ other.raw
213
+ end
214
+
215
+ # Grabs the raw value of a Money instance, erroring with a message
216
+ # about comparison if it's the wrong type.
217
+ #
218
+ # @param SpookAndPuff::Money other
219
+ # @param String op
220
+ #
221
+ # @return BigDecimal
222
+ #
223
+ # @raise ArgumentError
224
+ def for_operation(other, op)
225
+ unless other.is_a?(Money)
226
+ raise ArgumentError.new("Cannot perform #{op} on SpookAndPuff::Money with #{other.class}")
227
+ end
228
+
229
+ other.raw
230
+ end
231
+
232
+ # Coerces the provided value into a BigDecimal. It will handle any
233
+ # Numeric or string.
234
+ #
235
+ # @param [Numeric, String] other
236
+ #
237
+ # @return BigDecimal
238
+ #
239
+ # @raise TypeError
240
+ def coerce(other)
241
+ case other
242
+ when BigDecimal then other
243
+ when String then BigDecimal.new(other)
244
+ when Integer, Fixnum, Bignum then BigDecimal.new(other.to_s)
245
+ else raise TypeError
246
+ end
247
+ end
248
+ end # Money
249
+ end # SpookAndPuff
metadata ADDED
@@ -0,0 +1,98 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: spook_and_puff_money
3
+ version: !ruby/object:Gem::Version
4
+ version: '0.5'
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Luke Sutton
9
+ - Ben Hull
10
+ autorequire:
11
+ bindir: bin
12
+ cert_chain: []
13
+ date: 2013-05-10 00:00:00.000000000 Z
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: rspec
17
+ requirement: !ruby/object:Gem::Requirement
18
+ none: false
19
+ requirements:
20
+ - - '='
21
+ - !ruby/object:Gem::Version
22
+ version: 2.13.0
23
+ type: :development
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ none: false
27
+ requirements:
28
+ - - '='
29
+ - !ruby/object:Gem::Version
30
+ version: 2.13.0
31
+ - !ruby/object:Gem::Dependency
32
+ name: yard
33
+ requirement: !ruby/object:Gem::Requirement
34
+ none: false
35
+ requirements:
36
+ - - '='
37
+ - !ruby/object:Gem::Version
38
+ version: 0.8.6.1
39
+ type: :development
40
+ prerelease: false
41
+ version_requirements: !ruby/object:Gem::Requirement
42
+ none: false
43
+ requirements:
44
+ - - '='
45
+ - !ruby/object:Gem::Version
46
+ version: 0.8.6.1
47
+ - !ruby/object:Gem::Dependency
48
+ name: redcarpet
49
+ requirement: !ruby/object:Gem::Requirement
50
+ none: false
51
+ requirements:
52
+ - - '='
53
+ - !ruby/object:Gem::Version
54
+ version: 2.2.2
55
+ type: :development
56
+ prerelease: false
57
+ version_requirements: !ruby/object:Gem::Requirement
58
+ none: false
59
+ requirements:
60
+ - - '='
61
+ - !ruby/object:Gem::Version
62
+ version: 2.2.2
63
+ description:
64
+ email:
65
+ - lukeandben@spookandpuff.com
66
+ executables: []
67
+ extensions: []
68
+ extra_rdoc_files: []
69
+ files:
70
+ - lib/spook_and_puff/money.rb
71
+ - MIT-LICENSE
72
+ - README.md
73
+ homepage: http://spookandpuff.com
74
+ licenses: []
75
+ post_install_message:
76
+ rdoc_options: []
77
+ require_paths:
78
+ - lib
79
+ required_ruby_version: !ruby/object:Gem::Requirement
80
+ none: false
81
+ requirements:
82
+ - - ! '>='
83
+ - !ruby/object:Gem::Version
84
+ version: '0'
85
+ required_rubygems_version: !ruby/object:Gem::Requirement
86
+ none: false
87
+ requirements:
88
+ - - ! '>='
89
+ - !ruby/object:Gem::Version
90
+ version: '0'
91
+ requirements: []
92
+ rubyforge_project:
93
+ rubygems_version: 1.8.24
94
+ signing_key:
95
+ specification_version: 3
96
+ summary: A simple money class.
97
+ test_files: []
98
+ has_rdoc: