measured 2.8.2 → 3.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (42) hide show
  1. checksums.yaml +4 -4
  2. data/.github/dependabot.yml +20 -0
  3. data/.github/workflows/ci.yml +12 -6
  4. data/.github/workflows/cla.yml +23 -0
  5. data/.github/workflows/dependabot_auto_merge.yml +93 -0
  6. data/.ruby-version +1 -0
  7. data/CHANGELOG.md +13 -0
  8. data/Gemfile +2 -0
  9. data/README.md +114 -4
  10. data/cache/weight.json +230 -0
  11. data/dev.yml +1 -2
  12. data/gemfiles/rails-7.0.gemfile +6 -0
  13. data/gemfiles/rails-7.1.gemfile +6 -0
  14. data/gemfiles/rails-edge.gemfile +6 -0
  15. data/lib/measured/measurable.rb +3 -1
  16. data/lib/measured/rails/active_record.rb +130 -0
  17. data/lib/measured/rails/validations.rb +68 -0
  18. data/lib/measured/railtie.rb +12 -0
  19. data/lib/measured/units/weight.rb +3 -2
  20. data/lib/measured/version.rb +1 -1
  21. data/lib/measured.rb +2 -0
  22. data/lib/tapioca/dsl/compilers/measured_rails.rb +110 -0
  23. data/measured.gemspec +5 -0
  24. data/test/internal/app/models/thing.rb +14 -0
  25. data/test/internal/app/models/thing_with_custom_unit_accessor.rb +18 -0
  26. data/test/internal/app/models/thing_with_custom_value_accessor.rb +19 -0
  27. data/test/internal/app/models/validated_thing.rb +45 -0
  28. data/test/internal/config/database.yml +3 -0
  29. data/test/internal/config.ru +9 -0
  30. data/test/internal/db/.gitignore +1 -0
  31. data/test/internal/db/schema.rb +99 -0
  32. data/test/internal/log/.gitignore +1 -0
  33. data/test/measurable_test.rb +4 -0
  34. data/test/rails/active_record_test.rb +433 -0
  35. data/test/rails/validation_test.rb +252 -0
  36. data/test/tapioca/dsl/compilers/measured_rails_test.rb +220 -0
  37. data/test/test_helper.rb +15 -0
  38. data/test/units/weight_test.rb +77 -2
  39. metadata +84 -10
  40. data/gemfiles/activesupport-5.2.gemfile +0 -5
  41. data/gemfiles/activesupport-6.0.gemfile +0 -5
  42. data/gemfiles/activesupport-6.1.gemfile +0 -5
data/cache/weight.json CHANGED
@@ -89,6 +89,10 @@
89
89
  "numerator": 1,
90
90
  "denominator": 1000000
91
91
  },
92
+ "q": {
93
+ "numerator": 1,
94
+ "denominator": 100000
95
+ },
92
96
  "slug": {
93
97
  "numerator": 1000,
94
98
  "denominator": 14593903
@@ -203,6 +207,10 @@
203
207
  "numerator": 1,
204
208
  "denominator": 1000000000000000000000000000000
205
209
  },
210
+ "q": {
211
+ "numerator": 1,
212
+ "denominator": 100000000000000000000000000000
213
+ },
206
214
  "slug": {
207
215
  "numerator": 1,
208
216
  "denominator": 14593903000000000000000000000
@@ -317,6 +325,10 @@
317
325
  "numerator": 1,
318
326
  "denominator": 1000000000000000000000000000
319
327
  },
328
+ "q": {
329
+ "numerator": 1,
330
+ "denominator": 100000000000000000000000000
331
+ },
320
332
  "slug": {
321
333
  "numerator": 1,
322
334
  "denominator": 14593903000000000000000000
@@ -431,6 +443,10 @@
431
443
  "numerator": 1,
432
444
  "denominator": 1000000000000000000000000
433
445
  },
