sequel-money-fields 0.1.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.
- checksums.yaml +7 -0
- data/README.md +34 -0
- data/lib/sequel/plugins/money_fields.rb +107 -0
- data/spec/sequel/plugins/money_fields_spec.rb +81 -0
- data/spec/spec_helper.rb +27 -0
- metadata +187 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: a94918adeebbe13b0f3a81e9fd4a0a893489c3a4be15456db5b0a4fd30cf01aa
|
4
|
+
data.tar.gz: e354f31b9cac26e0d7c18cff39218e91eba9d028fc81f3a9c960c1f202d8924a
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: ec255f4145ff10166166c065bcfe2fda483390d782d4d1e10f085a5e54ebcb40592257d684b725e554d926a156636204df9502245967ff0f24acbbdd43e10580
|
7
|
+
data.tar.gz: 393660b834401798060793a215d5748eb7d462bf30ce9efc97d56471b29fa19befec32b3d3aefe0456ba54eab7576dae8f834d04310ed0029d55d506901785a4
|
data/README.md
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
# Sequel::Money::Fields
|
2
|
+
|
3
|
+
Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/sequel/money/fields`. To experiment with that code, run `bin/console` for an interactive prompt.
|
4
|
+
|
5
|
+
TODO: Delete this and the text above, and describe your gem
|
6
|
+
|
7
|
+
## Installation
|
8
|
+
|
9
|
+
Add this line to your application's Gemfile:
|
10
|
+
|
11
|
+
```ruby
|
12
|
+
gem 'sequel_money_fields-money-fields'
|
13
|
+
```
|
14
|
+
|
15
|
+
And then execute:
|
16
|
+
|
17
|
+
$ bundle install
|
18
|
+
|
19
|
+
Or install it yourself as:
|
20
|
+
|
21
|
+
$ gem install sequel-money-fields
|
22
|
+
|
23
|
+
## Usage
|
24
|
+
|
25
|
+
TODO: Write usage instructions here
|
26
|
+
|
27
|
+
|
28
|
+
## Contributing
|
29
|
+
|
30
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/lithictech/sequel-money-fields.
|
31
|
+
|
32
|
+
## License
|
33
|
+
|
34
|
+
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
@@ -0,0 +1,107 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# frozen_string_literal: true
|
4
|
+
|
5
|
+
require "money"
|
6
|
+
require "monetize"
|
7
|
+
|
8
|
+
require "sequel"
|
9
|
+
require "sequel/model"
|
10
|
+
|
11
|
+
# Plugin for adding money fields to a model.
|
12
|
+
#
|
13
|
+
# == Example
|
14
|
+
#
|
15
|
+
# Define a model with money values:
|
16
|
+
#
|
17
|
+
# class ACME::Property < Sequel::Model(:properties)
|
18
|
+
#
|
19
|
+
# plugin :money_fields, :rent
|
20
|
+
#
|
21
|
+
# And in the schema:
|
22
|
+
#
|
23
|
+
# create_table( :properties ) do
|
24
|
+
# primary_key :id
|
25
|
+
# bigint :rent_cents, null: false
|
26
|
+
# text :rent_currency, null: false, default: 'USD'
|
27
|
+
# end
|
28
|
+
#
|
29
|
+
# And used as follows:
|
30
|
+
#
|
31
|
+
# property = ACME::Property.new(rent: Monetize.parse('$5'))
|
32
|
+
# property.rent_cents # 500
|
33
|
+
# property.rent # Money object presenting 5 USD
|
34
|
+
#
|
35
|
+
# Each money field you declare requires two columns: an integer(ish) column that
|
36
|
+
# will store the fractional amount called "#{field}_cents", and a text(ish)
|
37
|
+
# column for storing the currency name called "#{field}_currency".
|
38
|
+
#
|
39
|
+
# The plugin generates methods for getting and setting each field. The setter
|
40
|
+
# automatically parses the input using the 'monetize' gem into a Money object,
|
41
|
+
# and the getter creates a new Money object from the two columns and returns it.
|
42
|
+
#
|
43
|
+
# If you don't give at least one column to the plugin declaration, the field
|
44
|
+
# will be assumed to be called 'money'.
|
45
|
+
#
|
46
|
+
# See the docs for Money and Monetize for details on what you can do with the
|
47
|
+
# Money objects these fields use.
|
48
|
+
#
|
49
|
+
|
50
|
+
module Sequel::Plugins::MoneyFields
|
51
|
+
VERSION = "0.1.0"
|
52
|
+
|
53
|
+
def self.configure(model, *args)
|
54
|
+
args << :money if args.empty?
|
55
|
+
|
56
|
+
args.flatten.each do |field|
|
57
|
+
reader = self.make_money_reader(field)
|
58
|
+
writer = self.make_money_writer(field)
|
59
|
+
|
60
|
+
model.send(:define_method, field.to_s, reader)
|
61
|
+
model.send(:define_method, "#{field}=", writer)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
# Return a Proc that can serve as the method body for the Money amount
|
66
|
+
# reader for the given +field+.
|
67
|
+
def self.make_money_reader(field)
|
68
|
+
cents_column = "#{field}_cents".to_sym
|
69
|
+
currency_column = "#{field}_currency".to_sym
|
70
|
+
|
71
|
+
return lambda do
|
72
|
+
Money.new(self[cents_column], self[currency_column])
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
# Return a Proc that can serve as the method body for the Money amount
|
77
|
+
# writer for the given +field+.
|
78
|
+
def self.make_money_writer(field)
|
79
|
+
cents_column = "#{field}_cents".to_sym
|
80
|
+
currency_column = "#{field}_currency".to_sym
|
81
|
+
|
82
|
+
return lambda do |value|
|
83
|
+
if value.respond_to?(:cents) && value.respond_to?(:currency)
|
84
|
+
money = Money.new(value.cents, value.currency)
|
85
|
+
else
|
86
|
+
begin
|
87
|
+
cents = value[:cents] || value["cents"]
|
88
|
+
cur = value[:currency] || value["currency"]
|
89
|
+
money = Money.new(cents, cur)
|
90
|
+
rescue TypeError, NoMethodError
|
91
|
+
money = Monetize.parse!(value)
|
92
|
+
end
|
93
|
+
end
|
94
|
+
self[cents_column] = money.cents.to_i
|
95
|
+
self[currency_column] = money.currency
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
### Creates readers and writers that allow assignment to the attributes of
|
100
|
+
### the singleton of the declaring object that correspond to the specified
|
101
|
+
### +symbols+.
|
102
|
+
def singleton_attr_accessor(*symbols)
|
103
|
+
symbols.each do |sym|
|
104
|
+
singleton_class.__send__(:attr_accessor, sym)
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "money"
|
4
|
+
require "monetize"
|
5
|
+
require "sequel"
|
6
|
+
require "sequel/model"
|
7
|
+
|
8
|
+
require "sequel/plugins/money_fields"
|
9
|
+
|
10
|
+
RSpec.describe Sequel::Plugins::MoneyFields, :db do
|
11
|
+
context "with no fields given" do
|
12
|
+
before do
|
13
|
+
@db = Sequel.mock
|
14
|
+
@c = Class.new(Sequel::Model(@db)) do
|
15
|
+
set_columns([:id, :money_cents, :money_currency])
|
16
|
+
end
|
17
|
+
@c.plugin :money_fields
|
18
|
+
@m = @c.new
|
19
|
+
end
|
20
|
+
|
21
|
+
# let(:model_object) { model_class.new }
|
22
|
+
|
23
|
+
it "uses :money as the high-level accessor" do
|
24
|
+
@m.money = "$1800"
|
25
|
+
expect(@m.money).to be_a(Money)
|
26
|
+
expect(@m.money_cents).to eq(180_000)
|
27
|
+
expect(@m.money_currency).to eq("USD")
|
28
|
+
|
29
|
+
@m.money = {cents: 200, currency: "CAD"}
|
30
|
+
expect(@m.money_cents).to eq(200)
|
31
|
+
expect(@m.money_currency).to eq("CAD")
|
32
|
+
|
33
|
+
@m.money = OpenStruct.new(cents: 300, currency: "GBP")
|
34
|
+
expect(@m.money_cents).to eq(300)
|
35
|
+
expect(@m.money_currency).to eq("GBP")
|
36
|
+
|
37
|
+
@m.money = {"cents" => 400, "currency" => "EUR"}
|
38
|
+
expect(@m.money_cents).to eq(400)
|
39
|
+
expect(@m.money_currency).to eq("EUR")
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
context "with fields set to 'rent' and 'deposit'" do
|
44
|
+
# let(:model_class) do
|
45
|
+
# mc = create_model(:money_fields_test) do
|
46
|
+
# primary_key :id
|
47
|
+
# integer :rent_cents
|
48
|
+
# text :rent_currency
|
49
|
+
# integer :deposit_cents
|
50
|
+
# text :deposit_currency
|
51
|
+
# end
|
52
|
+
# mc.plugin(:money_fields, :rent, :deposit)
|
53
|
+
# mc
|
54
|
+
# end
|
55
|
+
#
|
56
|
+
# let(:model_object) { model_class.new }
|
57
|
+
|
58
|
+
before do
|
59
|
+
@db = Sequel.mock
|
60
|
+
@c = Class.new(Sequel::Model(@db)) do
|
61
|
+
set_columns([:id, :rent_cents, :rent_currency, :deposit_cents, :deposit_currency])
|
62
|
+
end
|
63
|
+
@c.plugin(:money_fields, :rent, :deposit)
|
64
|
+
@m = @c.new
|
65
|
+
end
|
66
|
+
|
67
|
+
it "provides high-level accessors for each column" do
|
68
|
+
@m.rent = 1250
|
69
|
+
expect(@m.rent).to be_a(Money)
|
70
|
+
expect(@m.rent.cents).to eq(125_000)
|
71
|
+
expect(@m.rent_cents).to eq(125_000)
|
72
|
+
expect(@m.rent_currency).to eq("USD")
|
73
|
+
|
74
|
+
@m.deposit = "CAD 82.50"
|
75
|
+
expect(@m.deposit).to be_a(Money)
|
76
|
+
expect(@m.deposit.cents).to eq(82_50)
|
77
|
+
expect(@m.deposit_cents).to eq(82_50)
|
78
|
+
expect(@m.deposit_currency).to eq("CAD")
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "rspec"
|
4
|
+
require "sequel"
|
5
|
+
require "sequel/plugins/money_fields"
|
6
|
+
|
7
|
+
RSpec.configure do |config|
|
8
|
+
# config.full_backtrace = true
|
9
|
+
|
10
|
+
# RSpec::Support::ObjectFormatter.default_instance.max_formatted_output_length = 600
|
11
|
+
|
12
|
+
config.expect_with :rspec do |expectations|
|
13
|
+
expectations.include_chain_clauses_in_custom_matcher_descriptions = true
|
14
|
+
end
|
15
|
+
|
16
|
+
config.mock_with :rspec do |mocks|
|
17
|
+
mocks.verify_partial_doubles = true
|
18
|
+
end
|
19
|
+
|
20
|
+
config.order = :random
|
21
|
+
Kernel.srand config.seed
|
22
|
+
|
23
|
+
config.filter_run :focus
|
24
|
+
config.run_all_when_everything_filtered = true
|
25
|
+
config.disable_monkey_patching!
|
26
|
+
config.default_formatter = "doc" if config.files_to_run.one?
|
27
|
+
end
|
metadata
ADDED
@@ -0,0 +1,187 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: sequel-money-fields
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Lithic Tech
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2021-04-06 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: monetize
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: money
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: sequel
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rake
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rspec
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: rubocop
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: rubocop-performance
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ">="
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ">="
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: rubocop-rake
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - ">="
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - ">="
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '0'
|
125
|
+
- !ruby/object:Gem::Dependency
|
126
|
+
name: rubocop-rspec
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - ">="
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: '0'
|
132
|
+
type: :development
|
133
|
+
prerelease: false
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - ">="
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: '0'
|
139
|
+
- !ruby/object:Gem::Dependency
|
140
|
+
name: rubocop-sequel
|
141
|
+
requirement: !ruby/object:Gem::Requirement
|
142
|
+
requirements:
|
143
|
+
- - ">="
|
144
|
+
- !ruby/object:Gem::Version
|
145
|
+
version: '0'
|
146
|
+
type: :development
|
147
|
+
prerelease: false
|
148
|
+
version_requirements: !ruby/object:Gem::Requirement
|
149
|
+
requirements:
|
150
|
+
- - ">="
|
151
|
+
- !ruby/object:Gem::Version
|
152
|
+
version: '0'
|
153
|
+
description:
|
154
|
+
email:
|
155
|
+
- hello@lithic.tech
|
156
|
+
executables: []
|
157
|
+
extensions: []
|
158
|
+
extra_rdoc_files: []
|
159
|
+
files:
|
160
|
+
- README.md
|
161
|
+
- lib/sequel/plugins/money_fields.rb
|
162
|
+
- spec/sequel/plugins/money_fields_spec.rb
|
163
|
+
- spec/spec_helper.rb
|
164
|
+
homepage:
|
165
|
+
licenses:
|
166
|
+
- MIT
|
167
|
+
metadata: {}
|
168
|
+
post_install_message:
|
169
|
+
rdoc_options: []
|
170
|
+
require_paths:
|
171
|
+
- lib
|
172
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
173
|
+
requirements:
|
174
|
+
- - ">="
|
175
|
+
- !ruby/object:Gem::Version
|
176
|
+
version: 2.7.2
|
177
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
178
|
+
requirements:
|
179
|
+
- - ">="
|
180
|
+
- !ruby/object:Gem::Version
|
181
|
+
version: '0'
|
182
|
+
requirements: []
|
183
|
+
rubygems_version: 3.1.4
|
184
|
+
signing_key:
|
185
|
+
specification_version: 4
|
186
|
+
summary: Gem for adding money fields to a model
|
187
|
+
test_files: []
|