iknow_view_models 3.2.0 → 3.2.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (78) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +13 -0
  3. data/Appraisals +6 -6
  4. data/Rakefile +5 -5
  5. data/gemfiles/rails_5_2.gemfile +5 -5
  6. data/gemfiles/rails_6_0.gemfile +5 -5
  7. data/iknow_view_models.gemspec +40 -39
  8. data/lib/iknow_view_models.rb +9 -7
  9. data/lib/iknow_view_models/version.rb +1 -1
  10. data/lib/view_model.rb +17 -14
  11. data/lib/view_model/access_control.rb +5 -2
  12. data/lib/view_model/access_control/composed.rb +10 -9
  13. data/lib/view_model/access_control/open.rb +2 -0
  14. data/lib/view_model/access_control/read_only.rb +2 -0
  15. data/lib/view_model/access_control/tree.rb +11 -6
  16. data/lib/view_model/access_control_error.rb +4 -1
  17. data/lib/view_model/active_record.rb +12 -11
  18. data/lib/view_model/active_record/association_data.rb +2 -1
  19. data/lib/view_model/active_record/association_manipulation.rb +6 -4
  20. data/lib/view_model/active_record/cache.rb +4 -2
  21. data/lib/view_model/active_record/collection_nested_controller.rb +3 -3
  22. data/lib/view_model/active_record/controller_base.rb +4 -1
  23. data/lib/view_model/active_record/nested_controller_base.rb +1 -0
  24. data/lib/view_model/active_record/update_context.rb +8 -6
  25. data/lib/view_model/active_record/update_data.rb +32 -30
  26. data/lib/view_model/active_record/update_operation.rb +17 -13
  27. data/lib/view_model/active_record/visitor.rb +0 -1
  28. data/lib/view_model/after_transaction_runner.rb +0 -1
  29. data/lib/view_model/callbacks.rb +3 -1
  30. data/lib/view_model/controller.rb +13 -3
  31. data/lib/view_model/deserialization_error.rb +15 -12
  32. data/lib/view_model/error.rb +12 -10
  33. data/lib/view_model/error_view.rb +3 -1
  34. data/lib/view_model/migration/no_path_error.rb +1 -0
  35. data/lib/view_model/migration/one_way_error.rb +1 -0
  36. data/lib/view_model/migration/unspecified_version_error.rb +1 -0
  37. data/lib/view_model/record.rb +11 -13
  38. data/lib/view_model/reference.rb +3 -1
  39. data/lib/view_model/references.rb +8 -5
  40. data/lib/view_model/registry.rb +1 -1
  41. data/lib/view_model/schemas.rb +9 -4
  42. data/lib/view_model/serialization_error.rb +4 -1
  43. data/lib/view_model/serialize_context.rb +4 -4
  44. data/lib/view_model/test_helpers.rb +8 -3
  45. data/lib/view_model/test_helpers/arvm_builder.rb +19 -14
  46. data/lib/view_model/traversal_context.rb +2 -1
  47. data/test/.rubocop.yml +14 -0
  48. data/test/helpers/arvm_test_models.rb +12 -9
  49. data/test/helpers/arvm_test_utilities.rb +5 -3
  50. data/test/helpers/controller_test_helpers.rb +31 -29
  51. data/test/helpers/match_enumerator.rb +1 -0
  52. data/test/helpers/query_logging.rb +2 -1
  53. data/test/helpers/test_access_control.rb +5 -3
  54. data/test/helpers/viewmodel_spec_helpers.rb +21 -20
  55. data/test/unit/view_model/access_control_test.rb +144 -144
  56. data/test/unit/view_model/active_record/alias_test.rb +15 -13
  57. data/test/unit/view_model/active_record/belongs_to_test.rb +40 -39
  58. data/test/unit/view_model/active_record/cache_test.rb +27 -26
  59. data/test/unit/view_model/active_record/cloner_test.rb +67 -63
  60. data/test/unit/view_model/active_record/controller_test.rb +37 -38
  61. data/test/unit/view_model/active_record/counter_test.rb +10 -9
  62. data/test/unit/view_model/active_record/customization_test.rb +59 -58
  63. data/test/unit/view_model/active_record/has_many_test.rb +112 -111
  64. data/test/unit/view_model/active_record/has_many_through_poly_test.rb +15 -14
  65. data/test/unit/view_model/active_record/has_many_through_test.rb +33 -38
  66. data/test/unit/view_model/active_record/has_one_test.rb +37 -36
  67. data/test/unit/view_model/active_record/migration_test.rb +13 -13
  68. data/test/unit/view_model/active_record/namespacing_test.rb +19 -17
  69. data/test/unit/view_model/active_record/poly_test.rb +44 -45
  70. data/test/unit/view_model/active_record/shared_test.rb +30 -28
  71. data/test/unit/view_model/active_record/version_test.rb +9 -7
  72. data/test/unit/view_model/active_record_test.rb +72 -72
  73. data/test/unit/view_model/callbacks_test.rb +19 -15
  74. data/test/unit/view_model/controller_test.rb +4 -2
  75. data/test/unit/view_model/record_test.rb +92 -97
  76. data/test/unit/view_model/traversal_context_test.rb +4 -5
  77. data/test/unit/view_model_test.rb +18 -16
  78. metadata +7 -5
@@ -14,6 +14,7 @@ module MiniTest::Assertions
14
14
 
