attr_json 1.2.0 → 1.5.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b6bbeb0707de928eae27b0bceafa5691486a2784d3065c71f91757e825bbaa94
4
- data.tar.gz: 64b4d70c31b1b9499ee74f764940b283d45231ec6f4809cec35459e7d6ed9288
3
+ metadata.gz: 3cd2566fed014325bee56f5c062080d3c929a790dbb3b287e92b086c2fa3180f
4
+ data.tar.gz: ffa8e7b471dce27a2708b12e6a2bf27edb5b20d1345656ca026ecc4b263a01a7
5
5
  SHA512:
6
- metadata.gz: 91aab7ce45bf723d4c76d9b2756ad65650bef1b223b2214bc9091118a8e4a04cb347fbac2438e7aaab4ed302f92c26f88b23f602e626b494f1aa5251f81473d7
7
- data.tar.gz: 7862793a46004520e65cbb8b98a4857ec5441d6f0456dd8e368c4af7be8fafaefd8f0ef780f38f7361ea45b1117dbee4fe384492e44f5044aa295ee56488a99b
6
+ metadata.gz: f8db6d4211a2dd9f4b9d8a5482b723597958082617e139157c325e8e3b9dddf15216d21bd56daece5d5b3674acdc8e099a22998ad452473a4bf0834774b7a21f
7
+ data.tar.gz: 13e2cd5b4b10f67f4ecfc1be8732c6a33a7f7a7fdb561b6d8f4f89ae39c74e4b0b153ae10fdf5d650a239534f5b28cd33750aaff90009eeec8877677e765a935
@@ -0,0 +1,87 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [ master ]
6
+ pull_request:
7
+ branches: [ '**' ]
8
+ # UTC Tuesdays 0900. note, no notifications will be sent for failed scheduled builds. :(
9
+ schedule:
10
+ - cron: '0 9 * * TUE'
11
+
12
+
13
+ env:
14
+ POSTGRES_USER: postgres
15
+ POSTGRES_PASSWORD: postgres
16
+
17
+ jobs:
18
+ tests:
19
+ services:
20
+ db:
21
+ image: postgres:9.4
22
+ env:
23
+ POSTGRES_USER: postgres
24
+ POSTGRES_PASSWORD: postgres
25
+ ports: ['5432:5432']
26
+
27
+ runs-on: ubuntu-latest
28
+ strategy:
29
+ fail-fast: false
30
+ matrix:
31
+ include:
32
+ - gemfile: rails_5_0
33
+ ruby: 2.4
34
+
35
+ - gemfile: rails_5_0
36
+ ruby: 2.5
37
+
38
+ - gemfile: rails_5_1
39
+ ruby: 2.4
40
+
41
+ - gemfile: rails_5_2
42
+ ruby: 2.4
43
+
44
+ - gemfile: rails_5_2
45
+ ruby: 2.6
46
+
47
+ - gemfile: rails_6_0
48
+ ruby: 2.6
49
+
50
+ - gemfile: rails_6_0
51
+ ruby: 2.7
52
+
53
+ - gemfile: rails_6_1
54
+ ruby: 2.7
55
+
56
+ - gemfile: rails_6_1
57
+ ruby: '3.0'
58
+
59
+ - gemfile: rails_7_0
60
+ ruby: '3.0'
61
+
62
+ - gemfile: rails_7_0
63
+ ruby: 3.1
64
+
65
+ - gemfile: rails_7_0
66
+ ruby: 3.2
67
+
68
+
69
+ name: ${{ matrix.gemfile }}, ruby ${{ matrix.ruby }}
70
+
71
+ steps:
72
+ - uses: actions/checkout@v3
73
+
74
+ - name: Set up Ruby
75
+ uses: ruby/setup-ruby@v1
76
+ with:
77
+ ruby-version: ${{ matrix.ruby }}
78
+ bundler-cache: false
79
+
80
+ - name: Bundle install
81
+ run: |
82
+ bundle config set gemfile "${GITHUB_WORKSPACE}/gemfiles/${{ matrix.gemfile }}.gemfile"
83
+ bundle install --jobs 4 --retry 3
84
+
85
+ - name: Run tests
86
+ run: |
87
+ bundle exec rspec
@@ -0,0 +1,66 @@
1
+ name: CI on Future Rails Versions
2
+
3
+ # Experimenting with separate github actions workflow
4
+ # for gemfiles for FUTURE Rails vesions, we'd like to keep an eye on
5
+ # if they pass, but they aren't required to do so.
6
+ #
7
+ # This has to just be a copy-and-paste copy of our main ci.yml,
8
+ # but with different gemfiles in the matrix. That is not great.
9
+ # We also choose NOT to run this one on pull_request, we just
10
+ # run it on master, see how that works.
11
+ #
12
+ # These jobs can be left out of "required" for merge in github settings
13
+ # for "Branch Protection Rules" at https://github.com/jrochkind/attr_json/settings/branches
14
+ #
15
+ # You can move a Rails version between this file and ci.yml, and (un)check it in those
16
+ # github settings. (I wish whether it was required to pass could be in this file
17
+ # too, to keep things together)
18
+
19
+ on:
20
+ push:
21
+ branches: [ master ]
22
+ # UTC Sundays 0900. note, no notifications will be sent for failed scheduled builds. :(
23
+ schedule:
24
+ - cron: '0 9 * * SUN'
25
+
26
+ env:
27
+ POSTGRES_USER: postgres
28
+ POSTGRES_PASSWORD: postgres
29
+
30
+ jobs:
31
+ tests:
32
+ services:
33
+ db:
34
+ image: postgres:9.4
35
+ env:
36
+ POSTGRES_USER: postgres
37
+ POSTGRES_PASSWORD: postgres
38
+ ports: ['5432:5432']
39
+
40
+ runs-on: ubuntu-latest
41
+
42
+ strategy:
43
+ fail-fast: false
44
+ matrix:
45
+ include:
46
+
47
+ - gemfile: rails_edge
48
+ ruby: '3.1'
49
+
50
+ name: ${{ matrix.gemfile }}, ruby ${{ matrix.ruby }}
51
+
52
+ steps:
53
+ - uses: actions/checkout@v3
54
+
55
+ - name: Set up Ruby
56
+ uses: ruby/setup-ruby@v1
57
+ with:
58
+ ruby-version: ${{ matrix.ruby }}
59
+
60
+ - name: Bundle install
61
+ run: |
62
+ bundle config set gemfile "${GITHUB_WORKSPACE}/gemfiles/${{ matrix.gemfile }}.gemfile"
63
+ bundle install --jobs 4 --retry 3
64
+
65
+ - name: Run tests
66
+ run: bundle exec rspec
data/Appraisals CHANGED
@@ -28,20 +28,35 @@ end
28
28
  appraise "rails-6-0" do
