money_attribute 0.11.0 → 0.12.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 874e817fa1e157ee49e460c8848dabff3fe525d9849571d21045de2694dd0770
4
- data.tar.gz: 933dcdd5adc296d9aa635da79fc181e15652ed884c2e3b1231655a5652a2beca
3
+ metadata.gz: 306761efbc2f4f645f3e975ea830ff26901bc4ba5fac664346f5d7b5720050b8
4
+ data.tar.gz: 13dfc1b02f256f22ac1027700164ae57cee60bc77e1b233c28549b20988adaf7
5
5
  SHA512:
6
- metadata.gz: b5547742974245c1cffd5b690fa4c763e79224e553c90c2e19e88cdccb0d2c7ccdf669f9000e1917abe01fb880c2a50b0b2b475ffebf3fdfe01b787b0f4630ad
7
- data.tar.gz: d0b760447e051fb0a1dc15492ba737676af935443ad5dcec4fb18988c898db37bf5980781d52cc64a4c60c651d03646ad77bb63ffdb6cb046c6d19f67cc7d092
6
+ metadata.gz: 3d39e999c298070baf49359ed226f9582defac099e4da3b342f3b367df81c658575e973095a0c8de4a19d8c7116af778d38160de6dbb263fd050a6a36bb3f0a9
7
+ data.tar.gz: 02c399705be0e9ac78c3f9dd1bbe9603055d6702df60a43e12e57fb0fa16ecfd4212d129a91294bdb4323f487030def2bc3fe52a7484552b93c4f2e81b6a71ed
data/README.md CHANGED
@@ -91,7 +91,9 @@ The generator creates `config/initializers/money_attribute.rb`.
91
91
 
92
92
  ## Migration helpers
93
93
 
94
- MoneyAttribute adds `add_money` / `remove_money` for existing tables and `t.money` / `t.remove_money` for `create_table` / `change_table` blocks:
94
+ MoneyAttribute adds `add_money` / `remove_money` for existing tables and `t.money` / `t.remove_money` for `create_table` / `change_table` blocks.
95
+
96
+ By default `t.money :price` creates a `decimal(16,4)` amount column and a `string` currency column — both nullable, no default. Pass `amount: { type: :integer }` to store subunits instead, or `currency: false` to skip the currency column entirely.
95
97
 
96
98
  ```ruby
97
99
  class CreateProducts < ActiveRecord::Migration[8.1]
@@ -101,7 +103,7 @@ class CreateProducts < ActiveRecord::Migration[8.1]
101
103
  t.money :price # price (decimal) + price_currency (string)
102
104
  t.money :price_amount # price_amount + price_currency (strips _amount suffix)
103
105
  t.money :fee, currency: false # single column, no currency
104
- t.money :tax, type: :bigint # bigint amount + currency
106
+ t.money :tax, amount: { type: :bigint } # bigint amount + currency
105
107
  t.timestamps
106
108
  end
107
109
  end
@@ -110,7 +112,7 @@ end
110
112
  class AddPriceToProducts < ActiveRecord::Migration[8.1]
111
113
  def change
112
114
  add_money :products, :price # add price + price_currency
113
- add_money :products, :discount, type: :integer
115
+ add_money :products, :discount, amount: { type: :integer }
114
116
  remove_money :products, :obsolete_fee # reversible in change
115
117
  end
116
118
  end
@@ -123,8 +125,19 @@ end
123
125
  | `t.money :price` | `price` decimal + `price_currency` string | `money_attribute :price` |
124
126
  | `t.money :price_amount` | `price_amount` decimal + `price_currency` string | `money_attribute :price` |
125
127
  | `t.money :price, currency: false` | `price` decimal | `money_attribute :price` |
126
- | `t.money :price, type: :integer` | `price` integer + `price_currency` string | `money_attribute :price` |
127
- | `t.money :price, amount: :a, currency: :c` | `a` + `c` | `money_attribute :price, mapping: { amount: :a, currency: :c }` |
128
+ | `t.money :price, amount: { type: :integer }` | `price` integer + `price_currency` string | `money_attribute :price` |
129
+ | `t.money :price, amount: { column: :a }, currency: { column: :c }` | `a` + `c` | `money_attribute :price, mapping: { amount: :a, currency: :c }` |
130
+ | `t.money :price, currency: { limit: 3 }` | `price` decimal + `price_currency` string(3) | `money_attribute :price` |
131
+ | `t.money :price, amount: { precision: 14, scale: 2, null: false }, currency: { limit: 3, default: 'USD' }` | `price` decimal(14,2) NOT NULL + `price_currency` string(3) DEFAULT 'USD' | `money_attribute :price` |
132
+ | `t.remove_money :price` | Removes `price` + `price_currency` | `money_attribute :price` |
133
+
134
+ Inside `change_table`:
135
+
136
+ ```ruby
137
+ change_table :products do |t|
138
+ t.remove_money :obsolete_fee # removes obsolete_fee + obsolete_fee_currency
139
+ end
140
+ ```
128
141
 
129
142
  ## Configuration
130
143
 
@@ -224,6 +237,8 @@ offer = Offer.new(price: '12')
224
237
  offer.price.currency.code # => "USD"
225
238
  ```
226
239
 
240
+ Unlike fixed-currency attributes, composite mode does not enforce a specific currency — any registered currency is accepted at assignment.
241
+
227
242
  ## Column type detection
228
243
 