15
15
  def result
16
16
  return false unless @actual.respond_to? :to_a
17
+
17
18
  @extra_items = difference_between_enumerators(@actual, @expected)
18
19
  @missing_items = difference_between_enumerators(@expected, @actual)
19
20
  @extra_items.empty? & @missing_items.empty?
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # Test mixin that allows queries executed in a block to be introspected.
2
4
  #
3
5
  # Code run within a `log_queries` block will collect data. Collected data is
@@ -9,7 +11,6 @@
9
11
  require 'active_support/subscriber'
10
12
 
11
13
  module QueryLogging
12
-
13
14
  # ActiveRecord integration
14
15
  class QueryLogger < ActiveSupport::Subscriber
15
16
  @log = false
@@ -1,5 +1,6 @@
1
- require "iknow_view_models"
1
+ # frozen_string_literal: true
2
2
 
3
+ require 'iknow_view_models'
3
4
 
4
5
  class TestAccessControl < ViewModel::AccessControl
5
6
  attr_accessor :editable_checks, :visible_checks
@@ -41,13 +42,14 @@ class TestAccessControl < ViewModel::AccessControl
41
42
  def valid_edit_changes(ref)
42
43
  all = all_valid_edit_changes(ref)
43
44
  raise "Expected single change for ref '#{ref}'; found #{all}" unless all.size == 1
45
+
44
46
  all.first
45
47
  end
46
48
 
47
49
  def all_valid_edit_changes(ref)
48
50
  @valid_edit_checks
49
- .select { | cref, _changes| cref == ref }
50
- .map { |_cref, changes| changes }
51
+ .select { |cref, _changes| cref == ref }
52
+ .map { |_cref, changes| changes }
51
53
  end
52
54
 
53
55
  def was_edited?(ref)
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'view_model'
2
4
  require 'view_model/test_helpers'
3
5
 
@@ -77,7 +79,7 @@ module ViewModelSpecHelpers
77
79
  ViewModel::TestHelpers::ARVMBuilder::Spec.new(
78
80
  schema: ->(t) { t.string :name },
79
81
  model: ->(m) {},
80
- viewmodel: ->(v) { root!; attribute :name }
82
+ viewmodel: ->(_v) { root!; attribute :name },
81
83
  )
82
84
  end
83
85
 
@@ -85,7 +87,7 @@ module ViewModelSpecHelpers
85
87
  ViewModel::TestHelpers::ARVMBuilder::Spec.new(
86
88
  schema: ->(t) { t.string :name },
87
89
  model: ->(m) {},
88
- viewmodel: ->(v) { attribute :name }
90
+ viewmodel: ->(_v) { attribute :name },
89
91
  )
90
92
  end
91
93
 
@@ -125,7 +127,7 @@ module ViewModelSpecHelpers
125
127
  end
126
128
 
127
129
  def child_attributes
128
- super.merge(model: ->(m) { has_one :model, inverse_of: :child })
130
+ super.merge(model: ->(_m) { has_one :model, inverse_of: :child })
129
131
  end
130
132
 
131
133
  # parent depends on child, ensure it's touched first
@@ -208,7 +210,7 @@ module ViewModelSpecHelpers
208
210
  extend ActiveSupport::Concern
209
211
  include ViewModelSpecHelpers::ParentAndBelongsToChild
210
212
  def child_attributes
211
- super.merge(viewmodel: ->(v) { root! })
213
+ super.merge(viewmodel: ->(_v) { root! })
212
214
  end
213
215
  end
214
216
 
@@ -222,11 +224,11 @@ module ViewModelSpecHelpers
222
224
  t.string :name
223
225
  t.integer :next_id
224
226
  },
