has_money_fields 0.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.
- data/.gitignore +6 -0
- data/Gemfile +4 -0
- data/Guardfile +8 -0
- data/LICENSE +22 -0
- data/README.md +71 -0
- data/Rakefile +2 -0
- data/has_money_fields.gemspec +32 -0
- data/lib/has_money_fields/version.rb +3 -0
- data/lib/has_money_fields.rb +40 -0
- data/spec/has_money_fields_spec.rb +30 -0
- data/spec/models.rb +15 -0
- data/spec/spec_helper.rb +12 -0
- metadata +182 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/Guardfile
ADDED
@@ -0,0 +1,8 @@
|
|
1
|
+
# A sample Guardfile
|
2
|
+
# More info at https://github.com/guard/guard#readme
|
3
|
+
|
4
|
+
guard 'rspec', :version => 2, :cli => "--color" do
|
5
|
+
watch(%r{^spec/.+_spec\.rb$})
|
6
|
+
watch(%r{^lib/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
|
7
|
+
watch('spec/spec_helper.rb') { "spec" }
|
8
|
+
end
|
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2011 Francisco J. Casas
|
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.
|
21
|
+
|
22
|
+
|
data/README.md
ADDED
@@ -0,0 +1,71 @@
|
|
1
|
+
# Introduction
|
2
|
+
|
3
|
+
`has_money_fields` is a try to DRY the following code from the Money gem
|
4
|
+
documentation
|
5
|
+
|
6
|
+
```ruby
|
7
|
+
composed_of :price,
|
8
|
+
:class_name => "Money",
|
9
|
+
:mapping => [%w(price_cents cents), %w(currency currency_as_string)],
|
10
|
+
:constructor => Proc.new { |cents, currency| Money.new(cents || 0, currency || Money.default_currency) },
|
11
|
+
:converter => Proc.new { |value| value.respond_to?(:to_money) ? value.to_money : raise(ArgumentError, "Can't convert #{value.class} to Money") }
|
12
|
+
```
|
13
|
+
|
14
|
+
It turns that code it into a smal gem that you can use yo provide currency
|
15
|
+
capabilities to fields on your ActiveRecord models.
|
16
|
+
|
17
|
+
## Usage
|
18
|
+
|
19
|
+
You can choose whether to store the currency with you "money" or to leave it to
|
20
|
+
the default you've configured for the gem. For an example `Product` model:
|
21
|
+
|
22
|
+
You'll need a migration like this:
|
23
|
+
|
24
|
+
```ruby
|
25
|
+
class CreateProducts < ActiveRecord::Migration
|
26
|
+
def self.up
|
27
|
+
create_table :products do |t|
|
28
|
+
t.integer :money_price, :default => 0
|
29
|
+
t.string :currency_price
|
30
|
+
|
31
|
+
t.string :name, :null => false
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def self.down
|
36
|
+
drop_table :products
|
37
|
+
end
|
38
|
+
end
|
39
|
+
```
|
40
|
+
|
41
|
+
And a model like that:
|
42
|
+
|
43
|
+
```ruby
|
44
|
+
class Product < ActiveRecord::Base
|
45
|
+
has_money_fields :price
|
46
|
+
end
|
47
|
+
```
|
48
|
+
|
49
|
+
`money_price` will store the amount and 'currency_price' will store the actual
|
50
|
+
currency, so, at the end your product will have a `price` field that you can
|
51
|
+
use like that:
|
52
|
+
|
53
|
+
```ruby
|
54
|
+
p = Product.new :price => Money.new(1000, "EUR"), :name => "T-shirt"
|
55
|
+
|
56
|
+
p.price # => #<Money cents:1000 currency:EUR>
|
57
|
+
p.price.format # => "10.00 €"
|
58
|
+
p.price.cents # => 1000
|
59
|
+
p.price.currency_as_string => "€"
|
60
|
+
```
|
61
|
+
|
62
|
+
To use the default currency from the money gem, you'd rather drop the
|
63
|
+
`currency_price` field from the migration and use `has_money_fields` like that:
|
64
|
+
|
65
|
+
```ruby
|
66
|
+
class Product < ActiveRecord::Base
|
67
|
+
has_money_fields :price, :only_cents => true
|
68
|
+
end
|
69
|
+
```
|
70
|
+
|
71
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "has_money_fields/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "has_money_fields"
|
7
|
+
s.version = HasMoneyFields::VERSION
|
8
|
+
s.platform = Gem::Platform::RUBY
|
9
|
+
s.authors = ["Francisco J. Casas"]
|
10
|
+
s.email = ["fran@zorros.be"]
|
11
|
+
s.homepage = "http://zorros.be"
|
12
|
+
s.summary = %q{Persist your money on a clean and easy way with Money gem}
|
13
|
+
s.description = <<-DESC
|
14
|
+
Use the Money gem and ActiveRecord's composed_of to store fields wich contains
|
15
|
+
currency data in a safe and clean way.
|
16
|
+
DESC
|
17
|
+
|
18
|
+
s.rubyforge_project = "has_money_fields"
|
19
|
+
|
20
|
+
s.files = `git ls-files`.split("\n")
|
21
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
22
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
23
|
+
s.require_paths = ["lib"]
|
24
|
+
|
25
|
+
s.add_dependency "activerecord", ">= 3.0"
|
26
|
+
s.add_dependency "money"
|
27
|
+
s.add_development_dependency "sqlite3"
|
28
|
+
s.add_development_dependency "rspec", "~> 2"
|
29
|
+
s.add_development_dependency "ruby-debug"
|
30
|
+
s.add_development_dependency "guard"
|
31
|
+
s.add_development_dependency "guard-rspec"
|
32
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'active_record'
|
2
|
+
require 'money'
|
3
|
+
|
4
|
+
module HasMoneyFields
|
5
|
+
module ClassMethods
|
6
|
+
def has_money_fields *args
|
7
|
+
options = args.extract_options!
|
8
|
+
options.symbolize_keys!
|
9
|
+
options.assert_valid_keys(:only_cents)
|
10
|
+
|
11
|
+
args.each do |attr|
|
12
|
+
constructor = Proc.new do |cents, currency|
|
13
|
+
Money.new(cents || 0, currency || Money.default_currency)
|
14
|
+
end
|
15
|
+
|
16
|
+
converter = Proc.new do |value|
|
17
|
+
if value.respond_to? :to_money
|
18
|
+
value.to_money
|
19
|
+
else
|
20
|
+
raise(ArgumentError, "Can't convert #{value.class} to Money")
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
if options[:only_cents]
|
25
|
+
mapping = [["money_#{attr.to_s}", "cents"]]
|
26
|
+
else
|
27
|
+
mapping = [["money_#{attr.to_s}", "cents"], ["currency_#{attr.to_s}", "currency_as_string"]]
|
28
|
+
end
|
29
|
+
|
30
|
+
self.composed_of attr,
|
31
|
+
:class_name => "Money",
|
32
|
+
:mapping => mapping,
|
33
|
+
:constructor => constructor,
|
34
|
+
:converter => converter
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
ActiveRecord::Base.send :extend, HasMoneyFields::ClassMethods
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require "spec/spec_helper"
|
2
|
+
|
3
|
+
describe "Model with money fields" do
|
4
|
+
context "for cents and currency" do
|
5
|
+
before do
|
6
|
+
@product = Product.new :price => Money.new(1000, "EUR"),
|
7
|
+
:name => "Ruby T-shirt"
|
8
|
+
end
|
9
|
+
subject { @product }
|
10
|
+
|
11
|
+
its(:money_price) { should == 1000 }
|
12
|
+
its(:currency_price) { should eq("EUR") }
|
13
|
+
its(:price) { should == Money.new(1000, "EUR") }
|
14
|
+
end
|
15
|
+
|
16
|
+
context "only for cents" do
|
17
|
+
before do
|
18
|
+
@product = Product.create! :price_in_usd => Money.new(1000),
|
19
|
+
:name => "Ruby T-shirt"
|
20
|
+
end
|
21
|
+
subject { @product }
|
22
|
+
|
23
|
+
it "doesn't have a stored currency" do
|
24
|
+
@product.respond_to?(:currency_price_in_usd).should be_false
|
25
|
+
end
|
26
|
+
|
27
|
+
its(:money_price_in_usd) { should == 1000 }
|
28
|
+
its(:price_in_usd) { should == Money.new(1000, "USD") }
|
29
|
+
end
|
30
|
+
end
|
data/spec/models.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
ActiveRecord::Schema.define(:version => 1) do
|
2
|
+
create_table :products do |t|
|
3
|
+
t.integer :money_price, :default => 0
|
4
|
+
t.string :currency_price
|
5
|
+
|
6
|
+
t.integer :money_price_in_usd, :default => 0
|
7
|
+
|
8
|
+
t.string :name, :null => false
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
class Product < ActiveRecord::Base
|
13
|
+
has_money_fields :price
|
14
|
+
has_money_fields :price_in_usd, :only_cents => true
|
15
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
require 'active_record'
|
2
|
+
|
3
|
+
$LOAD_PATH << File.expand_path("../lib", File.dirname(__FILE__))
|
4
|
+
|
5
|
+
# ---- setup environment/plugin
|
6
|
+
ActiveRecord::Base.establish_connection({
|
7
|
+
:adapter => "sqlite3",
|
8
|
+
:database => ":memory:",
|
9
|
+
})
|
10
|
+
|
11
|
+
require 'lib/has_money_fields'
|
12
|
+
require 'spec/models'
|
metadata
ADDED
@@ -0,0 +1,182 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: has_money_fields
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 29
|
5
|
+
prerelease:
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 0
|
9
|
+
- 1
|
10
|
+
version: 0.0.1
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Francisco J. Casas
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2011-07-11 00:00:00 +02:00
|
19
|
+
default_executable:
|
20
|
+
dependencies:
|
21
|
+
- !ruby/object:Gem::Dependency
|
22
|
+
name: activerecord
|
23
|
+
prerelease: false
|
24
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ">="
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
hash: 7
|
30
|
+
segments:
|
31
|
+
- 3
|
32
|
+
- 0
|
33
|
+
version: "3.0"
|
34
|
+
type: :runtime
|
35
|
+
version_requirements: *id001
|
36
|
+
- !ruby/object:Gem::Dependency
|
37
|
+
name: money
|
38
|
+
prerelease: false
|
39
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
40
|
+
none: false
|
41
|
+
requirements:
|
42
|
+
- - ">="
|
43
|
+
- !ruby/object:Gem::Version
|
44
|
+
hash: 3
|
45
|
+
segments:
|
46
|
+
- 0
|
47
|
+
version: "0"
|
48
|
+
type: :runtime
|
49
|
+
version_requirements: *id002
|
50
|
+
- !ruby/object:Gem::Dependency
|
51
|
+
name: sqlite3
|
52
|
+
prerelease: false
|
53
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
54
|
+
none: false
|
55
|
+
requirements:
|
56
|
+
- - ">="
|
57
|
+
- !ruby/object:Gem::Version
|
58
|
+
hash: 3
|
59
|
+
segments:
|
60
|
+
- 0
|
61
|
+
version: "0"
|
62
|
+
type: :development
|
63
|
+
version_requirements: *id003
|
64
|
+
- !ruby/object:Gem::Dependency
|
65
|
+
name: rspec
|
66
|
+
prerelease: false
|
67
|
+
requirement: &id004 !ruby/object:Gem::Requirement
|
68
|
+
none: false
|
69
|
+
requirements:
|
70
|
+
- - ~>
|
71
|
+
- !ruby/object:Gem::Version
|
72
|
+
hash: 7
|
73
|
+
segments:
|
74
|
+
- 2
|
75
|
+
version: "2"
|
76
|
+
type: :development
|
77
|
+
version_requirements: *id004
|
78
|
+
- !ruby/object:Gem::Dependency
|
79
|
+
name: ruby-debug
|
80
|
+
prerelease: false
|
81
|
+
requirement: &id005 !ruby/object:Gem::Requirement
|
82
|
+
none: false
|
83
|
+
requirements:
|
84
|
+
- - ">="
|
85
|
+
- !ruby/object:Gem::Version
|
86
|
+
hash: 3
|
87
|
+
segments:
|
88
|
+
- 0
|
89
|
+
version: "0"
|
90
|
+
type: :development
|
91
|
+
version_requirements: *id005
|
92
|
+
- !ruby/object:Gem::Dependency
|
93
|
+
name: guard
|
94
|
+
prerelease: false
|
95
|
+
requirement: &id006 !ruby/object:Gem::Requirement
|
96
|
+
none: false
|
97
|
+
requirements:
|
98
|
+
- - ">="
|
99
|
+
- !ruby/object:Gem::Version
|
100
|
+
hash: 3
|
101
|
+
segments:
|
102
|
+
- 0
|
103
|
+
version: "0"
|
104
|
+
type: :development
|
105
|
+
version_requirements: *id006
|
106
|
+
- !ruby/object:Gem::Dependency
|
107
|
+
name: guard-rspec
|
108
|
+
prerelease: false
|
109
|
+
requirement: &id007 !ruby/object:Gem::Requirement
|
110
|
+
none: false
|
111
|
+
requirements:
|
112
|
+
- - ">="
|
113
|
+
- !ruby/object:Gem::Version
|
114
|
+
hash: 3
|
115
|
+
segments:
|
116
|
+
- 0
|
117
|
+
version: "0"
|
118
|
+
type: :development
|
119
|
+
version_requirements: *id007
|
120
|
+
description: |
|
121
|
+
Use the Money gem and ActiveRecord's composed_of to store fields wich contains
|
122
|
+
currency data in a safe and clean way.
|
123
|
+
|
124
|
+
email:
|
125
|
+
- fran@zorros.be
|
126
|
+
executables: []
|
127
|
+
|
128
|
+
extensions: []
|
129
|
+
|
130
|
+
extra_rdoc_files: []
|
131
|
+
|
132
|
+
files:
|
133
|
+
- .gitignore
|
134
|
+
- Gemfile
|
135
|
+
- Guardfile
|
136
|
+
- LICENSE
|
137
|
+
- README.md
|
138
|
+
- Rakefile
|
139
|
+
- has_money_fields.gemspec
|
140
|
+
- lib/has_money_fields.rb
|
141
|
+
- lib/has_money_fields/version.rb
|
142
|
+
- spec/has_money_fields_spec.rb
|
143
|
+
- spec/models.rb
|
144
|
+
- spec/spec_helper.rb
|
145
|
+
has_rdoc: true
|
146
|
+
homepage: http://zorros.be
|
147
|
+
licenses: []
|
148
|
+
|
149
|
+
post_install_message:
|
150
|
+
rdoc_options: []
|
151
|
+
|
152
|
+
require_paths:
|
153
|
+
- lib
|
154
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
155
|
+
none: false
|
156
|
+
requirements:
|
157
|
+
- - ">="
|
158
|
+
- !ruby/object:Gem::Version
|
159
|
+
hash: 3
|
160
|
+
segments:
|
161
|
+
- 0
|
162
|
+
version: "0"
|
163
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
164
|
+
none: false
|
165
|
+
requirements:
|
166
|
+
- - ">="
|
167
|
+
- !ruby/object:Gem::Version
|
168
|
+
hash: 3
|
169
|
+
segments:
|
170
|
+
- 0
|
171
|
+
version: "0"
|
172
|
+
requirements: []
|
173
|
+
|
174
|
+
rubyforge_project: has_money_fields
|
175
|
+
rubygems_version: 1.5.3
|
176
|
+
signing_key:
|
177
|
+
specification_version: 3
|
178
|
+
summary: Persist your money on a clean and easy way with Money gem
|
179
|
+
test_files:
|
180
|
+
- spec/has_money_fields_spec.rb
|
181
|
+
- spec/models.rb
|
182
|
+
- spec/spec_helper.rb
|