229
244
  Declare the column as `decimal`, `integer`, or `bigint` — the gem adapts:
@@ -268,7 +283,14 @@ class Invoice < ApplicationRecord
268
283
  end
269
284
  ```
270
285
 
271
- The mapping keys are `:amount` and `:currency`; values are your database column names.
286
+ The mapping keys are `:amount` and `:currency`; values are your database column names. You can provide only one key — the other falls back to the `<name>_amount` / `<name>_currency` convention:
287
+
288
+ ```ruby
289
+ class Invoice < ApplicationRecord
290
+ money_attribute :total, mapping: { amount: :total_amount }
291
+ # currency column inferred as `total_currency`
292
+ end
293
+ ```
272
294
 
273
295
  ## Column resolution
274
296
 
@@ -279,8 +301,10 @@ When you declare `money_attribute :name`, the gem resolves which database column
279
301
  | 1 | `mapping:` provided | As specified | Explicit composite |
280
302
  | 2 | `name_currency` column exists | `name` + `name_currency` | Composite (multi-currency) |
281
303
  | 3 | `name == 'amount'` AND `currency` column exists | `amount` + `currency` | Composite (multi-currency) |
282
- | 4 | `name_amount` + `name_currency` columns exist | `name_amount` + `name_currency` | Composite (multi-currency) |
283
- | 5 | `name` column exists (no currency partner) | `name` alone | Single-column (fixed-currency) |
304
+ | 4 | `name` column exists (no currency partner) | `name` alone | Single-column (fixed-currency) |
305
+ | 5 | None of the above (name column missing) | `name_amount` + `name_currency` (convention) | Composite (multi-currency) |
306
+
307
+ Step 5 raises `ArgumentError` if the convention columns don't exist in the table.
284
308
 
285
309
  **Example**
286
310
 
@@ -8,42 +8,48 @@ module MoneyAttribute
8
8
  def parse_money_args(accessor, options = {})
9
9
  name = accessor.to_s
10
10
 
11
- amount_col = options.key?(:amount) ? options[:amount].to_s : name
12
-
13
- if options.key?(:currency)
14
- currency_col = if options[:currency] == false
15
- nil
16
- else
17
- options[:currency].to_s
18
- end
11
+ if options.key?(:amount) && options[:amount].is_a?(Hash)
12
+ amount_col = options[:amount][:column]&.to_s || name
13
+ opts = options[:amount]
14
+ amount_opts = {
15
+ type: opts[:type],
16
+ null: opts[:null],
17
+ default: opts[:default],
18
+ precision: opts[:precision],
19
+ scale: opts[:scale]
20
+ }.compact
19
21
  else
20
- stripped = name.end_with?('_amount') ? name.sub(/_amount$/, '') : name
21
- currency_col = "#{stripped}_currency"
22
+ amount_col = name
23
+ amount_opts = {}
22
24
  end
23
25
 
24
- col_type = options[:type] || :decimal
25
-
26
- amount_opts = {}
27
- amount_opts[:type] = col_type
26
+ amount_opts[:type] ||= :decimal
28
27
 
29
- if options.key?(:amount) && options[:amount].is_a?(Hash)
30
- amount_opts[:null] = options[:amount][:null] if options[:amount].key?(:null)
31
- amount_opts[:default] = options[:amount][:default] if options[:amount].key?(:default)
32
- amount_opts[:precision] = options[:amount][:precision] if options[:amount].key?(:precision)
33
- amount_opts[:scale] = options[:amount][:scale] if options[:amount].key?(:scale)
34
- end
35
-
36
- if col_type == :decimal && !amount_opts.key?(:precision) && !amount_opts.key?(:scale)
28
+ if amount_opts[:type] == :decimal && !amount_opts.key?(:precision) && !amount_opts.key?(:scale)
37
29
  amount_opts[:precision] = 16
38
30
  amount_opts[:scale] = 4
31
+ elsif amount_opts[:type] != :decimal
32
+ amount_opts.delete(:precision)
33
+ amount_opts.delete(:scale)
39
34
  end
40
35
 
41
- currency_opts = {}
42
- currency_opts[:limit] = options[:currency_limit] if options[:currency_limit]
43
-
44
- if options[:currency].is_a?(Hash)
45
- currency_opts[:null] = options[:currency][:null] if options[:currency].key?(:null)
46
- currency_opts[:default] = options[:currency][:default] if options[:currency].key?(:default)
36
+ stripped = name.end_with?('_amount') ? name.sub(/_amount$/, '') : name
37
+ default_currency_col = "#{stripped}_currency"
38
+
39
+ if options.key?(:currency) && options[:currency].is_a?(Hash)
40
+ currency_col = options[:currency][:column]&.to_s || default_currency_col
41
+ opts = options[:currency]
42
+ currency_opts = {
43
+ limit: opts[:limit],
44
+ null: opts[:null],
45
+ default: opts[:default]
46
+ }.compact
47
+ elsif options[:currency] == false
48
+ currency_col = nil
49
+ currency_opts = {}
50
+ else
51
+ currency_col = default_currency_col
52
+ currency_opts = {}
47
53
  end
48
54
 
49
55
  [amount_col, currency_col, amount_opts, currency_opts]
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module MoneyAttribute
4
- VERSION = '0.11.0'
4
+ VERSION = '0.12.0'
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: money_attribute
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.11.0
4
+ version: 0.12.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Gilson Ferraz