446
+ "q": {
447
+ "numerator": 1,
448
+ "denominator": 100000000000000000000000
449
+ },
434
450
  "slug": {
435
451
  "numerator": 1,
436
452
  "denominator": 14593903000000000000000
@@ -545,6 +561,10 @@
545
561
  "numerator": 1,
546
562
  "denominator": 1000000000000000000000
547
563
  },
564
+ "q": {
565
+ "numerator": 1,
566
+ "denominator": 100000000000000000000
567
+ },
548
568
  "slug": {
549
569
  "numerator": 1,
550
570
  "denominator": 14593903000000000000
@@ -659,6 +679,10 @@
659
679
  "numerator": 1,
660
680
  "denominator": 1000000000000000000
661
681
  },
682
+ "q": {
683
+ "numerator": 1,
684
+ "denominator": 100000000000000000
685
+ },
662
686
  "slug": {
663
687
  "numerator": 1,
664
688
  "denominator": 14593903000000000
@@ -773,6 +797,10 @@
773
797
  "numerator": 1,
774
798
  "denominator": 1000000000000000
775
799
  },
800
+ "q": {
801
+ "numerator": 1,
802
+ "denominator": 100000000000000
803
+ },
776
804
  "slug": {
777
805
  "numerator": 1,
778
806
  "denominator": 14593903000000
@@ -887,6 +915,10 @@
887
915
  "numerator": 1,
888
916
  "denominator": 1000000000000
889
917
  },
918
+ "q": {
919
+ "numerator": 1,
920
+ "denominator": 100000000000
921
+ },
890
922
  "slug": {
891
923
  "numerator": 1,
892
924
  "denominator": 14593903000
@@ -1001,6 +1033,10 @@
1001
1033
  "numerator": 1,
1002
1034
  "denominator": 1000000000
1003
1035
  },
1036
+ "q": {
1037
+ "numerator": 1,
1038
+ "denominator": 100000000
1039
+ },
1004
1040
  "slug": {
1005
1041
  "numerator": 1,
1006
1042
  "denominator": 14593903
@@ -1115,6 +1151,10 @@
1115
1151
  "numerator": 1,
1116
1152
  "denominator": 100000000
1117
1153
  },
1154
+ "q": {
1155
+ "numerator": 1,
1156
+ "denominator": 10000000
1157
+ },
1118
1158
  "slug": {
1119
1159
  "numerator": 10,
1120
1160
  "denominator": 14593903
@@ -1229,6 +1269,10 @@
1229
1269
  "numerator": 1,
1230
1270
  "denominator": 10000000
1231
1271
  },
1272
+ "q": {
1273
+ "numerator": 1,
1274
+ "denominator": 1000000
1275
+ },
1232
1276
  "slug": {
1233
1277
  "numerator": 100,
1234
1278
  "denominator": 14593903
@@ -1343,6 +1387,10 @@
1343
1387
  "numerator": 1,
1344
1388
  "denominator": 100000
1345
1389
  },
1390
+ "q": {
1391
+ "numerator": 1,
1392
+ "denominator": 10000
1393
+ },
1346
1394
  "slug": {
1347
1395
  "numerator": 10000,
1348
1396
  "denominator": 14593903
@@ -1457,6 +1505,10 @@
1457
1505
  "numerator": 1,
1458
1506
  "denominator": 10000
1459
1507
  },
1508
+ "q": {
1509
+ "numerator": 1,
1510
+ "denominator": 1000
1511
+ },
1460
1512
  "slug": {
1461
1513
  "numerator": 100000,
1462
1514
  "denominator": 14593903
@@ -1571,6 +1623,10 @@
1571
1623
  "numerator": 1,
1572
1624
  "denominator": 1000
1573
1625
  },
1626
+ "q": {
1627
+ "numerator": 1,
1628
+ "denominator": 100
1629
+ },
1574
1630
  "slug": {
1575
1631
  "numerator": 1000000,
1576
1632
  "denominator": 14593903
@@ -1685,6 +1741,10 @@
1685
1741
  "numerator": 1,
1686
1742
  "denominator": 1
1687
1743
  },
