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
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class ViewModel
2
4
  # A bucket for configuration, used for serializing and deserializing.
3
5
  class References
@@ -17,14 +19,15 @@ class ViewModel
17
19
  # under which the data is stored. If the data is not present, will compute
18
20
  # it by calling the given block.
19
21
  def add_reference(value)
20
- if (ref = @ref_by_value[value]).present?
21
- ref
22
- else
22
+ ref = @ref_by_value[value]
23
+
24
+ unless ref.present?
23
25
  ref = new_ref!(value)
24
26
  @ref_by_value[value] = ref
25
27
  @value_by_ref[ref] = value
26
- ref
27
28
  end
29
+
30
+ ref
28
31
  end
29
32
 
30
33
  def clear!
@@ -41,7 +44,7 @@ class ViewModel
41
44
  hash = Digest::SHA256.base64digest("#{vm_ref.viewmodel_class.name}.#{vm_ref.model_id}")
42
45
  "ref:h:#{hash}"
43
46
  else
44
- 'ref:i:%06d' % (@last_ref += 1)
47
+ format('ref:i:%06<count>d', count: (@last_ref += 1))
45
48
  end
46
49
  end
47
50
  end
@@ -12,7 +12,7 @@ class ViewModel::Registry
12
12
 
13
13
  def initialize
14
14
  @lock = Monitor.new
15
- @viewmodel_classes_by_name = {}
15
+ @viewmodel_classes_by_name = {}
16
16
  @deferred_viewmodel_classes = []
17
17
  end
18
18
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'json'
2
4
  require 'json_schema'
3
5
 
@@ -9,7 +11,8 @@ class ViewModel::Schemas
9
11
 
10
12
  ID_SCHEMA =
11
13
  { 'oneOf' => [{ 'type' => 'integer' },
12
- { 'type' => 'string', 'format' => 'uuid' }] }
14
+ { 'type' => 'string', 'format' => 'uuid' },] }.freeze
15
+
13
16
  ID = JsonSchema.parse!(ID_SCHEMA)
14
17
 
15
18
  VIEWMODEL_UPDATE_SCHEMA =
@@ -20,8 +23,9 @@ class ViewModel::Schemas
20
23
  ViewModel::ID_ATTRIBUTE => ID_SCHEMA,
21
24
  ViewModel::NEW_ATTRIBUTE => { 'type' => 'boolean' },
22
25
  ViewModel::VERSION_ATTRIBUTE => { 'type' => 'integer' } },
23
- 'required' => [ViewModel::TYPE_ATTRIBUTE]
24
- }
26
+ 'required' => [ViewModel::TYPE_ATTRIBUTE],
27
+ }.freeze
28
+
25
29
  VIEWMODEL_UPDATE = JsonSchema.parse!(VIEWMODEL_UPDATE_SCHEMA)
26
30
 
27
31
  VIEWMODEL_REFERENCE_SCHEMA =
@@ -31,7 +35,8 @@ class ViewModel::Schemas
31
35
  'properties' => { ViewModel::REFERENCE_ATTRIBUTE => { 'type' => 'string' } },
32
36
  'additionalProperties' => false,
33
37
  'required' => [ViewModel::REFERENCE_ATTRIBUTE],
34
- }
38
+ }.freeze
39
+
35
40
  VIEWMODEL_REFERENCE = JsonSchema.parse!(VIEWMODEL_REFERENCE_SCHEMA)
36
41
 
37
42
  def self.verify_schema!(schema, value)
@@ -1,7 +1,10 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class ViewModel::SerializationError < ViewModel::AbstractError
2
4
  attr_reader :detail
5
+
3
6
  status 400
4
- code "SerializationError"
7
+ code 'SerializationError'
5
8
 
6
9
  def initialize(detail)
7
10
  @detail = detail
@@ -38,10 +38,10 @@ class ViewModel::SerializeContext < ViewModel::TraversalContext
38
38
 
39
39
  while references.present?
40
40
  extract_referenced_views!.each do |ref, value|
41
- unless serialized_refs.has_key?(ref)
42
- serialized_refs[ref] = Jbuilder.new do |j|
43
- ViewModel.serialize(value, j, serialize_context: reference_context)
44
- end
41
+ next if serialized_refs.has_key?(ref)
42
+
43
+ serialized_refs[ref] = Jbuilder.new do |j|
44
+ ViewModel.serialize(value, j, serialize_context: reference_context)
45
45
  end
46
46
  end
47
47
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  ##
2
4
  # Helpers useful for writing tests for viewmodel implementations
3
5
  module ViewModel::TestHelpers
@@ -51,11 +53,13 @@ module ViewModel::TestHelpers
51
53
 
