measured 2.8.1 → 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (41) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ci.yml +11 -5
  3. data/.github/workflows/cla.yml +23 -0
  4. data/.ruby-version +1 -0
  5. data/CHANGELOG.md +13 -0
  6. data/Gemfile +2 -0
  7. data/README.md +114 -4
  8. data/cache/volume.json +532 -0
  9. data/dev.yml +1 -2
  10. data/gemfiles/{activesupport-6.0.gemfile → rails-6.0.gemfile} +1 -0
  11. data/gemfiles/{activesupport-6.1.gemfile → rails-6.1.gemfile} +1 -0
  12. data/gemfiles/rails-7.0.gemfile +6 -0
  13. data/gemfiles/rails-edge.gemfile +6 -0
  14. data/lib/measured/measurable.rb +3 -1
  15. data/lib/measured/rails/active_record.rb +130 -0
  16. data/lib/measured/rails/validations.rb +68 -0
  17. data/lib/measured/railtie.rb +12 -0
  18. data/lib/measured/units/volume.rb +2 -0
  19. data/lib/measured/units/weight.rb +1 -1
  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/volume_test.rb +107 -1
  39. data/test/units/weight_test.rb +3 -1
  40. metadata +80 -7
  41. data/gemfiles/activesupport-5.2.gemfile +0 -5
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5ec3f063994e56291a70f5b2726890e03b43ef00e512894a901bc8ea924ae895
4
- data.tar.gz: 442e6cca31eb154cbe318287a64f9379ab987b9ddcd59629a2780960b52ea00d
3
+ metadata.gz: b794b67ca5a9cc00444ec39526340e3f3710dc0395b7205aeb95f44d8ed698fe
4
+ data.tar.gz: 2696f28b014ce76cded21150a1e1b4ef4772ef92a358ddf4e99b526081125d2a
5
5
  SHA512:
6
- metadata.gz: 141a1214a375f0af9ae4d92c1e9c51d77e2a98d2a174321ee9e85eb4387fa72c3c98c49dcc5448d6617f7cc7d6bdf67e9ca4f12772d7446cb00e827329108d4f
7
- data.tar.gz: f5a34f7aa0baf05177f216089dd9b4443ca2b04eecda5c0b72bf5899973a9a5a2a462b2e4f11ea7087dffcc8927e35835e9555da211bc628d50f76fadd110c35
6
+ metadata.gz: 95c82144964349b7111b6a1d372384dc3721b3c5e79870c8b841b7468d6794f60702c2acb1be714fab6c5a858a26d0bc28c340ef987c61a5d94658ffd64eec25
7
+ data.tar.gz: 49b6f68fd80cce3886824df3298c2d837ec0f257b0e4bb311231558b0d9a81eb9cb744f3746540eeaa740f6ad1f84bb578441fc6914841ac81ae57005638a1c0
@@ -10,14 +10,20 @@ jobs:
10
10
  strategy:
11
11
  matrix:
12
12
  ruby:
13
- - '2.6'
14
- - '2.7'
15
13
  - '3.0'
14
+ - '3.1'
15
+ - '3.2'
16
16
  gemfile:
17
17
  - Gemfile
18
- - gemfiles/activesupport-5.2.gemfile
19
- - gemfiles/activesupport-6.0.gemfile
20
- - gemfiles/activesupport-6.1.gemfile
18
+ - gemfiles/rails-6.0.gemfile
19
+ - gemfiles/rails-6.1.gemfile
20
+ - gemfiles/rails-7.0.gemfile
21
+ - gemfiles/rails-edge.gemfile
22
+ exclude:
23
+ # Rails Edge only supports Ruby >= 3.1
24
+ - ruby: '3.0'
25
+ gemfile: gemfiles/rails-edge.gemfile
26
+
21
27
  name: Ruby ${{ matrix.ruby }} ${{ matrix.gemfile }}
22
28
  steps:
23
29
  - uses: actions/checkout@v1