1744
+ "q": {
1745
+ "numerator": 10,
1746
+ "denominator": 1
1747
+ },
1688
1748
  "slug": {
1689
1749
  "numerator": 1000000000,
1690
1750
  "denominator": 14593903
@@ -1799,6 +1859,10 @@
1799
1859
  "numerator": 1000,
1800
1860
  "denominator": 1
1801
1861
  },
1862
+ "q": {
1863
+ "numerator": 10000,
1864
+ "denominator": 1
1865
+ },
1802
1866
  "slug": {
1803
1867
  "numerator": 1000000000000,
1804
1868
  "denominator": 14593903
@@ -1913,6 +1977,10 @@
1913
1977
  "numerator": 1000000,
1914
1978
  "denominator": 1
1915
1979
  },
1980
+ "q": {
1981
+ "numerator": 10000000,
1982
+ "denominator": 1
1983
+ },
1916
1984
  "slug": {
1917
1985
  "numerator": 1000000000000000,
1918
1986
  "denominator": 14593903
@@ -2027,6 +2095,10 @@
2027
2095
  "numerator": 1000000000,
2028
2096
  "denominator": 1
2029
2097
  },
2098
+ "q": {
2099
+ "numerator": 10000000000,
2100
+ "denominator": 1
2101
+ },
2030
2102
  "slug": {
2031
2103
  "numerator": 1000000000000000000,
2032
2104
  "denominator": 14593903
@@ -2141,6 +2213,10 @@
2141
2213
  "numerator": 1000000000000,
2142
2214
  "denominator": 1
2143
2215
  },
2216
+ "q": {
2217
+ "numerator": 10000000000000,
2218
+ "denominator": 1
2219
+ },
2144
2220
  "slug": {
2145
2221
  "numerator": 1000000000000000000000,
2146
2222
  "denominator": 14593903
@@ -2255,6 +2331,10 @@
2255
2331
  "numerator": 1000000000000000,
2256
2332
  "denominator": 1
2257
2333
  },
2334
+ "q": {
2335
+ "numerator": 10000000000000000,
2336
+ "denominator": 1
2337
+ },
2258
2338
  "slug": {
2259
2339
  "numerator": 1000000000000000000000000,
2260
2340
  "denominator": 14593903
@@ -2369,6 +2449,10 @@
2369
2449
  "numerator": 1000000000000000000,
2370
2450
  "denominator": 1
2371
2451
  },
2452
+ "q": {
2453
+ "numerator": 10000000000000000000,
2454
+ "denominator": 1
2455
+ },
2372
2456
  "slug": {
2373
2457
  "numerator": 1000000000000000000000000000,
2374
2458
  "denominator": 14593903
@@ -2483,6 +2567,10 @@
2483
2567
  "numerator": 1,
2484
2568
  "denominator": 1000000000000000000
2485
2569
  },
2570
+ "q": {
2571
+ "numerator": 10,
2572
+ "denominator": 1
2573
+ },
2486
2574
  "slug": {
2487
2575
  "numerator": 1000000000,
2488
2576
  "denominator": 14593903
@@ -2508,6 +2596,124 @@
2508
2596
  "denominator": 45359237
2509
2597
  }
2510
2598
  },
