measured 2.8.2 → 3.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/dependabot.yml +20 -0
- data/.github/workflows/ci.yml +12 -6
- data/.github/workflows/cla.yml +23 -0
- data/.github/workflows/dependabot_auto_merge.yml +93 -0
- data/.ruby-version +1 -0
- data/CHANGELOG.md +13 -0
- data/Gemfile +2 -0
- data/README.md +114 -4
- data/cache/weight.json +230 -0
- data/dev.yml +1 -2
- data/gemfiles/rails-7.0.gemfile +6 -0
- data/gemfiles/rails-7.1.gemfile +6 -0
- data/gemfiles/rails-edge.gemfile +6 -0
- data/lib/measured/measurable.rb +3 -1
- data/lib/measured/rails/active_record.rb +130 -0
- data/lib/measured/rails/validations.rb +68 -0
- data/lib/measured/railtie.rb +12 -0
- data/lib/measured/units/weight.rb +3 -2
- data/lib/measured/version.rb +1 -1
- data/lib/measured.rb +2 -0
- data/lib/tapioca/dsl/compilers/measured_rails.rb +110 -0
- data/measured.gemspec +5 -0
- data/test/internal/app/models/thing.rb +14 -0
- data/test/internal/app/models/thing_with_custom_unit_accessor.rb +18 -0
- data/test/internal/app/models/thing_with_custom_value_accessor.rb +19 -0
- data/test/internal/app/models/validated_thing.rb +45 -0
- data/test/internal/config/database.yml +3 -0
- data/test/internal/config.ru +9 -0
- data/test/internal/db/.gitignore +1 -0
- data/test/internal/db/schema.rb +99 -0
- data/test/internal/log/.gitignore +1 -0
- data/test/measurable_test.rb +4 -0
- data/test/rails/active_record_test.rb +433 -0
- data/test/rails/validation_test.rb +252 -0
- data/test/tapioca/dsl/compilers/measured_rails_test.rb +220 -0
- data/test/test_helper.rb +15 -0
- data/test/units/weight_test.rb +77 -2
- metadata +84 -10
- data/gemfiles/activesupport-5.2.gemfile +0 -5
- data/gemfiles/activesupport-6.0.gemfile +0 -5
- 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
data/lib/measured/measurable.rb
CHANGED
@@ -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]
|
data/lib/measured/version.rb
CHANGED