52
54
  def assert_consistent_record(viewmodel, been_there: Set.new)
53
55
  return if been_there.include?(viewmodel.model)
56
+
54
57
  been_there << viewmodel.model
55
58
 
56
- if viewmodel.is_a?(ViewModel::ActiveRecord)
59
+ case viewmodel
60
+ when ViewModel::ActiveRecord
57
61
  assert_model_represents_database(viewmodel.model, been_there: been_there)
58
- elsif viewmodel.is_a?(ViewModel::Record)
62
+ when ViewModel::Record
59
63
  viewmodel.class._members.each do |name, attribute_data|
60
64
  if attribute_data.attribute_viewmodel
61
65
  assert_consistent_record(viewmodel.send(name), been_there: been_there)
@@ -66,6 +70,7 @@ module ViewModel::TestHelpers
66
70
 
67
71
  def assert_model_represents_database(model, been_there: Set.new)
68
72
  return if been_there.include?(model)
73
+
69
74
  been_there << model
70
75
 
71
76
  refute(model.new_record?, 'model represents database entity')
@@ -83,7 +88,7 @@ module ViewModel::TestHelpers
83
88
  next unless association.loaded?
84
89
 
85
90
  case
86
- when association.target == nil
91
+ when association.target.nil?
87
92
  assert_nil(database_model.association(reflection.name).target,
88
93
  'in memory nil association matches database')
89
94
  when reflection.collection?
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class ViewModel::TestHelpers::ARVMBuilder
2
4
  attr_reader :name, :model, :viewmodel, :namespace
3
5
 
@@ -46,16 +48,16 @@ class ViewModel::TestHelpers::ARVMBuilder
46
48
  instance_eval(&block)
47
49
  end
48
50
 
49
- raise "Model not created in ARVMBuilder" unless model
50
- raise "Schema not created in ARVMBuilder" unless model.table_exists?
51
- raise "ViewModel not created in ARVMBuilder" unless (viewmodel || @no_viewmodel)
51
+ raise 'Model not created in ARVMBuilder' unless model
52
+ raise 'Schema not created in ARVMBuilder' unless model.table_exists?
53
+ raise 'ViewModel not created in ARVMBuilder' unless viewmodel || @no_viewmodel
52
54
 
53
55
  # Force the realization of the view model into the library's lookup
54
56
  # table. If this doesn't happen the library may have conflicting entries in
55
57
  # the deferred table, and will allow viewmodels to leak between tests.
56
58
  unless @no_viewmodel || !(@viewmodel < ViewModel::Record)
57
59
  resolved = ViewModel::Registry.for_view_name(viewmodel.view_name)
58
- raise "Failed to register expected new class!" unless resolved == @viewmodel
60
+ raise 'Failed to register expected new class!' unless resolved == @viewmodel
59
61
  end
60
62
  end
61
63
 
@@ -70,7 +72,7 @@ class ViewModel::TestHelpers::ARVMBuilder
70
72
  private
71
73
 
72
74
  def viewmodel_name
73
- self.name + "View"
75
+ self.name + 'View'
74
76
  end
75
77
 
76
78
  def define_schema(&block)
@@ -84,10 +86,11 @@ class ViewModel::TestHelpers::ARVMBuilder
84
86
 
85
87
  def define_model(&block)
86
88
  model_name = name
87
- _namespace = namespace
88
- @model = Class.new(@model_base) do |c|
89
- raise "Model already defined: #{model_name}" if _namespace.const_defined?(model_name, false)
90
- _namespace.const_set(model_name, self)
89
+ model_namespace = namespace
90
+ @model = Class.new(@model_base) do |_c|
91
+ raise "Model already defined: #{model_name}" if model_namespace.const_defined?(model_name, false)
92
+
93
+ model_namespace.const_set(model_name, self)
91
94
  class_eval(&block)
92
95
  reset_column_information
93
96
  end
@@ -96,13 +99,15 @@ class ViewModel::TestHelpers::ARVMBuilder
96
99
 
97
100
  def define_viewmodel(&block)
98
101
  vm_name = viewmodel_name
99
- _namespace = namespace
100
- @viewmodel = Class.new(@viewmodel_base) do |c|
101
- raise "Viewmodel alreay defined: #{vm_name}" if _namespace.const_defined?(vm_name, false)
102
- _namespace.const_set(vm_name, self)
102
+ vm_namespace = namespace
103
+ @viewmodel = Class.new(@viewmodel_base) do |_c|
104
+ raise "Viewmodel alreay defined: #{vm_name}" if vm_namespace.const_defined?(vm_name, false)
105
+
106
+ vm_namespace.const_set(vm_name, self)
103
107
  class_eval(&block)
