minting-rails 0.8.2 → 0.8.4
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 +4 -4
- data/README.md +51 -0
- data/lib/generators/templates/minting.rb +2 -2
- data/lib/minting/money_attribute/money_attribute.rb +66 -40
- data/lib/minting/money_attribute/money_type.rb +2 -2
- data/lib/minting/money_attribute/version.rb +1 -1
- data/lib/minting/railties.rb +5 -3
- metadata +11 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 51ccbfc5e1da101cf48481d812400763aa410925247386b4a7471030ce301790
|
|
4
|
+
data.tar.gz: 2ee25dd8e7d055429ed72827d9c6637be59555ade55d8964d01809388c5e430f
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 7326b98ee8731f4139e0e48dfaeed3569a98ea57c59b01db0582762a4546bc550fd8e0950e2f97be48ec6a872c1ea9d18b659b6d2de8dca150d6d7b33e1f4fe7
|
|
7
|
+
data.tar.gz: 244facdd52251db6a7e250a6ceab68b5553972501ea89d80749f998c58e454bf380401c35b1d12b5064e8ad5649677b72679ccbee8e9e2c7a0d8b9a71e11142a
|
data/README.md
CHANGED
|
@@ -1,3 +1,14 @@
|
|
|
1
|
+
> **⚠️ DEPRECATED — use [money-attribute](https://github.com/gferraz/money-attribute) instead.**
|
|
2
|
+
>
|
|
3
|
+
> Since June of 2026, `minting-rails` has been renamed to **money-attribute** and will no longer be maintained.
|
|
4
|
+
> All future development happens under the new name. Update your Gemfile:
|
|
5
|
+
>
|
|
6
|
+
> ```ruby
|
|
7
|
+
> gem 'money-attribute'
|
|
8
|
+
> ```
|
|
9
|
+
>
|
|
10
|
+
> The API is identical — just replace the gem name and you're done.
|
|
11
|
+
|
|
1
12
|
# Minting::Rails
|
|
2
13
|
|
|
3
14
|
[](https://github.com/gferraz/minting-rails/actions/workflows/ci.yml)
|
|
@@ -269,6 +280,46 @@ end
|
|
|
269
280
|
|
|
270
281
|
The mapping keys are `:amount` and `:currency`; values are your database column names.
|
|
271
282
|
|
|
283
|
+
## Column resolution
|
|
284
|
+
|
|
285
|
+
When you declare `money_attribute :name`, the gem resolves which database columns to use by checking the table schema in this order:
|
|
286
|
+
|
|
287
|
+
| Step | Condition | Columns used | Mode |
|
|
288
|
+
|---|---|---|---|
|
|
289
|
+
| 1 | `mapping:` provided | As specified | Explicit composite |
|
|
290
|
+
| 2 | `name_currency` column exists | `name` + `name_currency` | Composite (multi-currency) |
|
|
291
|
+
| 3 | `name == 'amount'` AND `currency` column exists | `amount` + `currency` | Composite (multi-currency) |
|
|
292
|
+
| 4 | `name_amount` + `name_currency` columns exist | `name_amount` + `name_currency` | Composite (multi-currency) |
|
|
293
|
+
| 5 | `name` column exists (no currency partner) | `name` alone | Single-column (fixed-currency) |
|
|
294
|
+
|
|
295
|
+
**Example**
|
|
296
|
+
|
|
297
|
+
```ruby
|
|
298
|
+
create_table :financial_transactions do |t|
|
|
299
|
+
t.integer :amount
|
|
300
|
+
t.string :currency, limit: 3
|
|
301
|
+
t.integer :discount
|
|
302
|
+
t.string :discount_currency, limit: 3
|
|
303
|
+
t.decimal :price_amount
|
|
304
|
+
t.string :price_currency, limit: 3
|
|
305
|
+
t.bigint :surplus
|
|
306
|
+
t.bigint :tax
|
|
307
|
+
t.decimal :total_amount
|
|
308
|
+
t.string :currency_code, limit: 3
|
|
309
|
+
end
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
```ruby
|
|
313
|
+
class FinancialTransaction < ApplicationRecord
|
|
314
|
+
money_attribute :amount # step 3: amount(int) + currency
|
|
315
|
+
money_attribute :discount # step 2: discount(int) + discount_currency
|
|
316
|
+
money_attribute :price # step 4: price_amount(dec) + price_currency
|
|
317
|
+
money_attribute :surplus, currency: 'EUR' # step 5: surplus(int) (single-column, will use EUR)
|
|
318
|
+
money_attribute :tax # step 5: tax(int) (single-column, will use default currency)
|
|
319
|
+
money_attribute :total, mapping: { amount: :total_amount, currency: :currency_code } # step 1: explicit
|
|
320
|
+
end
|
|
321
|
+
```
|
|
322
|
+
|
|
272
323
|
## Querying
|
|
273
324
|
|
|
274
325
|
Fixed-currency attributes support Rails-native querying through the custom type:
|
|
@@ -10,8 +10,8 @@ Mint.configure do |config|
|
|
|
10
10
|
# {currency: 'NGN', subunit: 3, symbol: '₦'}
|
|
11
11
|
# ]
|
|
12
12
|
config.added_currencies = [
|
|
13
|
-
{ currency: '
|
|
14
|
-
{ currency: '
|
|
13
|
+
{ currency: 'XCRC', subunit: 2, symbol: '₡' },
|
|
14
|
+
{ currency: 'XNGN', subunit: 3, symbol: '₦' }
|
|
15
15
|
]
|
|
16
16
|
|
|
17
17
|
# To set the default currency
|
|
@@ -1,65 +1,91 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
module Mint
|
|
4
|
-
# MoneyAttribute
|
|
5
4
|
module MoneyAttribute
|
|
6
5
|
extend ActiveSupport::Concern
|
|
7
6
|
|
|
8
7
|
class_methods do
|
|
9
|
-
# Money attribute
|
|
10
8
|
def money_attribute(name, currency: Mint.default_currency, mapping: nil)
|
|
9
|
+
columns = attribute_names
|
|
11
10
|
currency = Currency.resolve!(currency)
|
|
11
|
+
name = name.to_s
|
|
12
12
|
parser = Parser.new(currency)
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
13
|
+
resolved_mapping = mapping || resolve_mapping(name, columns)
|
|
14
|
+
|
|
15
|
+
if columns.include?(name) && resolved_mapping.nil?
|
|
16
|
+
define_single_column_money_attribute(name, currency, parser)
|
|
16
17
|
else
|
|
17
|
-
|
|
18
|
-
options = {
|
|
19
|
-
allow_nil: true, class_name: 'Mint::Money',
|
|
20
|
-
constructor: parser, converter: parser,
|
|
21
|
-
mapping: {
|
|
22
|
-
aggregated[:amount] => amount_extractor_for(aggregated[:amount]),
|
|
23
|
-
aggregated[:currency] => :currency_code
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
composed_of(name, options)
|
|
18
|
+
define_composite_money_attribute(name, resolved_mapping, parser)
|
|
27
19
|
end
|
|
28
20
|
end
|
|
29
21
|
|
|
30
|
-
|
|
31
|
-
col = columns.find { |c| c.name == column_name.to_s }
|
|
22
|
+
private
|
|
32
23
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
24
|
+
# --- Preparation (no side effects) ---
|
|
25
|
+
|
|
26
|
+
def resolve_mapping(name, columns)
|
|
27
|
+
return nil unless columns.include?(name)
|
|
28
|
+
|
|
29
|
+
if columns.include?("#{name}_currency")
|
|
30
|
+
{ amount: name, currency: :"#{name}_currency" }
|
|
31
|
+
elsif columns.include?('currency') && name == 'amount'
|
|
32
|
+
{ amount: name, currency: :currency }
|
|
38
33
|
end
|
|
39
34
|
end
|
|
40
35
|
|
|
41
|
-
def
|
|
42
|
-
|
|
43
|
-
missing_keys = (%i[amount currency] - mapping.keys).join(', ')
|
|
44
|
-
if missing_keys.present?
|
|
45
|
-
raise ArgumentError,
|
|
46
|
-
"Mapping for :#{name} money attribute is missing required keys: #{missing_keys}"
|
|
47
|
-
end
|
|
48
|
-
composite = { amount: mapping[:amount].to_s, currency: mapping[:currency].to_s }
|
|
49
|
-
else
|
|
50
|
-
composite = { amount: "#{name}_amount", currency: "#{name}_currency" }
|
|
51
|
-
end
|
|
36
|
+
def resolve_composite_for(name, mapping:)
|
|
37
|
+
composite = { amount: "#{name}_amount", currency: "#{name}_currency" }
|
|
52
38
|
|
|
53
|
-
|
|
54
|
-
if
|
|
55
|
-
raise ArgumentError,
|
|
56
|
-
"Could not find columns for :#{name} money attribute. " \
|
|
57
|
-
"Expected: #{composite.values.join(', ')}, " \
|
|
58
|
-
"Found: #{attribute_names.join(', ')}"
|
|
59
|
-
end
|
|
39
|
+
composite[:amount] = mapping[:amount].to_s if mapping&.key?(:amount)
|
|
40
|
+
composite[:currency] = mapping[:currency].to_s if mapping&.key?(:currency)
|
|
60
41
|
|
|
42
|
+
assert_columns_exist!(name, composite)
|
|
61
43
|
composite
|
|
62
44
|
end
|
|
45
|
+
|
|
46
|
+
def assert_columns_exist!(name, composite)
|
|
47
|
+
missing = composite.values - attribute_names
|
|
48
|
+
return if missing.empty?
|
|
49
|
+
|
|
50
|
+
raise ArgumentError,
|
|
51
|
+
"Could not find columns for :#{name} money attribute. " \
|
|
52
|
+
"Expected: #{composite.values.join(', ')}, " \
|
|
53
|
+
"Found: #{attribute_names.join(', ')}"
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def amount_extractor_for(column_name)
|
|
57
|
+
integer_column?(column_name) ? :fractional : :to_d
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def money_constructor_for(amount_column) = integer_column?(amount_column) ? :from_fractional : :from
|
|
61
|
+
|
|
62
|
+
def integer_column?(column_name)
|
|
63
|
+
col = columns.find { |c| c.name == column_name }
|
|
64
|
+
%i[integer bigint].include?(col&.type)
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
# --- Configuration (registers types, normalizers, composed_of) ---
|
|
68
|
+
|
|
69
|
+
def define_single_column_money_attribute(name, currency, parser)
|
|
70
|
+
column_type = integer_column?(name) ? ActiveRecord::Type::Integer.new : ActiveRecord::Type::Decimal.new
|
|
71
|
+
attribute(name.to_sym, :mint_money, currency:, column_type: column_type)
|
|
72
|
+
normalizes(name.to_sym, with: parser)
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def define_composite_money_attribute(name, mapping, parser)
|
|
76
|
+
aggregated = resolve_composite_for(name, mapping:)
|
|
77
|
+
|
|
78
|
+
composed_of(name.to_sym, {
|
|
79
|
+
allow_nil: true,
|
|
80
|
+
class_name: 'Mint::Money',
|
|
81
|
+
constructor: money_constructor_for(aggregated[:amount]),
|
|
82
|
+
converter: parser,
|
|
83
|
+
mapping: {
|
|
84
|
+
aggregated[:amount] => amount_extractor_for(aggregated[:amount]),
|
|
85
|
+
aggregated[:currency] => :currency_code
|
|
86
|
+
}
|
|
87
|
+
})
|
|
88
|
+
end
|
|
63
89
|
end
|
|
64
90
|
end
|
|
65
91
|
end
|
|
@@ -26,9 +26,9 @@ module Mint
|
|
|
26
26
|
return nil unless value
|
|
27
27
|
|
|
28
28
|
if @column_type.is_a?(ActiveRecord::Type::Integer)
|
|
29
|
-
Mint.
|
|
29
|
+
Mint::Money.from_fractional(value, @currency)
|
|
30
30
|
else
|
|
31
|
-
Mint.
|
|
31
|
+
Mint::Money.from(value, @currency)
|
|
32
32
|
end
|
|
33
33
|
end
|
|
34
34
|
|
data/lib/minting/railties.rb
CHANGED
|
@@ -33,13 +33,15 @@ module Mint
|
|
|
33
33
|
def self.register_custom_currencies!
|
|
34
34
|
Array(Mint.config.added_currencies).each do |currency_data|
|
|
35
35
|
if currency_data.respond_to?(:values_at)
|
|
36
|
-
code = currency_data[:currency]
|
|
37
|
-
subunit = currency_data[:subunit]
|
|
38
|
-
symbol = currency_data[:symbol]
|
|
36
|
+
code = currency_data[:currency]
|
|
37
|
+
subunit = currency_data[:subunit]
|
|
38
|
+
symbol = currency_data[:symbol]
|
|
39
39
|
else
|
|
40
40
|
code, subunit, symbol = *currency_data
|
|
41
41
|
end
|
|
42
42
|
Currency.register(code:, subunit:, symbol:)
|
|
43
|
+
rescue KeyError
|
|
44
|
+
nil
|
|
43
45
|
end
|
|
44
46
|
end
|
|
45
47
|
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: minting-rails
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.8.
|
|
4
|
+
version: 0.8.4
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Gilson Ferraz
|
|
@@ -68,6 +68,16 @@ metadata:
|
|
|
68
68
|
changelog_uri: https://github.com/gferraz/minting-rails/releases
|
|
69
69
|
bug_tracker_uri: https://github.com/gferraz/minting-rails/issues
|
|
70
70
|
rubygems_mfa_required: 'true'
|
|
71
|
+
deprecated_at: '2026-6-15'
|
|
72
|
+
replaced_by: money-attribute
|
|
73
|
+
post_install_message: |2
|
|
74
|
+
|
|
75
|
+
⚠️ `minting-rails` has been renamed to `money-attribute` and will no longer be maintained.
|
|
76
|
+
Update your Gemfile:
|
|
77
|
+
|
|
78
|
+
gem 'money-attribute'
|
|
79
|
+
|
|
80
|
+
The API is identical — just replace the gem name and you're done.
|
|
71
81
|
rdoc_options: []
|
|
72
82
|
require_paths:
|
|
73
83
|
- lib
|