2599
+ "q": {
2600
+ "q": {
2601
+ "numerator": 1,
2602
+ "denominator": 1
2603
+ },
2604
+ "g": {
2605
+ "numerator": 100000,
2606
+ "denominator": 1
2607
+ },
2608
+ "yg": {
2609
+ "numerator": 100000000000000000000000000000,
2610
+ "denominator": 1
2611
+ },
2612
+ "zg": {
2613
+ "numerator": 100000000000000000000000000,
2614
+ "denominator": 1
2615
+ },
2616
+ "ag": {
2617
+ "numerator": 100000000000000000000000,
2618
+ "denominator": 1
2619
+ },
2620
+ "fg": {
2621
+ "numerator": 100000000000000000000,
2622
+ "denominator": 1
2623
+ },
2624
+ "pg": {
2625
+ "numerator": 100000000000000000,
2626
+ "denominator": 1
2627
+ },
2628
+ "ng": {
2629
+ "numerator": 100000000000000,
2630
+ "denominator": 1
2631
+ },
2632
+ "μg": {
2633
+ "numerator": 100000000000,
2634
+ "denominator": 1
2635
+ },
2636
+ "mg": {
2637
+ "numerator": 100000000,
2638
+ "denominator": 1
2639
+ },
2640
+ "cg": {
2641
+ "numerator": 10000000,
2642
+ "denominator": 1
2643
+ },
2644
+ "dg": {
2645
+ "numerator": 1000000,
2646
+ "denominator": 1
2647
+ },
2648
+ "dag": {
2649
+ "numerator": 10000,
2650
+ "denominator": 1
2651
+ },
2652
+ "hg": {
2653
+ "numerator": 1000,
2654
+ "denominator": 1
2655
+ },
2656
+ "kg": {
2657
+ "numerator": 100,
2658
+ "denominator": 1
2659
+ },
2660
+ "Mg": {
2661
+ "numerator": 1,
2662
+ "denominator": 10
2663
+ },
2664
+ "Gg": {
2665
+ "numerator": 1,
2666
+ "denominator": 10000
2667
+ },
2668
+ "Tg": {
2669
+ "numerator": 1,
2670
+ "denominator": 10000000
2671
+ },
2672
+ "Pg": {
2673
+ "numerator": 1,
2674
+ "denominator": 10000000000
2675
+ },
2676
+ "Eg": {
2677
+ "numerator": 1,
2678
+ "denominator": 10000000000000
2679
+ },
2680
+ "Zg": {
2681
+ "numerator": 1,
2682
+ "denominator": 10000000000000000
2683
+ },
2684
+ "Yg": {
2685
+ "numerator": 1,
2686
+ "denominator": 10000000000000000000
2687
+ },
2688
+ "t": {
2689
+ "numerator": 1,
2690
+ "denominator": 10
2691
+ },
2692
+ "slug": {
2693
+ "numerator": 100000000,
2694
+ "denominator": 14593903
2695
+ },
2696
+ "N": {
2697
+ "numerator": 10000000000000000000,
2698
+ "denominator": 10197162129779283
2699
+ },
2700
+ "long_ton": {
2701
+ "numerator": 31250000,
2702
+ "denominator": 317514659
2703
+ },
2704
+ "short_ton": {
2705
+ "numerator": 5000000,
2706
+ "denominator": 45359237
2707
+ },
2708
+ "lb": {
2709
+ "numerator": 10000000000,
2710
+ "denominator": 45359237
2711
+ },
2712
+ "oz": {
2713
+ "numerator": 160000000000,
2714
+ "denominator": 45359237
2715
+ }
2716
+ },
2511
2717
  "slug": {
2512
2718
  "slug": {
2513
2719
  "numerator": 1,
@@ -2601,6 +2807,10 @@
2601
2807
  "numerator": 14593903,
2602
2808
  "denominator": 1000000000
2603
2809
  },
2810
+ "q": {
2811
+ "numerator": 14593903,
2812
+ "denominator": 100000000
2813
+ },
2604
2814
  "N": {
2605
2815
  "numerator": 1459390300000000000,
2606
2816
  "denominator": 10197162129779283
@@ -2715,6 +2925,10 @@
2715
2925
  "numerator": 10197162129779283,
2716
2926
  "denominator": 100000000000000000000
2717
2927
  },
2928
+ "q": {
2929
+ "numerator": 10197162129779283,
2930
+ "denominator": 10000000000000000000
2931
+ },
2718
2932
  "slug": {
2719
2933
  "numerator": 10197162129779283,
2720
2934
  "denominator": 1459390300000000000
@@ -2829,6 +3043,10 @@
2829
3043
  "numerator": 317514659,
2830
3044
  "denominator": 312500000
2831
3045
  },
3046
+ "q": {
3047
+ "numerator": 317514659,
3048
+ "denominator": 31250000
3049
+ },
2832
3050
  "slug": {
2833
3051
  "numerator": 5080234544,
2834
3052
  "denominator": 72969515
@@ -2943,6 +3161,10 @@
2943
3161
  "numerator": 45359237,
2944
3162
  "denominator": 50000000
2945
3163
  },
3164
+ "q": {
3165
+ "numerator": 45359237,
3166
+ "denominator": 5000000
3167
+ },
2946
3168
  "slug": {
2947
3169
  "numerator": 907184740,
2948
3170
  "denominator": 14593903
@@ -3057,6 +3279,10 @@
3057
3279
  "numerator": 45359237,
3058
3280
  "denominator": 100000000000
3059
3281
  },
3282
+ "q": {
3283
+ "numerator": 45359237,
3284
+ "denominator": 10000000000
3285
+ },
3060
3286
  "slug": {
3061
3287
  "numerator": 45359237,
3062
3288
  "denominator": 1459390300
@@ -3171,6 +3397,10 @@
3171
3397
  "numerator": 45359237,
3172
3398
  "denominator": 1600000000000
3173
3399
  },
3400
+ "q": {
3401
+ "numerator": 45359237,
3402
+ "denominator": 160000000000
3403
+ },
3174
3404
  "slug": {
3175
3405
  "numerator": 45359237,
3176
3406
  "denominator": 23350244800
data/dev.yml CHANGED
@@ -1,8 +1,7 @@
1
1
  name: measured
2
2
 
3
3
  up:
4
- - ruby:
5
- version: 3.0.2
4
+ - ruby
6
5
  - bundler
7
6
 
8
7
  commands:
@@ -0,0 +1,6 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec path: '..'
4
+
5
+ gem 'activesupport', '~> 7.0'
6
+ gem 'activerecord', '~> 7.0'
@@ -0,0 +1,6 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec path: '..'
4
+
5
+ gem 'activesupport', '~> 7.1'
6
+ gem "activerecord", '~> 7.1'
@@ -0,0 +1,6 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec path: '..'
4
+
5
+ gem 'activesupport', github: 'rails/rails', branch: 'main'
6
+ gem 'activerecord', github: 'rails/rails', branch: 'main'
@@ -17,6 +17,8 @@ class Measured::Measurable < Numeric
17
17
  value
18
18
  when Integer
19
19
  Rational(value)
20
+ when String
21
+ /\d+\/\d+/.match?(value) ? Rational(value) : BigDecimal(value)
20
22
  else
21
23
  BigDecimal(value)
22
24
  end
@@ -30,7 +32,7 @@ class Measured::Measurable < Numeric
30
32
  else
31
33
  value.to_f.to_s
32
34
  end
33
- str.gsub(/\.0*\Z/, "")
35
+ /\.0*\Z/.match?(str) ? str.gsub(/\.0*\Z/, "") : str
34
36
  end.freeze
35
37
  end
36
38
 
@@ -0,0 +1,130 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Measured::Rails::ActiveRecord
4
+ extend ActiveSupport::Concern
5
+
6
+ module ClassMethods
7
+ def measured(measured_class, *fields)
8
+ options = fields.extract_options!
9
+ options = {}.merge(options)
10
+
11
+ measured_class = measured_class.constantize if measured_class.is_a?(String)
12
+ unless measured_class.is_a?(Class) && measured_class.ancestors.include?(Measured::Measurable)
13
+ raise Measured::Rails::Error, "Expecting #{ measured_class } to be a subclass of Measured::Measurable"
14
+ end
15
+
16
+ options[:class] = measured_class
17
+
18
+ fields.map(&:to_sym).each do |field|
19
+ raise Measured::Rails::Error, "The field #{ field } has already been measured" if measured_fields.key?(field)
20
+
21
+ measured_fields[field] = options
22
+
23
+ unit_field_name = if options[:unit_field_name]
24
+ measured_fields[field][:unit_field_name] = options[:unit_field_name].to_s
25
+ else
26
+ "#{ field }_unit"
27
+ end
28
+
29
+ value_field_name = if options[:value_field_name]
30
+ measured_fields[field][:value_field_name] = options[:value_field_name].to_s
31
+ else
32
+ "#{ field }_value"
33
+ end
34
+
35
+ # Reader to retrieve measured object
36
+ define_method(field) do
37
+ value = public_send(value_field_name)
38
+ unit = public_send(unit_field_name)
39
+
40
+ return nil unless value && unit
41
+
42
+ instance = instance_variable_get("@measured_#{ field }") if instance_variable_defined?("@measured_#{ field }")
43
+ new_instance = begin
44
+ measured_class.new(value, unit)
45
+ rescue Measured::UnitError
46
+ nil
47
+ end
48
+
49
+ if instance == new_instance
50
+ instance
51
+ else
52
+ instance_variable_set("@measured_#{ field }", new_instance)
53
+ end
54
+ end
55
+
56
+ # Writer to assign measured object
57
+ define_method("#{ field }=") do |incoming|
58
+ if incoming.is_a?(measured_class)
59
+ instance_variable_set("@measured_#{ field }", incoming)
60
+ precision = self.column_for_attribute(value_field_name).precision
61
+ scale = self.column_for_attribute(value_field_name).scale
62
+ rounded_to_scale_value = incoming.value.round(scale)
63
+
64
+ max = self.class.measured_fields[field][:max_on_assignment]
65
+ if max && rounded_to_scale_value > max
66
+ rounded_to_scale_value = max
67
+ elsif rounded_to_scale_value.to_i.to_s.length > (precision - scale)
68
+ raise Measured::Rails::Error, "The value #{rounded_to_scale_value} being set for column '#{value_field_name}' has too many significant digits. Please ensure it has no more than #{precision - scale} significant digits."
69
+ end
70
+
71
+ public_send("#{ value_field_name }=", rounded_to_scale_value)
72
+ public_send("#{ unit_field_name }=", incoming.unit.name)
73
+ else
74
+ instance_variable_set("@measured_#{ field }", nil)
75
+ public_send("#{ value_field_name}=", nil)
76
+ public_send("#{ unit_field_name }=", nil)
77
+ end
78
+ end
79
+
80
+ # Writer to override unit assignment
81
+ redefine_method("#{ unit_field_name }=") do |incoming|
82
+ unit_name = measured_class.unit_system.unit_for(incoming).try!(:name)
83
+ write_attribute(unit_field_name, unit_name || incoming)
84
+ end
85
+ end
86
+ end
87
+
88
+ def measured_fields
89
+ @measured_fields ||= {}
90
+ end
91
+
92
+ end
93
+
94
+ module Length
95
+ extend ActiveSupport::Concern
96
+
97
+ module ClassMethods
98
+ def measured_length(*fields)
99
+ measured(Measured::Length, *fields)
100
+ end
101
+ end
102
+ end
103
+
104
+ module Volume
105
+ extend ActiveSupport::Concern
106
+
107
+ module ClassMethods
108
+ def measured_volume(*fields)
109
+ measured(Measured::Volume, *fields)
110
+ end
111
+ end
112
+ end
113
+
114
+ module Weight
115
+ extend ActiveSupport::Concern
116
+
117
+ module ClassMethods
118
+ def measured_weight(*fields)
119
+ measured(Measured::Weight, *fields)
120
+ end
121
+ end
122
+ end
123
+ end
124
+
125
+ ::ActiveRecord::Base.include(
126
+ Measured::Rails::ActiveRecord,
127
+ Measured::Rails::ActiveRecord::Length,
128
+ Measured::Rails::ActiveRecord::Volume,
129
+ Measured::Rails::ActiveRecord::Weight,
130
+ )
@@ -0,0 +1,68 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_model/validations"
4
+
5
+ class MeasuredValidator < ActiveModel::EachValidator
6
+ CHECKS = {
7
+ greater_than: :>,
8
+ greater_than_or_equal_to: :>=,
9
+ equal_to: :==,
10
+ less_than: :<,
11
+ less_than_or_equal_to: :<=,
12
+ }.freeze
13
+
14
+ def validate_each(record, attribute, measurable)
15
+ measured_config = record.class.measured_fields[attribute]
16
+ unit_field_name = measured_config[:unit_field_name] || "#{ attribute }_unit"
17
+ value_field_name = measured_config[:value_field_name] || "#{ attribute }_value"
18
+
19
+ measured_class = measured_config[:class]
20
+
21
+ measurable_unit_name = record.public_send(unit_field_name)
22
+ measurable_value = record.public_send(value_field_name)
23
+
24
+ return unless measurable_unit_name.present? || measurable_value.present?
25
+
26
+ measurable_unit = measured_class.unit_system.unit_for(measurable_unit_name)
27
+ record.errors.add(attribute, message(record, "is not a valid unit")) unless measurable_unit
28
+
29
+ if options[:units] && measurable_unit.present?
30
+ valid_units = Array(options[:units]).map { |unit| measured_class.unit_system.unit_for(unit) }
31
+ record.errors.add(attribute, message(record, "is not a valid unit")) unless valid_units.include?(measurable_unit)
32
+ end
33
+
34
+ if measurable_unit && measurable_value.present?
35
+ options.slice(*CHECKS.keys).each do |option, value|
36
+ comparable_value = value_for(value, record)
37
+ comparable_value = measured_class.new(comparable_value, measurable_unit) unless comparable_value.is_a?(Measured::Measurable)
38
+ unless measurable.public_send(CHECKS[option], comparable_value)
39
+ record.errors.add(attribute, message(record, "#{measurable.to_s} must be #{CHECKS[option]} #{comparable_value}"))
40
+ end
41
+ end
42
+ end
43
+ end
44
+
45
+ private
46
+
47
+ def message(record, default_message)
48
+ if options[:message].respond_to?(:call)
49
+ options[:message].call(record)
50
+ else
51
+ options[:message] || default_message
52
+ end
53
+ end
54
+
55
+ def value_for(key, record)
56
+ value = case key
57
+ when Proc
58
+ key.call(record)
59
+ when Symbol
60
+ record.send(key)
61
+ else
62
+ key
63
+ end
64
+
65
+ raise ArgumentError, ":#{ value } must be a number or a Measurable object" unless (value.is_a?(Numeric) || value.is_a?(Measured::Measurable))
66
+ value
67
+ end
68
+ end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Measured
4
+ class Rails < ::Rails::Railtie
5
+ class Error < StandardError ; end
6
+
7
+ ActiveSupport.on_load(:active_record) do
8
+ require "measured/rails/active_record"
9
+ require "measured/rails/validations"
10
+ end
11
+ end
12
+ end
@@ -1,8 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
  Measured::Weight = Measured.build do
3
- si_unit :g, aliases: [:gram, :grams]
3
+ si_unit :g, aliases: [:gram, :grams, :gm, :gms]
4
4
 
5
- unit :t, value: "1000 kg", aliases: [:metric_ton, :metric_tons]
5
+ unit :t, value: "1000 kg", aliases: [:metric_ton, :metric_tons, :tonne, :tonnes]
6
+ unit :q, value: "100 kg", aliases: [:quintal, :quintals]
6
7
  unit :slug, value: "14.593903 kg", aliases: [:slugs]
7
8
  unit :N, value: "0.10197162129779283 kg", aliases: [:newtons, :newton]
8
9
  unit :long_ton, value: "2240 lb", aliases: [:long_tons, :weight_ton, :weight_tons, 'W/T', :imperial_ton, :imperial_tons, :displacement_ton, :displacement_tons]
@@ -1,4 +1,4 @@
1
1
  # frozen_string_literal: true
2
2
  module Measured
3
- VERSION = "2.8.2"
3
+ VERSION = "3.1.0"
4
4
  end