104
108
  end
105
- raise "help help" if @viewmodel.name.nil?
109
+ raise 'help help' if @viewmodel.name.nil?
110
+
106
111
  @viewmodel
107
112
  end
108
113
 
@@ -21,6 +21,7 @@ class ViewModel::TraversalContext
21
21
  end
22
22
 
23
23
  attr_reader :shared_context
24
+
24
25
  delegate :access_control, :callbacks, to: :shared_context
25
26
 
26
27
  def self.new_child(*args)
@@ -118,7 +119,7 @@ class ViewModel::TraversalContext
118
119
 
119
120
  def nearest_root_viewmodel
120
121
  if root?
121
- raise RuntimeError.new("Attempted to find nearest root from a root context. This is probably not what you wanted.")
122
+ raise RuntimeError.new('Attempted to find nearest root from a root context. This is probably not what you wanted.')
122
123
  elsif parent_context.root?
123
124
  parent_viewmodel
124
125
  else
@@ -0,0 +1,14 @@
1
+ inherit_from: ../.rubocop.yml
2
+
3
+ Lint/NestedMethodDefinition:
4
+ Enabled: false
5
+ Lint/ConstantDefinitionInBlock:
6
+ Enabled: false
7
+ Layout/MultilineBlockLayout:
8
+ Enabled: false
9
+ Layout/HashAlignment:
10
+ Enabled: false
11
+ Layout/BlockEndNewline:
12
+ Enabled: false
13
+ Style/Semicolon:
14
+ Enabled: false
@@ -1,19 +1,22 @@
1
- require_relative "test_access_control.rb"
1
+ # frozen_string_literal: true
2
2
 
3
- require "iknow_view_models"
4
- require "view_model/active_record"
5
- require "view_model/active_record/controller"
3
+ require_relative 'test_access_control'
6
4
 
7
- require "acts_as_manual_list"
5
+ require 'iknow_view_models'
6
+ require 'view_model/active_record'
7
+ require 'view_model/active_record/controller'
8
+
9
+ require 'acts_as_manual_list'
8
10
 
9
11
  db_config_path = File.join(File.dirname(__FILE__), '../config/database.yml')
10
- db_config = YAML.load(File.open(db_config_path))
11
- raise "Test database configuration missing" unless db_config["test"]
12
- ActiveRecord::Base.establish_connection(db_config["test"])
12
+ db_config = YAML.safe_load(File.open(db_config_path))
13
+ raise 'Test database configuration missing' unless db_config['test']
14
+
15
+ ActiveRecord::Base.establish_connection(db_config['test'])
13
16
 
14
17
  # Remove test tables if any exist
15
18
  %w[labels parents children targets poly_ones poly_twos owners
16
- grand_parents categories tags parents_tags].each do |t|
19
+ grand_parents categories tags parents_tags].each do |t|
17
20
  ActiveRecord::Base.connection.execute("DROP TABLE IF EXISTS #{t} CASCADE")
18
21
  end
19
22
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'active_support'
2
4
  require 'minitest/hooks'
3
5
 
@@ -10,7 +12,7 @@ unless ViewModel::Config.configured?
10
12
  end
11
13
  end
12
14
 
13
- require_relative 'query_logging.rb'
15
+ require_relative 'query_logging'
14
16
 
15
17
  ActiveSupport::TestCase.include(Minitest::Hooks)
16
18
 
@@ -91,7 +93,7 @@ module ARVMTestUtilities
91
93
 
92
94
  def enable_logging!
93
95
  if ENV['DEBUG']
94
- ActiveRecord::Base.logger = Logger.new(STDERR)
96
+ ActiveRecord::Base.logger = Logger.new($stderr)
95
97
  end
96
98
  end
97
99
 
@@ -170,7 +172,7 @@ module ARVMTestUtilities
170
172
  {
171
173
  ViewModel::ActiveRecord::TYPE_ATTRIBUTE => type::NAME,
172
174
  ViewModel::ActiveRecord::VALUES_ATTRIBUTE => values,
173
- }.merge(rest.transform_keys(&:to_s))
175
+ }.merge(rest.transform_keys(&:to_s)),
174
176
  )
175
177
  end
176
178
 
@@ -1,11 +1,13 @@
1
- require "iknow_view_models"
2
- require "view_model/active_record"
3
- require "view_model/active_record/controller"
1
+ # frozen_string_literal: true
4
2
 
5
- require_relative "../helpers/arvm_test_utilities.rb"
6
- require_relative "../helpers/arvm_test_models.rb"
3
+ require 'iknow_view_models'
4
+ require 'view_model/active_record'
5
+ require 'view_model/active_record/controller'
7
6
 
