picklive-currency 1.0.0

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
+ pkg
data/Gemfile ADDED
@@ -0,0 +1,10 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in picklive-currency.gemspec
4
+ gemspec
5
+
6
+ group :development do
7
+ gem 'guard'
8
+ gem 'guard-rspec'
9
+ gem 'rake'
10
+ end
@@ -0,0 +1,68 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ picklive-currency (0.0.1)
5
+ actionpack
6
+
7
+ GEM
8
+ remote: http://rubygems.org/
9
+ specs:
10
+ actionpack (3.1.2)
11
+ activemodel (= 3.1.2)
12
+ activesupport (= 3.1.2)
13
+ builder (~> 3.0.0)
14
+ erubis (~> 2.7.0)
15
+ i18n (~> 0.6)
16
+ rack (~> 1.3.5)
17
+ rack-cache (~> 1.1)
18
+ rack-mount (~> 0.8.2)
19
+ rack-test (~> 0.6.1)
20
+ sprockets (~> 2.1.0)
21
+ activemodel (3.1.2)
22
+ activesupport (= 3.1.2)
23
+ builder (~> 3.0.0)
24
+ i18n (~> 0.6)
25
+ activesupport (3.1.2)
26
+ multi_json (~> 1.0)
27
+ builder (3.0.0)
28
+ diff-lcs (1.1.3)
29
+ erubis (2.7.0)
30
+ guard (0.8.8)
31
+ thor (~> 0.14.6)
32
+ guard-rspec (0.5.1)
33
+ guard (>= 0.8.4)
34
+ hike (1.2.1)
35
+ i18n (0.6.0)
36
+ multi_json (1.0.3)
37
+ rack (1.3.5)
38
+ rack-cache (1.1)
39
+ rack (>= 0.4)
40
+ rack-mount (0.8.3)
41
+ rack (>= 1.0.0)
42
+ rack-test (0.6.1)
43
+ rack (>= 1.0)
44
+ rake (0.9.2)
45
+ rspec (2.7.0)
46
+ rspec-core (~> 2.7.0)
47
+ rspec-expectations (~> 2.7.0)
48
+ rspec-mocks (~> 2.7.0)
49
+ rspec-core (2.7.1)
50
+ rspec-expectations (2.7.0)
51
+ diff-lcs (~> 1.1.2)
52
+ rspec-mocks (2.7.0)
53
+ sprockets (2.1.1)
54
+ hike (~> 1.2)
55
+ rack (~> 1.0)
56
+ tilt (~> 1.1, != 1.3.0)
57
+ thor (0.14.6)
58
+ tilt (1.3.3)
59
+
60
+ PLATFORMS
61
+ ruby
62
+
63
+ DEPENDENCIES
64
+ guard
65
+ guard-rspec
66
+ picklive-currency!
67
+ rake
68
+ rspec
@@ -0,0 +1,6 @@
1
+ guard 'rspec' do
2
+ watch(%r{^spec/.+_spec\.rb$})
3
+ watch(%r{^lib/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
4
+ end
5
+
6
+
@@ -0,0 +1,52 @@
1
+ # picklive-currency
2
+
3
+ Classes for representing amounts of money or virtual money.
4
+
5
+ Currently it has GBP and Chips currencies built in.
6
+
7
+ ## Examples
8
+
9
+ ```ruby
10
+ # The amount can be given in as the usual value or the integer value:
11
+ GBP[5.20] == GBP.new(520) # => true
12
+
13
+ # They are comparable:
14
+ GBP[3.10] > GBP[3.09] # => true
15
+ GBP[3.10] > GBP[3.10] # => false
16
+
17
+ # You can compare with an integer value
18
+ GBP[3.10] > 309 # => true
19
+
20
+ # Equality check is more strict:
21
+ GBP[3.10] == 310 # => false
22
+
23
+ # Objects are instances of Picklive::Currency::Base
24
+ GBP[3.10].is_a? Picklive::Currency::Base # => true
25
+
26
+ GBP[3.10].to_s # => "£3.10"
27
+ Chips[100].to_s # => "100 Chips"
28
+
29
+ Chips[100].class.real? # => false
30
+ Chips[100].class.virtual? # => true
31
+ GBP[3.10].class.real? # => true
32
+
33
+ class Transaction
34
+ attr_accessor :amount_in_pennies
35
+ attr_accessor :currency_code
36
+ include Picklive::Currency::ModelMethods
37
+ include Picklive::Currency::Converters
38
+ currency_field :amount
39
+ end
40
+
41
+ t = Transaction.new
42
+ t.amount_in_pennies = 310
43
+ t.currency_code = 'GBP'
44
+
45
+ t.amount # => <GBP:3.1>
46
+ t.amount_in_currency # => <GBP:3.1>
47
+
48
+ t.amount = Chips[100]
49
+ t.amount_in_pennies # => 100
50
+ t.currency_code # => "chips"
51
+ ```
52
+
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+
3
+ require 'rspec/core/rake_task'
4
+ RSpec::Core::RakeTask.new(:spec)
5
+ task :default => :spec
6
+
@@ -0,0 +1,3 @@
1
+ # -*- encoding : utf-8 -*-
2
+
3
+ require 'picklive/currency'
@@ -0,0 +1,243 @@
1
+ # -*- encoding : utf-8 -*-
2
+
3
+ require 'action_view'
4
+
5
+ module Picklive
6
+ module Currency
7
+
8
+ def self.[](code)
9
+ puts "WARN: Currency code #{code.inspect} is DEPRECATED" if code == 'chip'
10
+ return GBP if code == 'GBP'
11
+ return Chips if code == 'chips' || code == 'chip'
12
+ raise ArgumentError.new("unknown currency code: #{code.inspect}")
13
+ end
14
+
15
+ def self.all ; [GBP, Chips] ; end
16
+ def self.cash_codes ; 'GBP' ; end
17
+ def self.virtual_codes ; 'chips' ; end
18
+
19
+ # To create a currency object:
20
+ #
21
+ # GBP.new(1000) # -> <GBP:10.0>
22
+ # GBP[10] # -> <GBP:10.0>
23
+ # GBP['10.00'] # -> <GBP:10.0>
24
+ # Chips[1000] # -> <Chips:1000>
25
+ class Base
26
+ def self.fake? ; not real? ; end
27
+ def self.cash? ; real? ; end
28
+ def self.virtual? ; !cash? ; end
29
+ def self.html_symbol ; symbol ; end
30
+
31
+ attr_accessor :integer_amount
32
+ private :integer_amount=
33
+
34
+ def initialize integer_amount
35
+ self.integer_amount = integer_amount.to_i
36
+ end
37
+
38
+ def self.[](human_value)
39
+ v = human_value.to_f
40
+ new((v * self.precision).round)
41
+ end
42
+
43
+ def amount
44
+ if self.class.precision == 1
45
+ integer_amount
46
+ else
47
+ integer_amount / self.class.precision.to_f
48
+ end
49
+ end
50
+ alias_method :to_decimal, :amount
51
+
52
+ def +(other); same_type!(other); self.class.new(integer_amount + num_from(other)); end
53
+ def -(other); same_type!(other); self.class.new(integer_amount - num_from(other)); end
54
+ def *(multiplier); self.class.new(integer_amount * multiplier); end
55
+ def /(divider); self.*(1/divider.to_f); end
56
+ def -@; self.class.new(-integer_amount); end
57
+ def abs; self.class.new(integer_amount.abs); end
58
+
59
+ include Comparable
60
+ def <=>(other); same_type!(other); self.integer_amount <=> num_from(other); end
61
+ def ==(other)
62
+ if other.is_a?(self.class)
63
+ self.integer_amount == other.integer_amount
64
+ else
65
+ self.integer_amount == 0 && (other.respond_to?(:to_i) && other.to_i == 0)
66
+ end
67
+ end
68
+ def eql?(other); self == other; end
69
+
70
+ def same_type!(other)
71
+ unless other.is_a?(Fixnum) || other.is_a?(Float)
72
+ unless other.is_a?(Picklive::Currency::Base)
73
+ raise "Not a currency: #{other.inspect}"
74
+ end
75
+ if self.class.code != other.class.code
76
+ raise ArgumentError.new("Different currencies: #{self.class.code} vs #{other.class.code}")
77
+ end
78
+ end
79
+ end
80
+
81
+ def num_from(other)
82
+ other.respond_to?(:integer_amount) ? other.integer_amount : other
83
+ end
84
+
85
+ def to_i; integer_amount; end
86
+ def to_f; integer_amount.to_f; end
87
+ def inspect; "<#{self.class.code}:#{amount}>"; end
88
+
89
+ def for_sentence
90
+ to_s(:short => true)
91
+ end
92
+ end
93
+
94
+
95
+ class GBP < Base
96
+ def self.precision ; 100 ; end
97
+ def self.code ; 'GBP' ; end
98
+ def self.real? ; true ; end
99
+ def self.symbol ; '£' ; end
100
+ def self.html_symbol ; '&pound;' ; end
101
+
102
+ include ActionView::Helpers::NumberHelper
103
+
104
+ def to_s options = {}
105
+ s = number_to_currency(amount, :unit => '£')
106
+ if options[:short]
107
+ if amount < 1.0
108
+ s = "#{integer_amount}p"
109
+ else
110
+ s = s.gsub(/\.0+$/, '')
111
+ end
112
+ end
113
+ s
114
+ end
115
+ end
116
+
117
+
118
+ class Chips < Base
119
+ def self.precision ; 1 ; end
120
+ def self.code ; 'chips' ; end
121
+ def self.real? ; false ; end
122
+ def self.symbol ; '' ; end
123
+
124
+ include ActionView::Helpers::TextHelper
125
+
126
+ def to_s
127
+ pluralize(amount, "Chip")
128
+ end
129
+ end
130
+
131
+
132
+ # It provides scopes for models that have a `currency_code` method.
133
+ module ModelMethods
134
+
135
+ def self.included(base)
136
+ if defined?(ActiveRecord::Base) && base.superclass == ActiveRecord::Base
137
+ base.class_eval do
138
+ scope :cash_only, where(:currency_code => Picklive::Currency.cash_codes)
139
+ scope :virtual_only, where(:currency_code => Picklive::Currency.virtual_codes)
140
+ end
141
+ end
142
+ end
143
+
144
+ def currency
145
+ Picklive::Currency[currency_code]
146
+ end
147
+
148
+ def amount_in_currency
149
+ currency.new(amount_in_pennies)
150
+ end
151
+ end
152
+
153
+ # Provides setters and getters for `something_in_currency`, alias: `something`
154
+ # Mix it into classes that have `something_in_pennies` setter/getter and call:
155
+ # cuurrency_field :something
156
+ module Converters
157
+ def self.included(base)
158
+ base.instance_eval do
159
+ def currency_field(*fields)
160
+ self.class_eval do
161
+
162
+ fields.each do |field|
163
+ define_method "#{field}_in_currency" do
164
+ pennies = self.send("#{field}_in_pennies")
165
+ currency.new(pennies) unless pennies.nil?
166
+ end
167
+
168
+ define_method "#{field}_in_currency=" do |amount_in_currency|
169
+ if ! amount_in_currency.is_a?(Picklive::Currency::Base)
170
+ amount_in_currency = Picklive::Currency::GBP.new((amount_in_currency.to_f * Picklive::Currency::GBP.precision).round)
171
+ end
172
+ if self.respond_to?("currency_code=")
173
+ self.currency_code = amount_in_currency.class.code
174
+ end
175
+ self.send("#{field}_in_pennies=", amount_in_currency.integer_amount)
176
+ end
177
+
178
+ alias_method :"#{field}", :"#{field}_in_currency"
179
+ alias_method :"#{field}=", :"#{field}_in_currency="
180
+
181
+ end
182
+ end
183
+ end
184
+
185
+ def currency_fields(*fields)
186
+ currency_field(*fields)
187
+ end
188
+ end
189
+ end
190
+ end
191
+
192
+ end
193
+ end
194
+
195
+ GBP = Picklive::Currency::GBP
196
+ Chips = Picklive::Currency::Chips
197
+
198
+ class Fixnum
199
+ def percent
200
+ self.to_f / 100
201
+ end
202
+
203
+ def pounds
204
+ (self * 100).pennies
205
+ end
206
+ alias_method :pound, :pounds
207
+
208
+ def pennies
209
+ Picklive::Currency::GBP.new(self)
210
+ end
211
+ alias_method :pence, :pennies
212
+
213
+ def to_pounds
214
+ self / 100.0
215
+ end
216
+
217
+ def to_pennies
218
+ self * 100
219
+ end
220
+
221
+ def chips
222
+ Picklive::Currency::Chips.new(self)
223
+ end
224
+ end
225
+
226
+ class Float
227
+ def pounds
228
+ (self * 100).round.pennies
229
+ end
230
+ alias_method :pound, :pounds
231
+
232
+ def to_pennies
233
+ (self * 100).round
234
+ end
235
+ end
236
+
237
+ class String
238
+ def pounds
239
+ to_f.pounds
240
+ end
241
+ alias_method :pound, :pounds
242
+ end
243
+
@@ -0,0 +1,5 @@
1
+ # -*- encoding : utf-8 -*-
2
+
3
+ module Picklive
4
+ autoload :Currency, 'picklive/currency'
5
+ end
@@ -0,0 +1,25 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+
4
+ require 'picklive/currency/autoload'
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = "picklive-currency"
8
+ s.version = "1.0.0"
9
+ s.authors = ["Levente Bagi"]
10
+ s.email = ["levente@picklive.com"]
11
+ s.homepage = "https://tech.picklive.com"
12
+ s.summary = %q{Picklive Currency}
13
+ s.description = %q{Currency classes that can represent GBP or Chips}
14
+
15
+ s.rubyforge_project = "picklive-currency"
16
+
17
+ s.files = `git ls-files`.split("\n")
18
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
19
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
20
+ s.require_paths = ["lib"]
21
+
22
+ s.add_dependency "actionpack"
23
+ s.add_development_dependency "rspec"
24
+
25
+ end
@@ -0,0 +1,53 @@
1
+ # -*- encoding : utf-8 -*-
2
+
3
+ require 'picklive/currency'
4
+
5
+ describe Picklive::Currency do
6
+
7
+ it "knows about GBP" do
8
+ Picklive::Currency['GBP'].should == GBP
9
+ end
10
+
11
+ it "knows about chips" do
12
+ Picklive::Currency['chips'].should == Chips
13
+ end
14
+
15
+ describe "currency 0 value" do
16
+ it "is equal to 0 as integer" do
17
+ (GBP.new(0) == 0).should be_true
18
+ end
19
+ end
20
+
21
+ describe "currency nonzero value" do
22
+ it "is not equal to the integer value" do
23
+ (GBP.new(100) == 100).should be_false
24
+ end
25
+ end
26
+
27
+ it "can be created in to different ways, which create equal objects" do
28
+ GBP[5.20].should == GBP.new(520)
29
+ end
30
+
31
+ it "is comparable with same type" do
32
+ (GBP[3.10] > GBP[3.09]).should be_true
33
+ (GBP[3.10] > GBP[3.10]).should be_false
34
+ end
35
+
36
+ it "is not comparable with a different type" do
37
+ expect { GBP[3.10] > Chips[309] }.to raise_error
38
+ end
39
+
40
+ it "is comparable to an integer, except for equality" do
41
+ (GBP[3.10] > 309).should be_true
42
+ (GBP[3.10] > 310).should be_false
43
+ (GBP[3.10] == 310).should be_false
44
+ (GBP[3.10] != 310).should be_true
45
+ end
46
+
47
+ it "has a format that can be included in sentences" do
48
+ "Give me #{GBP[5].for_sentence}".should == "Give me £5"
49
+ "Give me #{GBP[0.1].for_sentence}".should == "Give me 10p"
50
+ end
51
+ end
52
+
53
+
metadata ADDED
@@ -0,0 +1,103 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: picklive-currency
3
+ version: !ruby/object:Gem::Version
4
+ hash: 23
5
+ prerelease:
6
+ segments:
7
+ - 1
8
+ - 0
9
+ - 0
10
+ version: 1.0.0
11
+ platform: ruby
12
+ authors:
13
+ - Levente Bagi
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2012-02-14 00:00:00 Z
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: actionpack
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
24
+ none: false
25
+ requirements:
26
+ - - ">="
27
+ - !ruby/object:Gem::Version
28
+ hash: 3
29
+ segments:
30
+ - 0
31
+ version: "0"
32
+ type: :runtime
33
+ version_requirements: *id001
34
+ - !ruby/object:Gem::Dependency
35
+ name: rspec
36
+ prerelease: false
37
+ requirement: &id002 !ruby/object:Gem::Requirement
38
+ none: false
39
+ requirements:
40
+ - - ">="
41
+ - !ruby/object:Gem::Version
42
+ hash: 3
43
+ segments:
44
+ - 0
45
+ version: "0"
46
+ type: :development
47
+ version_requirements: *id002
48
+ description: Currency classes that can represent GBP or Chips
49
+ email:
50
+ - levente@picklive.com
51
+ executables: []
52
+
53
+ extensions: []
54
+
55
+ extra_rdoc_files: []
56
+
57
+ files:
58
+ - .gitignore
59
+ - Gemfile
60
+ - Gemfile.lock
61
+ - Guardfile
62
+ - README.md
63
+ - Rakefile
64
+ - lib/picklive-currency.rb
65
+ - lib/picklive/currency.rb
66
+ - lib/picklive/currency/autoload.rb
67
+ - picklive-currency.gemspec
68
+ - spec/picklive/currency_spec.rb
69
+ homepage: https://tech.picklive.com
70
+ licenses: []
71
+
72
+ post_install_message:
73
+ rdoc_options: []
74
+
75
+ require_paths:
76
+ - lib
77
+ required_ruby_version: !ruby/object:Gem::Requirement
78
+ none: false
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ hash: 3
83
+ segments:
84
+ - 0
85
+ version: "0"
86
+ required_rubygems_version: !ruby/object:Gem::Requirement
87
+ none: false
88
+ requirements:
89
+ - - ">="
90
+ - !ruby/object:Gem::Version
91
+ hash: 3
92
+ segments:
93
+ - 0
94
+ version: "0"
95
+ requirements: []
96
+
97
+ rubyforge_project: picklive-currency
98
+ rubygems_version: 1.8.10
99
+ signing_key:
100
+ specification_version: 3
101
+ summary: Picklive Currency
102
+ test_files:
103
+ - spec/picklive/currency_spec.rb