@@ -0,0 +1,23 @@
1
+ # .github/workflows/cla.yml
2
+ name: Contributor License Agreement (CLA)
3
+
4
+ on:
5
+ pull_request_target:
6
+ types: [opened, synchronize]
7
+ issue_comment:
8
+ types: [created]
9
+
10
+ jobs:
11
+ cla:
12
+ runs-on: ubuntu-latest
13
+ if: |
14
+ (github.event.issue.pull_request
15
+ && !github.event.issue.pull_request.merged_at
16
+ && contains(github.event.comment.body, 'signed')
17
+ )
18
+ || (github.event.pull_request && !github.event.pull_request.merged)
19
+ steps:
20
+ - uses: Shopify/shopify-cla-action@v1
21
+ with:
22
+ github-token: ${{ secrets.GITHUB_TOKEN }}
23
+ cla-token: ${{ secrets.CLA_TOKEN }}
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ 3.0.2
data/CHANGELOG.md CHANGED
@@ -3,6 +3,19 @@ Unreleased
3
3
 
4
4
 
5
5
 
6
+ 3.0.0
7
+ -----
8
+
9
+ * Merge functionality of `measured-rails` into this gem. From this version on, this gem is able to automatically integrate with Active Record out of the box. (@paracycle)
10
+ * Add `:gm` and `:gms` as aliases to weight. (@kushagra-03)
11
+ * Adds support for initializing `Measured` objects with a rational value from string. (@dvisockas)
12
+ * Make `Measured` initialization faster by avoiding string substitution in certain cases. (@bitwise-aiden)
13
+
14
+ 2.8.2
15
+ -----
16
+
17
+ * Add cm3 and mm3 to volume. (@fekadeabdejene)
18
+
6
19
  2.8.1
7
20
  -----
8
21
 
data/Gemfile CHANGED
@@ -1,3 +1,5 @@
1
1
  source 'https://rubygems.org'
2
2
 
3
3
  gemspec
4
+
5
+ gem "activerecord"
data/README.md CHANGED
@@ -4,7 +4,7 @@ Encapsulates measurements with their units. Provides easy conversion between uni
4
4
 
5
5
  Lightweight and easily extensible to include other units and conversions. Conversions done with `Rational` for precision.
6
6
 