8
- require "acts_as_manual_list"
7
+ require_relative '../helpers/arvm_test_utilities'
8
+ require_relative '../helpers/arvm_test_models'
9
+
10
+ require 'acts_as_manual_list'
9
11
 
10
12
  # models for ARVM controller test
11
13
  module ControllerTestModels
@@ -94,7 +96,7 @@ module ControllerTestModels
94
96
  end
95
97
  end
96
98
 
97
- down do |view, refs|
99
+ down do |view, _refs|
98
100
  view['old_name'] = view.delete('name')
99
101
  end
100
102
  end
@@ -152,18 +154,16 @@ class DummyController
152
154
  end
153
155
 
154
156
  def invoke(method)
155
- begin
156
- self.public_send(method)
157
- rescue Exception => ex
158
- handler = self.class.rescue_block(ex.class)
159
- case handler
160
- when nil
161
- raise
162
- when Symbol
163
- self.send(handler, ex)
164
- when Proc
165
- self.instance_exec(ex, &handler)
166
- end
157
+ self.public_send(method)
158
+ rescue StandardError => ex
159
+ handler = self.class.rescue_block(ex.class)
160
+ case handler
161
+ when nil
162
+ raise
163
+ when Symbol
164
+ self.send(handler, ex)
165
+ when Proc
166
+ self.instance_exec(ex, &handler)
167
167
  end
168
168
  end
169
169
 
@@ -183,7 +183,8 @@ class DummyController
183
183
  end
184
184
 
185
185
  def json_response
186
- raise "Not a JSON response" unless @content_type == 'application/json'
186
+ raise 'Not a JSON response' unless @content_type == 'application/json'
187
+
187
188
  @response_body
188
189
  end
189
190
 
@@ -194,6 +195,7 @@ class DummyController
194
195
  class << self
195
196
  def inherited(subclass)
196
197
  subclass.initialize_rescue_blocks
198
+ super
197
199
  end
198
200
 
199
201
  def initialize_rescue_blocks
@@ -205,11 +207,10 @@ class DummyController
205
207
  end
206
208
 
207
209
  def rescue_block(type)
208
- @rescue_blocks.to_a.reverse.detect { |btype, h| type <= btype }.try(&:last)
210
+ @rescue_blocks.to_a.reverse.detect { |btype, _h| type <= btype }.try(&:last)
209
211
  end
210
212
 
211
- def etag(*)
212
- end
213
+ def etag(*); end
213
214
  end
214
215
  end
215
216
 
@@ -230,14 +231,15 @@ end
230
231
 
231
232
  module CallbackTracing
232
233
  attr_reader :callback_tracer
234
+
233
235
  delegate :hook_trace, to: :callback_tracer
234
236
 
235
- def new_deserialize_context(**args)
237
+ def new_deserialize_context(**_args)
236
238
  @callback_tracer ||= CallbackTracer.new
237
239
  super(callbacks: [@callback_tracer])
238
240
  end
239
241
 
240
- def new_serialize_context(**args)
242
+ def new_serialize_context(**_args)
241
243
  @callback_tracer ||= CallbackTracer.new
242
244
  super(callbacks: [@callback_tracer])
243
245
  end
@@ -247,14 +249,14 @@ module ControllerTestControllers
247
249
  def before_all
248
250
  super
249
251
 
250
- Class.new(DummyController) do |c|
252
+ Class.new(DummyController) do |_c|
251
253
  Object.const_set(:ParentController, self)
252
254
  include ViewModel::ActiveRecord::Controller
253
255
  include CallbackTracing
254
256
  self.access_control = ViewModel::AccessControl::Open
255
257
  end
256
258
 
257
- Class.new(DummyController) do |c|
259
+ Class.new(DummyController) do |_c|
258
260
  Object.const_set(:ChildController, self)
259
261
  include ViewModel::ActiveRecord::Controller
260
262
  include CallbackTracing
@@ -262,7 +264,7 @@ module ControllerTestControllers
262
264
  nested_in :parent, as: :children
263
265
  end
264
266
 
265
- Class.new(DummyController) do |c|
267
+ Class.new(DummyController) do |_c|
266
268
  Object.const_set(:LabelController, self)
267
269
  include ViewModel::ActiveRecord::Controller
268
270
  include CallbackTracing
@@ -270,7 +272,7 @@ module ControllerTestControllers
270
272
  nested_in :parent, as: :label
271
273
  end
272
274
 
273
- Class.new(DummyController) do |c|
275
+ Class.new(DummyController) do |_c|
274
276
  Object.const_set(:TargetController, self)
275
277
  include ViewModel::ActiveRecord::Controller
276
278
  include CallbackTracing