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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6c6f9a0ca2ddc8795a648b6c6047728d626106e2afddbe63869ad3159fcd819e
4
- data.tar.gz: 863f9135a359162e053f988e991a9ac2a832e56e310cc1c7511410212e7c0427
3
+ metadata.gz: 51ccbfc5e1da101cf48481d812400763aa410925247386b4a7471030ce301790
4
+ data.tar.gz: 2ee25dd8e7d055429ed72827d9c6637be59555ade55d8964d01809388c5e430f
5
5
  SHA512:
6
- metadata.gz: 148ee6a06dde29d5685c47e5c3e284fdce46c7d75cd84ab265760087f1e3fcc43afb9f60e949bbe615cf311b576bb9a6180569f103c5665a137d10849604e42c
7
- data.tar.gz: 7c0eaca1345709f22bb446764b9220c5767cca2998e0570490871555cce3c2d692e5839eea9eedcae282cdbe032dca603d1a89bb8ba61d358aa725e83b26b883
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
  [![CI](https://github.com/gferraz/minting-rails/actions/workflows/ci.yml/badge.svg)](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: 'CRC', subunit: 2, symbol: '₡' },
14
- { currency: 'NGN', subunit: 3, symbol: '₦' }
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
- if attribute_names.include? name.to_s
14
- attribute(name, :mint_money, currency:)
15
- normalizes(name, with: parser)
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
- aggregated = find_money_attributes(name, mapping:)
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
- def amount_extractor_for(column_name)
31
- col = columns.find { |c| c.name == column_name.to_s }
22
+ private
32
23
 
33
- case col&.type
34
- when :bigint, :integer
35
- :fractional
36
- else
37
- :to_d # :decimal, :numeric, unknown
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 find_money_attributes(name, mapping:)
42
- if mapping.present?
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
- missing = composite.values - attribute_names
54
- if missing.any?
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.money(value * @currency.fractional_multiplier, @currency)
29
+ Mint::Money.from_fractional(value, @currency)
30
30
  else
31
- Mint.money(value, @currency)
31
+ Mint::Money.from(value, @currency)
32
32
  end
33
33
  end
34
34
 
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Mint
4
4
  module MoneyAttribute
5
- VERSION = '0.8.2'
5
+ VERSION = '0.8.4'
6
6
  end
7
7
  end
@@ -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] || currency_data['currency']
37
- subunit = currency_data[:subunit] || currency_data['subunit']
38
- symbol = currency_data[: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.2
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