7
- The adapter to integrate `measured` with Ruby on Rails is in a separate [`measured-rails`](https://github.com/Shopify/measured-rails) gem.
7
+ Since version 3.0.0, the adapter to integrate `measured` with Ruby on Rails is also a part of this gem. If you had been using [`measured-rails`](https://github.com/Shopify/measured-rails) for that functionality, you should now remove `measured-rails` from your gem file.
8
8
 
9
9
  ## Installation
10
10
 
@@ -158,6 +158,116 @@ Measured::Weight.new("3.14", "kg").format(with_conversion_string: false)
158
158
  > "3.14 kg"
159
159
  ```
160
160
 
161
+ ### Active Record
162
+
163
+ This gem also provides an Active Record adapter for persisting and retrieving measurements with their units, and model validations.
164
+
165
+ Columns are expected to have the `_value` and `_unit` suffix, and be `DECIMAL` and `VARCHAR`, and defaults are accepted. Customizing the column used to hold units is supported, see below for details.
166
+
167
+ ```ruby
168
+ class AddWeightAndLengthToThings < ActiveRecord::Migration
169
+ def change
170
+ add_column :things, :minimum_weight_value, :decimal, precision: 10, scale: 2
171
+ add_column :things, :minimum_weight_unit, :string, limit: 12
172
+
173
+ add_column :things, :total_length_value, :decimal, precision: 10, scale: 2, default: 0
174
+ add_column :things, :total_length_unit, :string, limit: 12, default: "cm"
175
+ end
176
+ end
177
+ ```
178
+
179
+ A column can be declared as a measurement with its measurement subclass:
180
+
181
+ ```ruby
182
+ class Thing < ActiveRecord::Base
183
+ measured Measured::Weight, :minimum_weight
184
+ measured Measured::Length, :total_length
185
+ measured Measured::Volume, :total_volume
186
+ end
187
+ ```
188
+
189
+ You can optionally customize the model's unit column by specifying it in the `unit_field_name` option, as follows:
190
+
191
+ ```ruby
192
+ class ThingWithCustomUnitAccessor < ActiveRecord::Base
193
+ measured_length :length, :width, :height, unit_field_name: :size_unit
194
+ measured_weight :total_weight, :extra_weight, unit_field_name: :weight_unit
195
+ measured_volume :total_volume, :extra_volume, unit_field_name: :volume_unit
196
+ end
197
+ ```
198
+
199
+ Similarly, you can optionally customize the model's value column by specifying it in the `value_field_name` option, as follows:
200
+
201
+ ```ruby
202
+ class ThingWithCustomValueAccessor < ActiveRecord::Base
203
+ measured_length :length, value_field_name: :custom_length
204
+ measured_weight :total_weight, value_field_name: :custom_weight
205
+ measured_volume :volume, value_field_name: :custom_volume
206
+ end
207
+ ```
208
+
209
+ There are some simpler methods for predefined types:
210
+
211
+ ```ruby
212
+ class Thing < ActiveRecord::Base
213
+ measured_weight :minimum_weight
214
+ measured_length :total_length
215
+ measured_volume :total_volume
216
+ end
217
+ ```
218
+
219
+ This will allow you to access and assign a measurement object:
220
+
221
+ ```ruby
222
+ thing = Thing.new
223
+ thing.minimum_weight = Measured::Weight.new(10, "g")
224
+ thing.minimum_weight_unit # "g"
225
+ thing.minimum_weight_value # 10
226
+ ```
227
+
228
+ Order of assignment does not matter, and each property can be assigned separately and with mass assignment:
229
+
230
+ ```ruby
231
+ params = { total_length_unit: "cm", total_length_value: "3" }
232
+ thing = Thing.new(params)
233
+ thing.total_length.to_s # 3 cm
234
+ ```
235
+
236
+ ### Validations
237
+
238
+ Validations are available:
239
+
240
+ ```ruby
241
+ class Thing < ActiveRecord::Base
242
+ measured_length :total_length
243
+
244
+ validates :total_length, measured: true
245
+ end
246
+ ```
247
+
248
+ This will validate that the unit is defined on the measurement, and that there is a value.
249
+
250
+ Rather than `true` the validation can accept a hash with the following options:
251
+
252
+ * `message`: Override the default "is invalid" message.
253
+ * `units`: A subset of units available for this measurement. Units must be in existing measurement.
254
+ * `greater_than`
255
+ * `greater_than_or_equal_to`
256
+ * `equal_to`
257
+ * `less_than`
258
+ * `less_than_or_equal_to`
259
+
260
+ All comparison validations require `Measured::Measurable` values, not scalars. Most of these options replace the `numericality` validator which compares the measurement/method name/proc to the column's value. Validations can also be combined with `presence` validator.
261
+
262
+ **Note:** Validations are strongly recommended since assigning an invalid unit will cause the measurement to return `nil`, even if there is a value:
263
+
264
+ ```ruby
265
+ thing = Thing.new
266
+ thing.total_length_value = 1
267
+ thing.total_length_unit = "invalid"
268
+ thing.total_length # nil
269
+ ```
270
+
161
271
  ## Units and conversions
162
272
 
163
273
  ### SI units support
@@ -269,7 +379,7 @@ Existing alternatives which were considered:
269
379
  * **Cons**
270
380
  * Opens up and modifies `Array`, `Date`, `Fixnum`, `Math`, `Numeric`, `String`, `Time`, and `Object`, then depends on those changes internally.
271
381
  * Lots of code to solve a relatively simple problem.
272
- * No ActiveRecord adapter.
382
+ * No Active Record adapter.
273
383
 
274
384
  ### Gem: [quantified](https://github.com/Shopify/quantified)
275
385
  * **Pros**
@@ -278,7 +388,7 @@ Existing alternatives which were considered:
278
388
  * All math done with floats making it highly lossy.
279
389
  * All units assumed to be pluralized, meaning using unit abbreviations is not possible.
280
390
  * Not actively maintained.
281
- * No ActiveRecord adapter.
391
+ * No Active Record adapter.
282
392
 
283
393
  ### Gem: [unitwise](https://github.com/joshwlewis/unitwise)
284
394
  * **Pros**
@@ -287,7 +397,7 @@ Existing alternatives which were considered:
287
397
  * **Cons**
288
398
  * Lots of code. Good code, but lots of it.
289
399
  * Many modifications to core types.
290
- * ActiveRecord adapter exists but is written and maintained by a different person/org.
400
+ * Active Record adapter exists but is written and maintained by a different person/org.
291
401
  * Not actively maintained.
292
402
 
293
403
  ## Contributing