29
29
  gem 'combustion', "~> 1.0"
30
30
 
31
- gem "rails", ">= 6.0.0.beta1", "< 6.1"
31
+ gem "rails", ">= 6.0.0", "< 6.1"
32
32
  gem "pg", "~> 1.0"
33
33
  end
34
34
 
35
- appraise "rails-edge-6" do
36
- # Edge rails needs unreleased combustion
37
- # https://github.com/pat/combustion/issues/92
35
+ appraise "rails-6-1" do
38
36
  gem 'combustion', "~> 1.0"
39
37
 
40
- gem "rails", git: "https://github.com/rails/rails.git", branch: "master"
38
+ gem "rails", "~> 6.1.0"
41
39
  gem "pg", "~> 1.0"
42
40
 
43
- # We don't actually use coffeescript at all, we need coffee-rails as an explicit
44
- # dependency just for transitory edge weirdness using current sprockets release
45
- # with rails 6 edge.
46
- gem 'coffee-rails'
41
+ # sprockets-rails is already a rails 6.1 dependency, but combustion is failing
42
+ # to require it, this is one way to get it required.
43
+ # https://github.com/pat/combustion/issues/128
44
+ gem "sprockets-rails"
45
+ end
46
+
47
+ appraise "rails-7-0" do
48
+ gem 'combustion', "~> 1.0"
49
+
50
+ gem "rails", "~> 7.0.0"
51
+ gem "pg", "~> 1.0"
52
+ end
53
+
54
+ appraise "rails-edge" do
55
+ # need combustion edge to work with rails edge, will no longer
56
+ # be true on next combustion release, probably no later than Rails 7.1
57
+ # https://github.com/pat/combustion/pull/126
58
+ gem 'combustion', "~> 1.0", github: "pat/combustion"
59
+
60
+ gem "rails", git: "https://github.com/rails/rails.git", branch: "main"
61
+ gem "pg", "~> 1.0"
47
62
  end
data/CHANGELOG.md CHANGED
@@ -4,9 +4,44 @@ Notable changes to this project will be documented in this file.
4
4
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
5
5
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
6
 
7
- ## [Unreleased](https://github.com/jrochkind/attr_json/compare/v1.2.0...HEAD)
7
+ ## [Unreleased](https://github.com/jrochkind/attr_json/compare/v1.4.1...HEAD)
8
8
 
9
9
 
10
+ ## [1.5.0](https://github.com/jrochkind/attr_json/compare/v1.4.1...v1.5.0)
11
+
12
+ ### Added
13
+
14
+ * AttrJson::Model#dup will properly deep-dup attributes https://github.com/jrochkind/attr_json/pull/169
15
+
16
+ * AttrJson::Model#freeze will freeze attributes -- but not deep-freeze. https://github.com/jrochkind/attr_json/pull/169
17
+
18
+ * AttrJson::Model has some methods conventional in ActiveModel classes: Klass.attribute_types, Klass.attribute_names, and instance.attribute_names. https://github.com/jrochkind/attr_json/pull/169
19
+
20
+ ## [1.4.1](https://github.com/jrochkind/attr_json/compare/v1.4.0...v1.4.1)
21
+
22
+ ### Fixed
23
+
24
+ * Fixed an obscure bug involving a conflict between attribute defaults and accepts_nested_attributes, in which defaults could overwrite assigned attributes. The `.fill_in_defaults` class method, which was never intended as public API and was commented accordingly, is gone. https://github.com/jrochkind/attr_json/pull/160
25
+
26
+ ## [1.4.0](https://github.com/jrochkind/attr_json/compare/v1.3.0...v1.4.0)
27
+
28
+ ### Changed
29
+
30
+ * When using store_key feature on an AttrJson::Model, you should not be able to pass in the store_key as a key in initializer or assign_attributes. It was really a bug that this ended up mapped to attribute this way, which could cause a problem in some cases; but calling it out in Changed section because if you were accidentally relying on it, it may appear as a backwards incompat to you. https://github.com/jrochkind/attr_json/pull/125
31
+
32
+ * Rails 7.0.0 allowed by gemspec and tested in CI
33
+
34
+ ### Fixed
35
+
36
+ * polymorphic single type can be set to nil https://github.com/jrochkind/attr_json/pull/115
37
+ * polymorphic models can be serialized from hash in container attribute. Thanks @machty. https://github.com/jrochkind/attr_json/pull/123
38
+ * fix bug with deserialization of nested attributes that have types that apply different serialization vs cast logic. Thanks @bradleesand. https://github.com/jrochkind/attr_json/pull/125
39
+
40
+ ## [1.3.0](https://github.com/jrochkind/attr_json/compare/v1.2.0...v1.3.0)
41
+
42
+ ### Added
43
+
44
+ * Gemspec allows use with ActiveRecord 6.1.x
10
45
 