225
- model: ->(m) {
227
+ model: ->(_m) {
226
228
  belongs_to :next, class_name: self.name, inverse_of: :previous, dependent: :destroy
227
229
  has_one :previous, class_name: self.name, foreign_key: :next_id, inverse_of: :next
228
230
  },
229
- viewmodel: ->(v) {
231
+ viewmodel: ->(_v) {
230
232
  # Not a root
231
233
  association :next
232
234
  attribute :name
@@ -245,15 +247,15 @@ module ViewModelSpecHelpers
245
247
  def model_attributes
246
248
  f = subject_association_features
247
249
  super.merge(
248
- model: ->(m) { has_one :child, inverse_of: :model, dependent: :destroy },
249
- viewmodel: ->(v) { association :child, **f }
250
+ model: ->(_m) { has_one :child, inverse_of: :model, dependent: :destroy },
251
+ viewmodel: ->(_v) { association :child, **f },
250
252
  )
251
253
  end
252
254
 
253
255
  def child_attributes
254
256
  super.merge(
255
257
  schema: ->(t) { t.references :model, foreign_key: true },
256
- model: ->(m) { belongs_to :model, inverse_of: :child }
258
+ model: ->(_m) { belongs_to :model, inverse_of: :child },
257
259
  )
258
260
  end
259
261
 
@@ -272,7 +274,7 @@ module ViewModelSpecHelpers
272
274
  extend ActiveSupport::Concern
273
275
  include ViewModelSpecHelpers::ParentAndHasOneChild
274
276
  def child_attributes
275
- super.merge(viewmodel: ->(v) { root! })
277
+ super.merge(viewmodel: ->(_v) { root! })
276
278
  end
277
279
  end
278
280
 
@@ -283,15 +285,15 @@ module ViewModelSpecHelpers
283
285
  def model_attributes
284
286
  f = subject_association_features
285
287
  super.merge(
286
- model: ->(m) { has_many :children, inverse_of: :model, dependent: :destroy },
287
- viewmodel: ->(v) { association :children, **f }
288
+ model: ->(_m) { has_many :children, inverse_of: :model, dependent: :destroy },
289
+ viewmodel: ->(_v) { association :children, **f },
288
290
  )
289
291
  end
290
292
 
291
293
  def child_attributes
292
294
  super.merge(
293
295
  schema: ->(t) { t.references :model, foreign_key: true },
294
- model: ->(m) { belongs_to :model, inverse_of: :children }
296
+ model: ->(_m) { belongs_to :model, inverse_of: :children },
295
297
  )
296
298
  end
297
299
 
@@ -310,7 +312,7 @@ module ViewModelSpecHelpers
310
312
  extend ActiveSupport::Concern
311
313
  include ViewModelSpecHelpers::ParentAndHasManyChildren
312
314
  def child_attributes
313
- super.merge(viewmodel: ->(v) { root! })
315
+ super.merge(viewmodel: ->(_v) { root! })
314
316
  end
315
317
  end
316
318
 
@@ -336,12 +338,11 @@ module ViewModelSpecHelpers
336
338
  table = model.table_name
337
339
  model.connection.execute <<-SQL
338
340
  ALTER TABLE #{table} ADD CONSTRAINT #{table}_unique_on_model_and_position UNIQUE(model_id, position) DEFERRABLE INITIALLY DEFERRED
339
- SQL
341
+ SQL
340
342
  end
341
343
  end
342
344
  end
343
345
 
344
-
345
346
  module ParentAndExternalSharedChild
346
347
  extend ActiveSupport::Concern
347
348
  include ViewModelSpecHelpers::ParentAndSharedBelongsToChild
@@ -358,15 +359,15 @@ module ViewModelSpecHelpers
358
359
  def model_attributes
359
360
  f = subject_association_features
360
361
  super.merge(
361
- model: ->(m) { has_many :model_children, inverse_of: :model, dependent: :destroy },
362
- viewmodel: ->(v) { association :children, through: :model_children, through_order_attr: :position, **f }
362
+ model: ->(_m) { has_many :model_children, inverse_of: :model, dependent: :destroy },
363
+ viewmodel: ->(_v) { association :children, through: :model_children, through_order_attr: :position, **f },
363
364
  )
364
365
  end
365
366
 
366
367
  def child_attributes
367
368
  super.merge(
368
- model: ->(m) { has_many :model_children, inverse_of: :child, dependent: :destroy },
369
- viewmodel: ->(v) { root! }
369
+ model: ->(_m) { has_many :model_children, inverse_of: :child, dependent: :destroy },
370
+ viewmodel: ->(_v) { root! },
370
371
  )
371
372
  end
372
373
 
@@ -1,15 +1,15 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative "../../helpers/arvm_test_utilities.rb"
4
- require_relative "../../helpers/arvm_test_models.rb"
5
- require_relative '../../helpers/viewmodel_spec_helpers.rb'
3
+ require_relative '../../helpers/arvm_test_utilities'
4
+ require_relative '../../helpers/arvm_test_models'
5
+ require_relative '../../helpers/viewmodel_spec_helpers'
6
6
 
7
- require "minitest/autorun"
7
+ require 'minitest/autorun'
8
8
  require 'minitest/unit'
9
9
 
10
10
  require 'rspec/expectations/minitest_integration'
11
11
 
12
- require "view_model/active_record"
12
+ require 'view_model/active_record'
13
13
 
14
14
  class ViewModel::AccessControlTest < ActiveSupport::TestCase
15
15
  include ARVMTestUtilities
@@ -55,103 +55,103 @@ class ViewModel::AccessControlTest < ActiveSupport::TestCase
55
55
  end
56
56
 
57
57
  def test_visible_if
58
- TestAccessControl.visible_if!("car is visible1") do
59
- view.car == "visible1"
58
+ TestAccessControl.visible_if!('car is visible1') do
59
+ view.car == 'visible1'
60
60
  end
61
61
 
62
- TestAccessControl.visible_if!("car is visible2") do
63
- view.car == "visible2"
62
+ TestAccessControl.visible_if!('car is visible2') do
63
+ view.car == 'visible2'
64
64
  end
65
65
 
66
- assert_serializes(ListView, List.create!(car: "visible1"))
67
- assert_serializes(ListView, List.create!(car: "visible2"))
68
- ex = refute_serializes(ListView, List.create!(car: "bad"), /none of the possible/)
66
+ assert_serializes(ListView, List.create!(car: 'visible1'))
67
+ assert_serializes(ListView, List.create!(car: 'visible2'))
68
+ ex = refute_serializes(ListView, List.create!(car: 'bad'), /none of the possible/)
69
69
  assert_equal(2, ex.reasons.count)
70
70
  end
71
71
 
72
72
  def test_visible_unless
73
- TestAccessControl.visible_if!("always") { true }
73
+ TestAccessControl.visible_if!('always') { true }
74
74
 
75
- TestAccessControl.visible_unless!("car is invisible") do
76
- view.car == "invisible"
75
+ TestAccessControl.visible_unless!('car is invisible') do
76
+ view.car == 'invisible'
77
77
  end
78
78
 
79
- assert_serializes(ListView, List.create!(car: "ok"))
80
- refute_serializes(ListView, List.create!(car: "invisible"), /not permitted.*car is invisible/)
79
+ assert_serializes(ListView, List.create!(car: 'ok'))
80
+ refute_serializes(ListView, List.create!(car: 'invisible'), /not permitted.*car is invisible/)
81
81
  end
82
82
 
83
83
  def test_editable_if
84
- TestAccessControl.visible_if!("always") { true }
84
+ TestAccessControl.visible_if!('always') { true }
85
85
 
86
- TestAccessControl.editable_if!("car is editable1") do
87
- view.car == "editable1"
86
+ TestAccessControl.editable_if!('car is editable1') do
87
+ view.car == 'editable1'
88
88
  end
89
89
 
90
- TestAccessControl.editable_if!("car is editable2") do
91
- view.car == "editable2"
90
+ TestAccessControl.editable_if!('car is editable2') do
91
+ view.car == 'editable2'
92
92
  end
93
93
 
94
- assert_deserializes(ListView, List.create!(car: "editable1")) { |v, _| v["car"] = "unchecked" }
95
- assert_deserializes(ListView, List.create!(car: "editable2")) { |v, _| v["car"] = "unchecked" }
96
- assert_deserializes(ListView, List.create!(car: "forbidden")) { |v, _| v["car"] = "forbidden" } # no change so permitted
97
- refute_deserializes(ListView, List.create!(car: "forbidden"), /none of the possible/) { |v, _| v["car"] = "unchecked" }
94
+ assert_deserializes(ListView, List.create!(car: 'editable1')) { |v, _| v['car'] = 'unchecked' }
95
+ assert_deserializes(ListView, List.create!(car: 'editable2')) { |v, _| v['car'] = 'unchecked' }
96
+ assert_deserializes(ListView, List.create!(car: 'forbidden')) { |v, _| v['car'] = 'forbidden' } # no change so permitted
97
+ refute_deserializes(ListView, List.create!(car: 'forbidden'), /none of the possible/) { |v, _| v['car'] = 'unchecked' }
98
98
  end
99
99
 
100
100
  def test_editable_unless
101
- TestAccessControl.visible_if!("always") { true }
102
- TestAccessControl.editable_if!("always") { true }
101
+ TestAccessControl.visible_if!('always') { true }
102
+ TestAccessControl.editable_if!('always') { true }
103
103
 
104
- TestAccessControl.editable_unless!("car is uneditable") do
105
- view.car == "uneditable"
104
+ TestAccessControl.editable_unless!('car is uneditable') do
105
+ view.car == 'uneditable'
106
106
  end
107
107
 
108
- assert_deserializes(ListView, List.create!(car: "ok")) { |v, _| v["car"] = "unchecked" }
109
- assert_deserializes(ListView, List.create!(car: "uneditable")) { |v, _| v["car"] = "uneditable" } # no change so permitted
110
- refute_deserializes(ListView, List.create!(car: "uneditable"), /car is uneditable/) { |v, _| v["car"] = "unchecked" }
108
+ assert_deserializes(ListView, List.create!(car: 'ok')) { |v, _| v['car'] = 'unchecked' }
109
+ assert_deserializes(ListView, List.create!(car: 'uneditable')) { |v, _| v['car'] = 'uneditable' } # no change so permitted
110
+ refute_deserializes(ListView, List.create!(car: 'uneditable'), /car is uneditable/) { |v, _| v['car'] = 'unchecked' }
111
111
  end
112
112
 
113
113
  def test_edit_valid_if
114
- TestAccessControl.visible_if!("always") { true }
114
+ TestAccessControl.visible_if!('always') { true }
115
115
 
116
- TestAccessControl.edit_valid_if!("car is validedit") do
117
- view.car == "validedit"
116
+ TestAccessControl.edit_valid_if!('car is validedit') do
117
+ view.car == 'validedit'
118
118
  end
119
119
 
120
- assert_deserializes(ListView, List.create!(car: "unchecked")) { |v, _| v["car"] = "validedit" }
121
- assert_deserializes(ListView, List.create!(car: "unmodified")) { |v, _| v["car"] = "unmodified" } # no change so permitted
122
- refute_deserializes(ListView, List.create!(car: "unchecked"), /none of the possible/) { |v, _| v["car"] = "bad" }
120
+ assert_deserializes(ListView, List.create!(car: 'unchecked')) { |v, _| v['car'] = 'validedit' }
121
+ assert_deserializes(ListView, List.create!(car: 'unmodified')) { |v, _| v['car'] = 'unmodified' } # no change so permitted
122
+ refute_deserializes(ListView, List.create!(car: 'unchecked'), /none of the possible/) { |v, _| v['car'] = 'bad' }
123
123
  end
124
124
 
125
125
  def test_edit_valid_unless
126
- TestAccessControl.visible_if!("always") { true }
127
- TestAccessControl.edit_valid_if!("always") { true }
128
- TestAccessControl.edit_valid_unless!("car is invalidedit") do
129
- view.car == "invalidedit"
126
+ TestAccessControl.visible_if!('always') { true }
127
+ TestAccessControl.edit_valid_if!('always') { true }
128
+ TestAccessControl.edit_valid_unless!('car is invalidedit') do
129
+ view.car == 'invalidedit'
130
130
  end
131
131
 
132
- assert_deserializes(ListView, List.create!(car: "unchecked")) { |v, _| v["car"] = "ok" }
133
- assert_deserializes(ListView, List.create!(car: "invalidedit")) { |v, _| v["car"] = "invalidedit" }
134
- refute_deserializes(ListView, List.create!(car: "unchecked"), /car is invalidedit/) { |v, _| v["car"] = "invalidedit" }
132
+ assert_deserializes(ListView, List.create!(car: 'unchecked')) { |v, _| v['car'] = 'ok' }
133
+ assert_deserializes(ListView, List.create!(car: 'invalidedit')) { |v, _| v['car'] = 'invalidedit' }
134
+ refute_deserializes(ListView, List.create!(car: 'unchecked'), /car is invalidedit/) { |v, _| v['car'] = 'invalidedit' }
135
135
  end
136
136
 
137
137
  def test_editable_and_edit_valid
138
- TestAccessControl.visible_if!("always") { true }
138
+ TestAccessControl.visible_if!('always') { true }
139
139
 
140
- TestAccessControl.editable_if!("original car permits") do
141
- view.car == "permitoriginal"
140
+ TestAccessControl.editable_if!('original car permits') do
141
+ view.car == 'permitoriginal'
142
142
  end
143
143
 
144
- TestAccessControl.edit_valid_if!("resulting car permits") do
145
- view.car == "permitresult"
144
+ TestAccessControl.edit_valid_if!('resulting car permits') do
145
+ view.car == 'permitresult'
146
146
  end
147
147
 
148
148
  # at least one valid
149
- assert_deserializes(ListView, List.create!(car: "permitoriginal")) { |v, _| v["car"] = "permitresult" }
150
- assert_deserializes(ListView, List.create!(car: "badoriginal")) { |v, _| v["car"] = "permitresult" }
151
- assert_deserializes(ListView, List.create!(car: "permitoriginal")) { |v, _| v["car"] = "badresult" }
149
+ assert_deserializes(ListView, List.create!(car: 'permitoriginal')) { |v, _| v['car'] = 'permitresult' }
150
+ assert_deserializes(ListView, List.create!(car: 'badoriginal')) { |v, _| v['car'] = 'permitresult' }
151
+ assert_deserializes(ListView, List.create!(car: 'permitoriginal')) { |v, _| v['car'] = 'badresult' }
152
152
 
153
153
  # no valid
154
- ex = refute_deserializes(ListView, List.create!(car: "badoriginal"), /none of the possible/) { |v, _| v["car"] = "badresult" }
154
+ ex = refute_deserializes(ListView, List.create!(car: 'badoriginal'), /none of the possible/) { |v, _| v['car'] = 'badresult' }
155
155
 
156
156
  assert_equal(2, ex.reasons.count)
157
157
  end
@@ -160,14 +160,14 @@ class ViewModel::AccessControlTest < ActiveSupport::TestCase
160
160
  child_access_control = Class.new(ViewModel::AccessControl::Composed)
161
161
  child_access_control.include_from(TestAccessControl)
162
162
 
163
- TestAccessControl.visible_if!("car is ancestor") { view.car == "ancestor" }
164
- child_access_control.visible_if!("car is descendent") { view.car == "descendent" }
163
+ TestAccessControl.visible_if!('car is ancestor') { view.car == 'ancestor' }
164
+ child_access_control.visible_if!('car is descendent') { view.car == 'descendent' }
165
165
 
166
166
  s_ctx = ListView.new_serialize_context(access_control: child_access_control.new)
167
167
 
168
- assert_serializes(ListView, List.create!(car: "ancestor"), serialize_context: s_ctx)
169
- assert_serializes(ListView, List.create!(car: "descendent"), serialize_context: s_ctx)
170
- ex = refute_serializes(ListView, List.create!(car: "foreigner"), serialize_context: s_ctx)
168
+ assert_serializes(ListView, List.create!(car: 'ancestor'), serialize_context: s_ctx)
169
+ assert_serializes(ListView, List.create!(car: 'descendent'), serialize_context: s_ctx)
170
+ ex = refute_serializes(ListView, List.create!(car: 'foreigner'), serialize_context: s_ctx)
171
171
  assert_equal(2, ex.reasons.count)
172
172
  end
173
173
  end
@@ -243,7 +243,7 @@ class ViewModel::AccessControlTest < ActiveSupport::TestCase
243
243
 
244
244
  child = root[attr]
245
245
 
246
- if (child_ref = child["_ref"])
246
+ if (child_ref = child['_ref'])
247
247
  child = refs[child_ref]
248
248
  end
249
249
 
@@ -255,189 +255,189 @@ class ViewModel::AccessControlTest < ActiveSupport::TestCase
255
255
  end
256
256
 
257
257
  def test_visibility_from_root
258
- TestAccessControl.view "Tree1" do
259
- visible_if!("true") { true }
258
+ TestAccessControl.view 'Tree1' do
259
+ visible_if!('true') { true }
260
260
 
261
- root_children_visible_if!("root children visible") do
262
- view.val == "rule:visible_children"
261
+ root_children_visible_if!('root children visible') do
262
+ view.val == 'rule:visible_children'
263
263
  end
264
264
  end
265
265
 
266
- refute_serializes(Tree1View, make_tree("arbitrary parent", "invisible child"))
267
- assert_serializes(Tree1View, make_tree("rule:visible_children", "visible child"))
266
+ refute_serializes(Tree1View, make_tree('arbitrary parent', 'invisible child'))
267
+ assert_serializes(Tree1View, make_tree('rule:visible_children', 'visible child'))
268
268
 
269
269
  # nested root
270
- refute_serializes(Tree1View, make_tree("rule:visible_children", "visible child", "arbitrary parent", "invisible child"))
271
- assert_serializes(Tree1View, make_tree("rule:visible_children", "visible child", "rule:visible_children", "visible child"))
270
+ refute_serializes(Tree1View, make_tree('rule:visible_children', 'visible child', 'arbitrary parent', 'invisible child'))
271
+ assert_serializes(Tree1View, make_tree('rule:visible_children', 'visible child', 'rule:visible_children', 'visible child'))
272
272
  end
273
273
 
274
274
  def test_visibility_veto_from_root
275
- TestAccessControl.view "Tree1" do
276
- root_children_visible_unless!("root children invisible") do
277
- view.val == "rule:invisible_children"
275
+ TestAccessControl.view 'Tree1' do
276
+ root_children_visible_unless!('root children invisible') do
277
+ view.val == 'rule:invisible_children'
278
278
  end
279
279
  end
280
280
 
281
281
  TestAccessControl.always do
282
- visible_if!("true") { true }
282
+ visible_if!('true') { true }
283
283
  end
284
284
 
285
- assert_serializes(Tree1View, make_tree("arbitrary parent", "visible child"))
286
- refute_serializes(Tree1View, make_tree("rule:invisible_children", "invisible child"))
285
+ assert_serializes(Tree1View, make_tree('arbitrary parent', 'visible child'))
286
+ refute_serializes(Tree1View, make_tree('rule:invisible_children', 'invisible child'))
287
287
 
288
288
  # nested root
289
- assert_serializes(Tree1View, make_tree("arbitrary parent", "visible child", "arbitrary nested parent", "visible child"))
290
- refute_serializes(Tree1View, make_tree("arbitrary parent", "visible child", "rule:invisible_children", "invisible child"))
289
+ assert_serializes(Tree1View, make_tree('arbitrary parent', 'visible child', 'arbitrary nested parent', 'visible child'))
290
+ refute_serializes(Tree1View, make_tree('arbitrary parent', 'visible child', 'rule:invisible_children', 'invisible child'))
291
291
  end
292
292
 
293
293
  def test_editability_from_root
294
294
  TestAccessControl.always do
295
- visible_if!("always") { true }
295
+ visible_if!('always') { true }
296
296
  end
297
297
 
298
- TestAccessControl.view "Tree1" do
299
- editable_if!("true") { true }
298
+ TestAccessControl.view 'Tree1' do
299
+ editable_if!('true') { true }
300
300
 
301
- root_children_editable_if!("root children editable") do
302
- view.val == "rule:editable_children"
301
+ root_children_editable_if!('root children editable') do
302
+ view.val == 'rule:editable_children'
303
303
  end
304
304
  end
305
305
 
306
- refute_deserializes(Tree1View, make_tree("arbitrary parent", "uneditable child")) { |v, r|
307
- dig_tree(v, r, "tree2")["val"] = "change"
306
+ refute_deserializes(Tree1View, make_tree('arbitrary parent', 'uneditable child')) { |v, r|
307
+ dig_tree(v, r, 'tree2')['val'] = 'change'
308
308
  }
309
309
 
310
- assert_deserializes(Tree1View, make_tree("rule:editable_children", "editable child")) { |v, r|
311
- dig_tree(v, r, "tree2")["val"] = "change"
310
+ assert_deserializes(Tree1View, make_tree('rule:editable_children', 'editable child')) { |v, r|
311
+ dig_tree(v, r, 'tree2')['val'] = 'change'
312
312
  }
313
313
 
314
314
  # nested root
315
- refute_deserializes(Tree1View, make_tree("rule:editable_children", "editable child", "arbitrary parent", "uneditable child")) { |v, r|
316
- dig_tree(v, r, "tree2", "tree1", "tree2")["val"] = "change"
315
+ refute_deserializes(Tree1View, make_tree('rule:editable_children', 'editable child', 'arbitrary parent', 'uneditable child')) { |v, r|
316
+ dig_tree(v, r, 'tree2', 'tree1', 'tree2')['val'] = 'change'
317
317
  }
318
318
 
319
- assert_deserializes(Tree1View, make_tree("arbitrary parent", "uneditable child", "rule:editable_children", "editable child")) { |v, r|
320
- dig_tree(v, r, "tree2", "tree1", "tree2")["val"] = "change"
319
+ assert_deserializes(Tree1View, make_tree('arbitrary parent', 'uneditable child', 'rule:editable_children', 'editable child')) { |v, r|
320
+ dig_tree(v, r, 'tree2', 'tree1', 'tree2')['val'] = 'change'
321
321
  }
322
322
  end
323
323
 
324
324
  def test_editability_veto_from_root
325
325
  TestAccessControl.always do
326
- visible_if!("always") { true }
327
- editable_if!("always") { true }
326
+ visible_if!('always') { true }
327
+ editable_if!('always') { true }
328
328
  end
329
329
 
330
- TestAccessControl.view "Tree1" do
331
- root_children_editable_unless!("root children uneditable") do
332
- view.val == "rule:uneditable_children"
330
+ TestAccessControl.view 'Tree1' do
331
+ root_children_editable_unless!('root children uneditable') do
332
+ view.val == 'rule:uneditable_children'
333
333
  end
334
334
  end
335
335
 
336
- refute_deserializes(Tree1View, make_tree("rule:uneditable_children", "uneditable child")) { |v, r|
337
- dig_tree(v, r, "tree2")["val"] = "change"
336
+ refute_deserializes(Tree1View, make_tree('rule:uneditable_children', 'uneditable child')) { |v, r|
337
+ dig_tree(v, r, 'tree2')['val'] = 'change'
338
338
  }
339
339
 
340
- assert_deserializes(Tree1View, make_tree("arbitrary parent", "editable child")) { |v, r|
341
- dig_tree(v, r, "tree2")["val"] = "change"
340
+ assert_deserializes(Tree1View, make_tree('arbitrary parent', 'editable child')) { |v, r|
341
+ dig_tree(v, r, 'tree2')['val'] = 'change'
342
342
  }
343
343
 
344
344
  # nested root
345
- refute_deserializes(Tree1View, make_tree("arbitrary parent", "editable child", "rule:uneditable_children", "uneditable child")) { |v, r|
346
- dig_tree(v, r, "tree2", "tree1", "tree2")["val"] = "change"
345
+ refute_deserializes(Tree1View, make_tree('arbitrary parent', 'editable child', 'rule:uneditable_children', 'uneditable child')) { |v, r|
346
+ dig_tree(v, r, 'tree2', 'tree1', 'tree2')['val'] = 'change'
347
347
  }
348
348
 
349
- assert_deserializes(Tree1View, make_tree("rule:uneditable_children", "uneditable child", "arbitrary parent", "editable child")) { |v, r|
350
- dig_tree(v, r, "tree2", "tree1", "tree2")["val"] = "change"
349
+ assert_deserializes(Tree1View, make_tree('rule:uneditable_children', 'uneditable child', 'arbitrary parent', 'editable child')) { |v, r|
350
+ dig_tree(v, r, 'tree2', 'tree1', 'tree2')['val'] = 'change'
351
351
  }
352
352
  end
353
353
 
354
354
  def test_type_independence
355
- TestAccessControl.view "Tree1" do
356
- visible_if!("tree1 visible") do
357
- view.val == "tree1visible"
355
+ TestAccessControl.view 'Tree1' do
356
+ visible_if!('tree1 visible') do
357
+ view.val == 'tree1visible'
358
358
  end
359
359
  end
360
360
 
361
- TestAccessControl.view "Tree2" do
362
- visible_if!("tree2 visible") do
363
- view.val == "tree2visible"
361
+ TestAccessControl.view 'Tree2' do
362
+ visible_if!('tree2 visible') do
363
+ view.val == 'tree2visible'
364
364
  end
365
365
  end
366
366
 
367
- refute_serializes(Tree1View, make_tree("tree1invisible", "tree2visible"))
368
- assert_serializes(Tree1View, make_tree("tree1visible", "tree2visible"))
369
- refute_serializes(Tree1View, make_tree("tree1visible", "tree2invisible"))
367
+ refute_serializes(Tree1View, make_tree('tree1invisible', 'tree2visible'))
368
+ assert_serializes(Tree1View, make_tree('tree1visible', 'tree2visible'))
369
+ refute_serializes(Tree1View, make_tree('tree1visible', 'tree2invisible'))
370
370
  end
371
371
 
372
372
  def test_visibility_always_composition
373
- TestAccessControl.view "Tree1" do
374
- visible_if!("tree1 visible") do
375
- view.val == "tree1visible"
373
+ TestAccessControl.view 'Tree1' do
374
+ visible_if!('tree1 visible') do
375
+ view.val == 'tree1visible'
376
376
  end
377
377
  end
378
378
 
379
379
  TestAccessControl.always do
380
- visible_if!("tree2 visible") do
381
- view.val == "alwaysvisible"
380
+ visible_if!('tree2 visible') do
381
+ view.val == 'alwaysvisible'
382
382
  end
383
383
  end
384
384
 
385
- refute_serializes(Tree1View, Tree1.create(val: "bad"))
386
- assert_serializes(Tree1View, Tree1.create(val: "tree1visible"))
387
- assert_serializes(Tree1View, Tree1.create(val: "alwaysvisible"))
385
+ refute_serializes(Tree1View, Tree1.create(val: 'bad'))
386
+ assert_serializes(Tree1View, Tree1.create(val: 'tree1visible'))
387
+ assert_serializes(Tree1View, Tree1.create(val: 'alwaysvisible'))
388
388
  end
389
389
 
390
390
  def test_editability_always_composition
391
- TestAccessControl.view "Tree1" do
392
- editable_if!("editable1") { view.val == "editable1" }
393
- edit_valid_if!("editvalid1") { view.val == "editvalid1" }
391
+ TestAccessControl.view 'Tree1' do
392
+ editable_if!('editable1') { view.val == 'editable1' }
393
+ edit_valid_if!('editvalid1') { view.val == 'editvalid1' }
394
394
  end
395
395
 
396
396
  TestAccessControl.always do
397
- editable_if!("editable2") { view.val == "editable2" }
398
- edit_valid_if!("editvalid2") { view.val == "editvalid2" }
397
+ editable_if!('editable2') { view.val == 'editable2' }
398
+ edit_valid_if!('editvalid2') { view.val == 'editvalid2' }
399
399
 
400
- visible_if!("always") { true }
400
+ visible_if!('always') { true }
401
401
  end
402
402
 
403
- refute_deserializes(Tree1View, Tree1.create!(val: "bad")) { |v, _| v["val"] = "alsobad" }
403
+ refute_deserializes(Tree1View, Tree1.create!(val: 'bad')) { |v, _| v['val'] = 'alsobad' }
404
404
 
405
- assert_deserializes(Tree1View, Tree1.create!(val: "editable1")) { |v, _| v["val"] = "unchecked" }
406
- assert_deserializes(Tree1View, Tree1.create!(val: "editable2")) { |v, _| v["val"] = "unchecked" }
405
+ assert_deserializes(Tree1View, Tree1.create!(val: 'editable1')) { |v, _| v['val'] = 'unchecked' }
406
+ assert_deserializes(Tree1View, Tree1.create!(val: 'editable2')) { |v, _| v['val'] = 'unchecked' }
407
407
 
408
- assert_deserializes(Tree1View, Tree1.create!(val: "unchecked")) { |v, _| v["val"] = "editvalid1" }
409
- assert_deserializes(Tree1View, Tree1.create!(val: "unchecked")) { |v, _| v["val"] = "editvalid2" }
408
+ assert_deserializes(Tree1View, Tree1.create!(val: 'unchecked')) { |v, _| v['val'] = 'editvalid1' }
409
+ assert_deserializes(Tree1View, Tree1.create!(val: 'unchecked')) { |v, _| v['val'] = 'editvalid2' }
410
410
  end
411
411
 
412
412
  def test_ancestry
413
- TestAccessControl.view "Tree1" do
414
- visible_if!("parent tree1") { view.val == "parenttree1" }
413
+ TestAccessControl.view 'Tree1' do
414
+ visible_if!('parent tree1') { view.val == 'parenttree1' }
415
415
  end
416
416
 
417
417
  TestAccessControl.always do
418
- visible_if!("parent always") { view.val == "parentalways" }
418
+ visible_if!('parent always') { view.val == 'parentalways' }
419
419
  end
420
420
 
421
421
  # Child must be set up after parent is fully defined
422
422
  child_access_control = Class.new(ViewModel::AccessControl::Tree)
423
423
  child_access_control.include_from(TestAccessControl)
424
424
 
425
- child_access_control.view "Tree1" do
426
- visible_if!("child tree1") { view.val == "childtree1" }
425
+ child_access_control.view 'Tree1' do
426
+ visible_if!('child tree1') { view.val == 'childtree1' }
427
427
  end
428
428
 
429
429
  child_access_control.always do
430
- visible_if!("child always") { view.val == "childalways" }
430
+ visible_if!('child always') { view.val == 'childalways' }
431
431
  end
432
432
 
433
433
  s_ctx = Tree1View.new_serialize_context(access_control: child_access_control.new)
434
434
 
435
- refute_serializes(Tree1View, Tree1.create!(val: "bad"), serialize_context: s_ctx)
435
+ refute_serializes(Tree1View, Tree1.create!(val: 'bad'), serialize_context: s_ctx)
436
436
 
437
- assert_serializes(Tree1View, Tree1.create!(val: "parenttree1"), serialize_context: s_ctx)
438
- assert_serializes(Tree1View, Tree1.create!(val: "parentalways"), serialize_context: s_ctx)
439
- assert_serializes(Tree1View, Tree1.create!(val: "childtree1"), serialize_context: s_ctx)
440
- assert_serializes(Tree1View, Tree1.create!(val: "childalways"), serialize_context: s_ctx)
437
+ assert_serializes(Tree1View, Tree1.create!(val: 'parenttree1'), serialize_context: s_ctx)
438
+ assert_serializes(Tree1View, Tree1.create!(val: 'parentalways'), serialize_context: s_ctx)
439
+ assert_serializes(Tree1View, Tree1.create!(val: 'childtree1'), serialize_context: s_ctx)
440
+ assert_serializes(Tree1View, Tree1.create!(val: 'childalways'), serialize_context: s_ctx)
441
441
  end
442
442
  end
443
443
 
@@ -574,7 +574,7 @@ class ViewModel::AccessControlTest < ActiveSupport::TestCase
574
574
  model_class.new(
575
575
  name: 'a',
576
576
  children: [child_model_class.new(name: 'x', position: 1),
577
- child_model_class.new(name: 'y', position: 2)])
577
+ child_model_class.new(name: 'y', position: 2),])
578
578
  end
579
579
 
580
580
  it 'records new children' do
@@ -619,7 +619,7 @@ class ViewModel::AccessControlTest < ActiveSupport::TestCase
619
619
 
620
620
  new_child = vm.children.detect { |c| c.name == 'b' }
621
621
  c_changes = ctx.valid_edit_changes(new_child.to_reference)
622
- assert_changes_match(c_changes, n:true, att: ['name'])
622
+ assert_changes_match(c_changes, n: true, att: ['name'])
623
623
 
624
624
  oc_changes = ctx.valid_edit_changes(
625
625
  ViewModel::Reference.new(child_viewmodel_class, replaced_child.id))