11
46
  ## [1.2.0](https://github.com/jrochkind/attr_json/compare/v1.1.0...v1.2.0)
12
47
 
data/Gemfile CHANGED
@@ -18,19 +18,26 @@ gem 'combustion', '~> 1.1'
18
18
  # be the way to do it.
19
19
  gem 'rails'
20
20
 
21
- # We should not really need to mention railties, it's already a dependency of
22
- # rails, but seems to be necessary to get around some mystery bug in bundler
23
- # dependency resolution.
24
- gem 'railties'
25
-
26
21
  gem "pg"
27
- gem "rspec-rails", "~> 4.0"
22
+ gem "rspec-rails", "~> 6.0"
28
23
  gem "simple_form", ">= 4.0"
29
24
  gem 'cocoon', ">= 1.2"
30
25
  gem 'jquery-rails'
31
26
 
27
+ # Even though we don't use coffee-script, when running specs, some part of rails
28
+ # or other part of our stack is still insisting on requiring it, for reasons we
29
+ # don't understand, so we need to depend on it.
30
+ gem "coffee-rails"
31
+
32
+ # We do some tests using cocoon via sprockets, which needs sprockets-rails,
33
+ # which is not automatically available in Rails 7. We add it explicitly,
34
+ # which will duplciate dependences in rails pre-7, but add for rails 7. Not sure
35
+ # the future of cocoon in general. https://github.com/nathanvda/cocoon/issues/555
36
+ gem "sprockets-rails"
37
+
38
+
32
39
  gem 'capybara', "~> 3.0"
33
- gem 'webdrivers', '~> 4.0'
40
+ gem 'webdrivers', '~> 5.0'
34
41
  gem "selenium-webdriver"
35
42
 
36
43
  gem "byebug"
data/README.md CHANGED
@@ -1,9 +1,10 @@
1
1
  # AttrJson
2
- [![Build Status](https://travis-ci.org/jrochkind/attr_json.svg?branch=master)](https://travis-ci.org/jrochkind/attr_json)
2
+ [![CI Status](https://github.com/jrochkind/attr_json/workflows/CI/badge.svg?branch=master)](https://github.com/jrochkind/attr_json/actions?query=workflow%3ACI+branch%3Amaster)
3
+ [![CI Status](https://github.com/jrochkind/attr_json/workflows/CI%20on%20Future%20Rails%20Versions/badge.svg?branch=master)](https://github.com/jrochkind/attr_json/actions?query=workflow%3A%22CI+on+Future+Rails+Versions%22+branch%3Amaster)
3
4
  [![Gem Version](https://badge.fury.io/rb/attr_json.svg)](https://badge.fury.io/rb/attr_json)
4
5
 
5
6
 
6
- ActiveRecord attributes stored serialized in a json column, super smooth. For Rails 5.0, 5.1, 5.2, or 6.0. Ruby 2.4+.
7
+ ActiveRecord attributes stored serialized in a json column, super smooth. For Rails 5.0 through 7.0. Ruby 2.4+.
7
8
 
8
9
  Typed and cast like Active Record. Supporting [nested models](#nested), [dirty tracking](#dirty), some [querying](#querying) (with postgres [jsonb](https://www.postgresql.org/docs/9.5/static/datatype-json.html) contains), and [working smoothy with form builders](#forms).
9
10
 
@@ -397,27 +398,29 @@ Rails 5.1+ on `attr_json`s on your ActiveRecord classes that include
397
398
  `AttrJson::Record`, by including `AttrJson::Record::Dirty`.
398
399
  Change-tracking methods are available off the `attr_json_changes` method.
399
400
 
400
- class MyModel < ActiveRecord::Base
401
- include AttrJson::Record
402
- include AttrJson::Record::Dirty
403
-
404
- attr_json :str, :string
405
- end
406
-
407
- model = MyModel.new
408
- model.str = "old"
409
- model.save
410
- model.str = "new"
401
+ ```ruby
402
+ class MyModel < ActiveRecord::Base
403
+ include AttrJson::Record
404
+ include AttrJson::Record::Dirty
411
405
 
412
- # All and only "new" style dirty tracking methods (Raisl 5.1+)
413
- # are available:
406
+ attr_json :str, :string
407
+ end
414
408
 
415
- model.attr_json_changes.saved_changes
416
- model.attr_json_changes.changes_to_save
417
- model.attr_json_changes.saved_change_to_str?
418
- model.attr_json_changes.saved_change_to_str
419
- model.attr_json_changes.will_save_change_to_str?
420
- # etc
409
+ model = MyModel.new
410
+ model.str = "old"
411
+ model.save
412
+ model.str = "new"
413
+
414
+ # All and only "new" style dirty tracking methods (Raisl 5.1+)
415
+ # are available:
416
+
417
+ model.attr_json_changes.saved_changes
418
+ model.attr_json_changes.changes_to_save
419
+ model.attr_json_changes.saved_change_to_str?
420
+ model.attr_json_changes.saved_change_to_str
421
+ model.attr_json_changes.will_save_change_to_str?
422
+ # etc
423
+ ```
421
424
 
422
425
  More options are available, including merging changes from 'ordinary'
423
426
  ActiveRecord attributes in. See docs on [Dirty Tracking](./doc_src/dirty_tracking.md)
@@ -475,11 +478,15 @@ to prevent overwriting other updates from processes.
475
478
 
476
479
  ## State of Code, and To Be Done
477
480
 
478
- The functionality that is here seems pretty solid, and is being used by jrochkind in a production app.
481
+ This code is solid and stable and is being used in production by at least a handful of people, including the primary maintainer, jrochkind.
482
+
483
+ The project is currently getting very little maintainance -- and is still working reliably through Rails releases. It is tested on edge rails and ruby (and has needed very few if any changes with subsequent releases), and I endeavor to keep it working as Rails keeps releasing.
484
+
485
+ In order to keep the low-maintenace scenario sustainable, I am *very* cautious accepting new features, especially if they increase code complexity at all. Even if you have a working PR, I may be reluctant to accept it. I'm prioritizing sustainability and stability over new features, and so far this is working out well. However, discussion is always welcome! Especially when paired with code (failing tests for the bugfix or feature you want are super helpful on their own!).
479
486
 
480
487
  We are committed to [semantic versioning](https://semver.org/) and will endeavor to release no backwards breaking changes without a major version. We are also serious about minimizing backwards incompat releases altogether (ie minimiing major version releases).
481
488
 
482
- Feedback of any kind of _very welcome_, please feel free to use the issue tracker.
489
+ Feedback of any kind of _very welcome_, please feel free to use the issue tracker. It is hard to get a sense of how many people are actually using this, which is helpful both for my own sense of reward and for anyone to get a sense of the size of the userbase -- feel free to say hi and let us know how you are using it!
483
490
 
484
491
  Except for the jsonb_contains stuff using postgres jsonb contains operator, I don't believe any postgres-specific features are used. It ought to work with MySQL, testing and feedback welcome. (Or a PR to test on MySQL?). My own interest is postgres.
485
492
 
@@ -487,26 +494,30 @@ This is still mostly a single-maintainer operation, so has all the sustainabilit
487
494
 
488
495
  ### Possible future features:
489
496
 
490
- * partial updates for json hashes would be really nice: Using postgres jsonb merge operators to only overwrite what changed. In my initial attempts, AR doesn't make it easy to customize this.
497
+ * Make AttrJson::Model lean more heavily on ActiveModel::Attributes API that did not fully exist in first version of attr_json [hope for a future attr_json 2.0 release]
498
+
499
+ * Make AttrJson::Record insist on creating rails cover attributes (no longer optional) and integrating more fully into rails, including rails dirty tricking, eliminating need for custom dirty tracking implementation. Overall decrease in lines of code. Can use jsonb_accessor as guide for some aspects. [hope for inclusion in future attr_json 2.0 release]
500
+
501
+ * partial updates for json hashes would be really nice: Using postgres jsonb merge operators to only overwrite what changed. In my initial attempts, AR doesn't make it easy to customize this. [update: this is hard, probably not coming soon]
491
502
 
492
- * seamless compatibility with ransack
503
+ * seamless compatibility with ransack [update: not necessarily prioritized]
493
504
 
494
505
  * Should we give AttrJson::Model a before_serialize hook that you might
495
506
  want to use similar to AR before_save? Should AttrJson::Models
496
- raise on trying to serialize an invalid model?
507
+ raise on trying to serialize an invalid model? [update: eh, hasn't really come up]
497
508
 
498
509
  * There are limits to what you can do with just jsonb_contains
499
510
  queries. We could support operations like `>`, `<`, `<>`
500
511
  as [jsonb_accessor](https://github.com/devmynd/jsonb_accessor),
501
512
  even accross keypaths. (At present, you could use a
502
513
  before_savee to denormalize/renormalize copy your data into
503
- ordinary AR columns/associations for searching. Or perhaps a postgres ts_vector for text searching. Needs to be worked out.)
514
+ ordinary AR columns/associations for searching. Or perhaps a postgres ts_vector for text searching. Needs to be worked out.) [update: interested, but not necessarily prioritized. This one would be interesting for a third-party PR draft!]
504
515
 
505
516
  * We could/should probably support `jsonb_order` clauses, even
506
- accross key paths, like jsonb_accessor.
517
+ accross key paths, like jsonb_accessor. [update: interested but not necessarily prioritized]
507
518
 
508
519
  * Could we make these attributes work in ordinary AR where, same
509
- as they do in jsonb_contains? Maybe.
520
+ as they do in jsonb_contains? Maybe. [update: probably not]
510
521
 
511
522
  ## Development
512
523
 
data/attr_json.gemspec CHANGED
@@ -44,14 +44,30 @@ attributes use as much of the existing ActiveRecord architecture as we can.}
44
44
 
45
45
  # Only to get CI to work on versions of Rails other than we release with,
46
46
  # should never release a gem with RAILS_GEM set!
47
- unless ENV['APPRAISAL_INITIALIZED'] || ENV["TRAVIS"]
48
- spec.add_runtime_dependency "activerecord", ">= 5.0.0", "< 6.1"
47
+ unless ENV['APPRAISAL_INITIALIZED'] || ENV["TRAVIS"] || ENV['CI']
48
+ spec.add_runtime_dependency "activerecord", ">= 5.0.0", "< 7.1"
49
49
  end
50
50
 
51
51
  spec.add_development_dependency "bundler"
52
52
  spec.add_development_dependency "rake", ">= 10.0"
53
53
  spec.add_development_dependency "rspec", "~> 3.7"
54
- spec.add_development_dependency "database_cleaner", "~> 1.5"
55
54
  spec.add_development_dependency "yard-activesupport-concern"
56
55
  spec.add_development_dependency "appraisal", "~> 2.2"
56
+
57
+ # Working around annoying issue in selenium 3.x with ruby 3.0.
58
+ # we don't actually use rexml ourselves. selenium 3 is a dependency
59
+ # of webdrivers, and tries to use rexml without depending on it
60
+ # as is needed in ruby 3.
61
+ #
62
+ # https://github.com/SeleniumHQ/selenium/issues/9001
63
+ #
64
+ # if in the future you can remove this dependecy and still have tests pass
65
+ # under ruby 3.x, you're good.
66
+ spec.add_development_dependency "rexml"
67
+
68
+ # Used only for Capybara.server in our spec_helper.rb.
69
+ # webrick is no longer included in ruby 3.0, so has to
70
+ # be expressed as a dependecy, unless we switch
71
+ # capybara to use alternate webserver.
72
+ spec.add_development_dependency "webrick", "~> 1.0"
57
73
  end
@@ -4,12 +4,13 @@ source "https://rubygems.org"
4
4
 
5
5
  gem "combustion", "~> 0.9.0"
6
6
  gem "rails", "~> 5.0.0"
7
- gem "railties"
8
7
  gem "pg", "~> 0.18"
9
8
  gem "rspec-rails", "~> 4.0"
10
9
  gem "simple_form", ">= 4.0"
11
10
  gem "cocoon", ">= 1.2"
12
11
  gem "jquery-rails"
12
+ gem "coffee-rails"
13
+ gem "sprockets-rails"
13
14
  gem "capybara", "~> 3.0"
14
15
  gem "webdrivers", "~> 4.0"
15
16
  gem "selenium-webdriver"
@@ -4,12 +4,13 @@ source "https://rubygems.org"
4
4
 
5
5
  gem "combustion", "~> 0.9.0"
6
6
  gem "rails", "~> 5.1.0"
7
- gem "railties"
8
7
  gem "pg", "~> 1.0"
9
8
  gem "rspec-rails", "~> 4.0"
10
9
  gem "simple_form", ">= 4.0"
11
10
  gem "cocoon", ">= 1.2"
12
11
  gem "jquery-rails"
12
+ gem "coffee-rails"
13
+ gem "sprockets-rails"
13
14
  gem "capybara", "~> 3.0"
14
15
  gem "webdrivers", "~> 4.0"
15
16
  gem "selenium-webdriver"
@@ -4,12 +4,13 @@ source "https://rubygems.org"
4
4
 
5
5
  gem "combustion", "~> 0.9.0"
6
6
  gem "rails", "~> 5.2.0"
7
- gem "railties"
8
7
  gem "pg", "~> 1.0"
9
8
  gem "rspec-rails", "~> 4.0"
10
9
  gem "simple_form", ">= 4.0"
11
10
  gem "cocoon", ">= 1.2"
12
11
  gem "jquery-rails"
12
+ gem "coffee-rails"
13
+ gem "sprockets-rails"
13
14
  gem "capybara", "~> 3.0"
14
15
  gem "webdrivers", "~> 4.0"
15
16
  gem "selenium-webdriver"
@@ -3,13 +3,14 @@
3
3
  source "https://rubygems.org"
4
4
 
5
5
  gem "combustion", "~> 1.0"
6
- gem "rails", ">= 6.0.0.beta1", "< 6.1"
7
- gem "railties"
6
+ gem "rails", ">= 6.0.0", "< 6.1"
8
7
  gem "pg", "~> 1.0"
9
8
  gem "rspec-rails", "~> 4.0"
10
9
  gem "simple_form", ">= 4.0"
11
10
  gem "cocoon", ">= 1.2"
12
11
  gem "jquery-rails"
12
+ gem "coffee-rails"
13
+ gem "sprockets-rails"
13
14
  gem "capybara", "~> 3.0"
14
15
  gem "webdrivers", "~> 4.0"
15
16
  gem "selenium-webdriver"
@@ -3,17 +3,17 @@
3
3
  source "https://rubygems.org"
4
4
 
5
5
  gem "combustion", "~> 1.0"
6
- gem "rails", git: "https://github.com/rails/rails.git", branch: "master"
7
- gem "railties"
6
+ gem "rails", "~> 6.1.0"
8
7
  gem "pg", "~> 1.0"
9
8
  gem "rspec-rails", "~> 4.0"
10
9
  gem "simple_form", ">= 4.0"
11
10
  gem "cocoon", ">= 1.2"
12
11
  gem "jquery-rails"
12
+ gem "coffee-rails"
13
+ gem "sprockets-rails"
13
14
  gem "capybara", "~> 3.0"
14
15
  gem "webdrivers", "~> 4.0"
15
16
  gem "selenium-webdriver"
16
17
  gem "byebug"
17
- gem "coffee-rails"
18
18
 
19
19
  gemspec path: "../"
@@ -0,0 +1,19 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "combustion", "~> 1.0"
6
+ gem "rails", "~> 7.0.0"
7
+ gem "pg", "~> 1.0"
8
+ gem "rspec-rails", "~> 4.0"
9
+ gem "simple_form", ">= 4.0"
10
+ gem "cocoon", ">= 1.2"
11
+ gem "jquery-rails"
12
+ gem "coffee-rails"
13
+ gem "sprockets-rails"
14
+ gem "capybara", "~> 3.0"
15
+ gem "webdrivers", "~> 4.0"
16
+ gem "selenium-webdriver"
17
+ gem "byebug"
18
+
19
+ gemspec path: "../"
@@ -2,18 +2,18 @@
2
2
 
3
3
  source "https://rubygems.org"
4
4
 
5
- gem "combustion", "~> 1.0"
6
- gem "rails", git: "https://github.com/rails/rails.git", branch: "master"
7
- gem "railties"
5
+ gem "combustion", "~> 1.0", github: "pat/combustion"
6
+ gem "rails", git: "https://github.com/rails/rails.git", branch: "main"
8
7
  gem "pg", "~> 1.0"
9
- gem "rspec-rails", "~> 3.7"
8
+ gem "rspec-rails", "~> 4.0"
10
9
  gem "simple_form", ">= 4.0"
11
10
  gem "cocoon", ">= 1.2"
12
11
  gem "jquery-rails"
12
+ gem "coffee-rails"
13
+ gem "sprockets-rails"
13
14
  gem "capybara", "~> 3.0"
14
15
  gem "webdrivers", "~> 4.0"
15
16
  gem "selenium-webdriver"
16
17
  gem "byebug"
17
- gem "coffee-rails"
18
18
 
19
19
  gemspec path: "../"
@@ -103,16 +103,27 @@ module AttrJson
103
103
  end
104
104
 
105
105
 
106
- # Like `.new`, but translate store keys in hash
106
+ # The inverse of model#serializable_hash -- re-hydrates a serialized hash to a model.
107
+ #
108
+ # Similar to `.new`, but translates things that need to be translated in deserialization,
109
+ # like store_keys, and properly calling deserialize on the underlying types.
110
+ #
111
+ # @example Model.new_from_serializable(hash)
107
112
  def new_from_serializable(attributes = {})
108
- attributes = attributes.transform_keys do |key|
113
+ attributes = attributes.collect do |key, value|
109
114
  # store keys in arguments get translated to attribute names on initialize.
110
115
  if attribute_def = self.attr_json_registry.store_key_lookup("", key.to_s)
111
- attribute_def.name.to_s
112
- else
113
- key
116
+ key = attribute_def.name.to_s
114
117
  end
115
- end
118
+
119
+ attr_type = self.attr_json_registry.has_attribute?(key) && self.attr_json_registry.type_for_attribute(key)
120
+ if attr_type
121
+ value = attr_type.deserialize(value)
122
+ end
123
+
124
+ [key, value]
125
+ end.to_h
126
+
116
127
  self.new(attributes)
117
128
  end
118
129
 
@@ -124,6 +135,17 @@ module AttrJson
124
135
  @serialization_coder ||= AttrJson::SerializationCoderFromType.new(to_type)
125
136
  end
126
137
 
138
+ # like the ActiveModel::Attributes method
139
+ def attribute_names
140
+ attr_json_registry.attribute_names
141
+ end
142
+
143
+ # like the ActiveModel::Attributes method, hash with name keys, and ActiveModel::Type values
144
+ def attribute_types
145
+ attribute_names.collect { |name| [name.to_s, attr_json_registry.type_for_attribute(name)]}.to_h
146
+ end
147
+
148
+
127
149
  # Type can be an instance of an ActiveModel::Type::Value subclass, or a symbol that will
128
150
  # be looked up in `ActiveModel::Type.lookup`
129
151
  #
@@ -166,27 +188,6 @@ module AttrJson
166
188
  end
167
189
  end
168
190
 
169
- # This should kind of be considered 'protected', but the semantics
170
- # of how we want to call it don't give us a visibility modifier that works.
171
- # Prob means refactoring called for. TODO?
172
- def fill_in_defaults(hash)
173
- # Only if we need to mutate it to add defaults, we'll dup it first. deep_dup not neccesary
174
- # since we're only modifying top-level here.
175
- duped = false
176
- attr_json_registry.definitions.each do |definition|
177
- if definition.has_default? && ! (hash.has_key?(definition.store_key.to_s) || hash.has_key?(definition.store_key.to_sym))
178
- unless duped
179
- hash = hash.dup
180
- duped = true
181
- end
182
-
183
- hash[definition.store_key] = definition.provide_default!
184
- end
185
- end
186
-
187
- hash
188
- end
189
-
190
191
  private
191
192
 
192
193
  # Define an anonymous module and include it, so can still be easily
@@ -202,11 +203,15 @@ module AttrJson
202
203
  end
203
204
 
204
205
  def initialize(attributes = {})
205
- if !attributes.respond_to?(:transform_keys)
206
- raise ArgumentError, "When assigning attributes, you must pass a hash as an argument."
207
- end
206
+ super
207
+
208
+ fill_in_defaults!
209
+ end
208
210
 
209
- super(self.class.fill_in_defaults(attributes))
211
+ # inspired by https://github.com/rails/rails/blob/8015c2c2cf5c8718449677570f372ceb01318a32/activemodel/lib/active_model/attributes.rb
212
+ def initialize_dup(other) # :nodoc:
213
+ @attributes = @attributes.deep_dup
214
+ super
210
215
  end
211
216
 
212
217
  def attributes
@@ -244,6 +249,11 @@ module AttrJson
244
249
  self.class.attr_json_registry.has_attribute?(str)
245
250
  end
246
251
 
252
+ # like the ActiveModel::Attributes method
253
+ def attribute_names
254
+ self.class.attribute_names
255
+ end
256
+
247
257
  # Override from ActiveModel::Serialization to #serialize
248
258
  # by type to make sure any values set directly on hash still
249
259
  # get properly type-serialized.
@@ -290,8 +300,25 @@ module AttrJson
290
300
  false
291
301
  end
292
302
 
303
+ # like ActiveModel::Attributes at
304
+ # https://github.com/rails/rails/blob/8015c2c2cf5c8718449677570f372ceb01318a32/activemodel/lib/active_model/attributes.rb#L120
305
+ #
306
+ # is not a full deep freeze
307
+ def freeze
308
+ attributes.freeze unless frozen?
309
+ super
310
+ end
311
+
293
312
  private
294
313
 
314
+ def fill_in_defaults!
315
+ self.class.attr_json_registry.definitions.each do |definition|
316
+ if definition.has_default? && !attributes.has_key?(definition.name.to_s)
317
+ self.send("#{definition.name.to_s}=", definition.provide_default!)
318
+ end
319
+ end
320
+ end
321
+
295
322
  def _attr_json_write(key, value)
296
323
  if attribute_def = self.class.attr_json_registry[key.to_sym]
297
324
  attributes[key.to_s] = attribute_def.cast(value)
@@ -270,7 +270,13 @@ module AttrJson
270
270
  # find it from currently declared attributes.
271
271
  # https://github.com/rails/rails/blob/6aa5cf03ea8232180ffbbae4c130b051f813c670/activemodel/lib/active_model/attribute_methods.rb#L463-L468
272
272
  def matched_attribute_method(method_name)
273
- matches = self.class.send(:attribute_method_matchers_matching, method_name)
273
+ if self.class.respond_to?(:attribute_method_patterns_matching, true)
274
+ # Rails 7.1+
275
+ matches = self.class.send(:attribute_method_patterns_matching, method_name)
276
+ else
277
+ matches = self.class.send(:attribute_method_matchers_matching, method_name)
278
+ end
279
+
274
280
  matches.detect do |match|
275
281
  registry.has_attribute?(match.attr_name)
276
282
  end
@@ -32,10 +32,10 @@ module AttrJson
32
32
  # to_hash is actually the 'implicit' conversion, it really is a hash
33
33
  # even though it isn't is_a?(Hash), try to_hash first before to_h,
34
34
  # the explicit conversion.
35
- model.new_from_serializable(v.to_hash)
35
+ model.new(v.to_hash)
36
36
  elsif v.respond_to?(:to_h)
37
37
  # TODO Maybe we ought not to do this on #to_h?
38
- model.new_from_serializable(v.to_h)
38
+ model.new(v.to_h)
39
39
  elsif model.attr_json_config.bad_cast == :as_nil
40
40
  # This was originally default behavior, to be like existing ActiveRecord
41
41
  # which kind of silently does this for non-castable basic values. That
@@ -58,7 +58,31 @@ module AttrJson
58
58
  end
59
59
 
60
60
  def deserialize(v)
61
- cast(v)
61
+ if v.nil?
62
+ # important to stay nil instead of empty object, because they
63
+ # are different things.
64
+ v
65
+ elsif v.kind_of? model
66
+ v
67
+ elsif v.respond_to?(:to_hash)
68
+ # to_hash is actually the 'implicit' conversion, it really is a hash
69
+ # even though it isn't is_a?(Hash), try to_hash first before to_h,
70
+ # the explicit conversion.
71
+ model.new_from_serializable(v.to_hash)
72
+ elsif v.respond_to?(:to_h)
73
+ # TODO Maybe we ought not to do this on #to_h? especially here in deserialize?
74
+ model.new_from_serializable(v.to_h)
75
+ elsif model.attr_json_config.bad_cast == :as_nil
76
+ # TODO should we have different config value for bad_deserialize vs bad_cast?
77
+
78
+ # This was originally default behavior, to be like existing ActiveRecord
79
+ # which kind of silently does this for non-castable basic values. That
80
+ # ended up being confusing in the basic case, so now we raise by default,
81
+ # but this is still configurable.
82
+ nil
83
+ else
84
+ raise BadCast.new("Can not cast from #{v.inspect} to #{self.type}")
85
+ end
62
86
  end
63
87
 
64
88
  # these guys are definitely mutable, so we need this.
@@ -114,6 +114,11 @@ module AttrJson
114
114
  end
115
115
 
116
116
  def serialize(v)
117
+ return nil if v.nil?
118
+
119
+ # if it's not already a model cast it to a model if possible (eg it's a hash)
120
+ v = cast(v)
121
+
117
122
  model_name = v.class.name
118
123
  type = type_for_model_name(model_name)
119
124
 
@@ -1,3 +1,3 @@
1
1
  module AttrJson
2
- VERSION = "1.2.0"
2
+ VERSION = "1.5.0"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: attr_json
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.0
4
+ version: 1.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jonathan Rochkind
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2020-06-22 00:00:00.000000000 Z
11
+ date: 2023-01-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord
@@ -19,7 +19,7 @@ dependencies:
19
19
  version: 5.0.0
20
20
  - - "<"
21
21
  - !ruby/object:Gem::Version
22
- version: '6.1'
22
+ version: '7.1'
23
23
  type: :runtime
24
24
  prerelease: false
25
25
  version_requirements: !ruby/object:Gem::Requirement
@@ -29,7 +29,7 @@ dependencies:
29
29
  version: 5.0.0
30
30
  - - "<"
31
31
  - !ruby/object:Gem::Version
32
- version: '6.1'
32
+ version: '7.1'
33
33
  - !ruby/object:Gem::Dependency
34
34
  name: bundler
35
35
  requirement: !ruby/object:Gem::Requirement
@@ -73,21 +73,35 @@ dependencies:
73
73
  - !ruby/object:Gem::Version
74
74
  version: '3.7'
75
75
  - !ruby/object:Gem::Dependency
76
- name: database_cleaner
76
+ name: yard-activesupport-concern
77
+ requirement: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - ">="
80
+ - !ruby/object:Gem::Version
81
+ version: '0'
82
+ type: :development
83
+ prerelease: false
84
+ version_requirements: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - ">="
87
+ - !ruby/object:Gem::Version
88
+ version: '0'
89
+ - !ruby/object:Gem::Dependency
90
+ name: appraisal
77
91
  requirement: !ruby/object:Gem::Requirement
78
92
  requirements:
79
93
  - - "~>"
80
94
  - !ruby/object:Gem::Version
81
- version: '1.5'
95
+ version: '2.2'
82
96
  type: :development
83
97
  prerelease: false
84
98
  version_requirements: !ruby/object:Gem::Requirement
85
99
  requirements:
86
100
  - - "~>"
87
101
  - !ruby/object:Gem::Version
88
- version: '1.5'
102
+ version: '2.2'
89
103
  - !ruby/object:Gem::Dependency
90
- name: yard-activesupport-concern
104
+ name: rexml
91
105
  requirement: !ruby/object:Gem::Requirement
92
106
  requirements:
93
107
  - - ">="
@@ -101,19 +115,19 @@ dependencies:
101
115
  - !ruby/object:Gem::Version
102
116
  version: '0'
103
117
  - !ruby/object:Gem::Dependency
104
- name: appraisal
118
+ name: webrick
105
119
  requirement: !ruby/object:Gem::Requirement
106
120
  requirements:
107
121
  - - "~>"
108
122
  - !ruby/object:Gem::Version
109
- version: '2.2'
123
+ version: '1.0'
110
124
  type: :development
111
125
  prerelease: false
112
126
  version_requirements: !ruby/object:Gem::Requirement
113
127
  requirements:
114
128
  - - "~>"
115
129
  - !ruby/object:Gem::Version
116
- version: '2.2'
130
+ version: '1.0'
117
131
  description: |-
118
132
  ActiveRecord attributes stored serialized in a json column, super smooth.
119
133
  For Rails 5.0, 5.1, or 5.2. Typed and cast like Active Record. Supporting nested models,
@@ -128,9 +142,10 @@ executables: []
128
142
  extensions: []
129
143
  extra_rdoc_files: []
130
144
  files:
145
+ - ".github/workflows/ci.yml"
146
+ - ".github/workflows/future_rails_ci.yml"
131
147
  - ".gitignore"
132
148
  - ".rspec"
133
- - ".travis.yml"
134
149
  - ".yardopts"
135
150
  - Appraisals
136
151
  - CHANGELOG.md
@@ -151,8 +166,9 @@ files:
151
166
  - gemfiles/rails_5_1.gemfile
152
167
  - gemfiles/rails_5_2.gemfile
153
168
  - gemfiles/rails_6_0.gemfile
169
+ - gemfiles/rails_6_1.gemfile
170
+ - gemfiles/rails_7_0.gemfile
154
171
  - gemfiles/rails_edge.gemfile
155
- - gemfiles/rails_edge_6.gemfile
156
172
  - lib/attr_json.rb
157
173
  - lib/attr_json/attribute_definition.rb
158
174
  - lib/attr_json/attribute_definition/registry.rb
@@ -195,7 +211,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
195
211
  - !ruby/object:Gem::Version
196
212
  version: '0'
197
213
  requirements: []
198
- rubygems_version: 3.0.3
214
+ rubygems_version: 3.2.33
199
215
  signing_key:
200
216
  specification_version: 4
201
217
  summary: ActiveRecord attributes stored serialized in a json column, super smooth.
data/.travis.yml DELETED
@@ -1,64 +0,0 @@
1
- #
2
- sudo: false
3
- addons:
4
- postgresql: '9.4'
5
- chrome: stable
6
- language: ruby
7
- cache: bundler
8
-
9
- # rvm:
10
- # - 2.4.5
11
- # - 2.5.3
12
- # - 2.6.5
13
- # - 2.7.0
14
- # gemfile:
15
- # - gemfiles/rails_5_0.gemfile
16
- # - gemfiles/rails_5_1.gemfile
17
- # - gemfiles/rails_5_2.gemfile
18
- # - gemfiles/rails_6_0.gemfile
19
- # - gemfiles/rails_edge.gemfile
20
-
21
- before_install:
22
- - gem install bundler -v "~> 2.0"
23
-
24
- matrix:
25
- include:
26
- - rvm: 2.4.5
27
- gemfile: gemfiles/rails_5_0.gemfile
28
-
29
- - rvm: 2.4.5
30
- gemfile: gemfiles/rails_5_1.gemfile
31
-
32
- - rvm: 2.4.5
33
- gemfile: gemfiles/rails_5_2.gemfile
34
-
35
- - rvm: 2.5.3
36
- gemfile: gemfiles/rails_5_0.gemfile
37
-
38
- - rvm: 2.5.3
39
- gemfile: gemfiles/rails_5_1.gemfile
40
-
41
- - rvm: 2.5.3
42
- gemfile: gemfiles/rails_5_2.gemfile
43
-
44
- - rvm: 2.5.3
45
- gemfile: gemfiles/rails_6_0.gemfile
46
-
47
- - rvm: 2.6.5
48
- gemfile: gemfiles/rails_5_2.gemfile
49
-
50
- - rvm: 2.6.5
51
- gemfile: gemfiles/rails_6_0.gemfile
52
-
53
- - rvm: 2.7.0
54
- gemfile: gemfiles/rails_6_0.gemfile
55
-
56
- - rvm: 2.7.0
57
- gemfile: gemfiles/rails_edge.gemfile
58
-
59
- allow_failures:
60
- - gemfile: gemfiles/rails_edge.gemfile
61
- fast_finish: true
62
-
63
-
64
-