activerecord-virtual_attributes 7.1.0 → 7.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e4a4b9dd1a4f51cfef16c50545afe8c064f1727a4580016b400b78afe4279a15
4
- data.tar.gz: 8a4c28698b8191586fb25dfe0885b54300306ac2f5a3866e7731bc789bd85654
3
+ metadata.gz: 0f9b4d5589eb768e0f866cd4d4cdf54e937284a98aea2ff1644e8dddb56413f9
4
+ data.tar.gz: 981261df2b4e1092f1206eb633b064d7605ada874ac1c56946524b89461f7779
5
5
  SHA512:
6
- metadata.gz: 0b06ebb3ad544e2c19f4b0a103ec54cd471fa9a187cee566399b985446244baadac66d35a343dc7311b7b73963bb55a15d87a3968287ea434f1093595073c974
7
- data.tar.gz: e904ebef2e7594f37055971d738a20343c546834ec7597d10816949a005f1ba6dbd979cc422b1ba1b99a079e699c9219b97907e798d9eee5e3fbfa7ce114e1f6
6
+ metadata.gz: 5bf6835a1bc40e8fd619b1f5b00a84d2f39f86ce51de170941d71e9880a1ae9c6c061b523c43f801664c8ec5789363f55d016207acde9e66655207c22fa923bf
7
+ data.tar.gz: 52a5dff2126f009791c7f9dad66647b0d589d9f0c659a184c79307fb087505b37bb23e8ad3c95c82c4939531d86ed8f11cc874f0b141c34cd5836cc122897dc6
data/CHANGELOG.md CHANGED
@@ -4,6 +4,14 @@ The versioning of this gem follows ActiveRecord versioning, and does not follow
4
4
 
5
5
  ## [Unreleased]
6
6
 
7
+ ## [7.1.2] - 2025-06-20
8
+
9
+ * Introduce virtual_has_many :through [#191](https://github.com/ManageIQ/activerecord-virtual_attributes/pull/191)
10
+
11
+ ## [7.1.1] - 2025-06-18
12
+
13
+ * Deprecate virtual_delegate without a type [#188](https://github.com/ManageIQ/activerecord-virtual_attributes/pull/188)
14
+
7
15
  ## [7.1.0] - 2025-02-19
8
16
 
9
17
  * Use TableAlias for table aliasing [#168](https://github.com/ManageIQ/activerecord-virtual_attributes/pull/168)
@@ -111,7 +119,9 @@ The versioning of this gem follows ActiveRecord versioning, and does not follow
111
119
  * Initial Release
112
120
  * Extracted from ManageIQ/manageiq
113
121
 
114
- [Unreleased]: https://github.com/ManageIQ/activerecord-virtual_attributes/compare/v7.1.0...HEAD
122
+ [Unreleased]: https://github.com/ManageIQ/activerecord-virtual_attributes/compare/v7.1.2...HEAD
123
+ [7.1.2]: https://github.com/ManageIQ/activerecord-virtual_attributes/compare/v7.1.1...v7.1.2
124
+ [7.1.1]: https://github.com/ManageIQ/activerecord-virtual_attributes/compare/v7.1.0...v7.1.1
115
125
  [7.1.0]: https://github.com/ManageIQ/activerecord-virtual_attributes/compare/v7.0.0...v7.1.0
116
126
  [7.0.0]: https://github.com/ManageIQ/activerecord-virtual_attributes/compare/v6.1.2...v7.0.0
117
127
  [6.1.2]: https://github.com/ManageIQ/activerecord-virtual_attributes/compare/v6.1.1...v6.1.2
@@ -28,14 +28,13 @@ Gem::Specification.new do |spec|
28
28
 
29
29
  spec.require_paths = ["lib"]
30
30
 
31
- spec.add_dependency "concurrent-ruby", "< 1.3.5" # Temporary pin down as concurrent-ruby 1.3.5 breaks Rails 7.0, and rails-core doesn't
32
- # plan to ship a new 7.0 to fix it. See https://github.com/rails/rails/pull/54264
33
- spec.add_runtime_dependency "activerecord", "~> 7.0", ">=7.0.8.7"
31
+ spec.add_runtime_dependency "activerecord", "~> 7.1", ">=7.1.5.1"
34
32
 
35
33
  spec.add_development_dependency "byebug"
36
34
  spec.add_development_dependency "database_cleaner-active_record", "~> 2.1"
37
35
  spec.add_development_dependency "db-query-matchers"
38
- spec.add_development_dependency "manageiq-style", ">= 1.5.3"
36
+ spec.add_development_dependency "manageiq-style", ">= 1.5.4"
37
+
39
38
  spec.add_development_dependency "mysql2"
40
39
  spec.add_development_dependency "pg"
41
40
  spec.add_development_dependency "rake", "~> 13.0"
@@ -1,5 +1,5 @@
1
1
  module ActiveRecord
2
2
  module VirtualAttributes
3
- VERSION = "7.1.0".freeze
3
+ VERSION = "7.1.2".freeze
4
4
  end
5
5
  end
@@ -111,52 +111,9 @@ module ActiveRecord
111
111
  private
112
112
 
113
113
  def define_virtual_arel(name, arel) # :nodoc:
114
- self._virtual_arel = _virtual_arel.merge(name => arel)
114
+ self._virtual_arel = _virtual_arel.merge(name.to_s => arel)
115
115
  end
116
116
  end
117
117
  end
118
118
  end
119
119
  end
120
-
121
- # fixed in https://github.com/rails/rails/pull/45642
122
- if ActiveRecord.version < Gem::Version.new(7.1)
123
- module Arel # :nodoc: all
124
- # rubocop:disable Naming/MethodName
125
- # rubocop:disable Naming/MethodParameterName
126
- # rubocop:disable Style/ConditionalAssignment
127
- module Visitors
128
- # rails 6.1...
129
- class ToSql
130
- private
131
-
132
- def visit_Arel_Nodes_HomogeneousIn(o, collector)
133
- collector.preparable = false
134
-
135
- # change:
136
- # See https://github.com/rails/rails/pull/45642
137
- visit(o.left, collector)
138
- # /change
139
-
140
- if o.type == :in
141
- collector << " IN ("
142
- else
143
- collector << " NOT IN ("
144
- end
145
-
146
- values = o.casted_values
147
-
148
- if values.empty?
149
- collector << @connection.quote(nil)
150
- else
151
- collector.add_binds(values, o.proc_for_binds, &bind_block)
152
- end
153
-
154
- collector << ")"
155
- end
156
- end
157
- end
158
- # rubocop:enable Naming/MethodName
159
- # rubocop:enable Naming/MethodParameterName
160
- # rubocop:enable Style/ConditionalAssignment
161
- end
162
- end
@@ -10,8 +10,7 @@ module ActiveRecord
10
10
  extend ActiveSupport::Concern
11
11
 
12
12
  included do
13
- class_attribute :virtual_delegates_to_define, :instance_accessor => false
14
- self.virtual_delegates_to_define = {}
13
+ class_attribute :virtual_delegates_to_define, :instance_accessor => false, :default => {}
15
14
  end
16
15
 
17
16
  module ClassMethods
@@ -19,38 +18,28 @@ module ActiveRecord
19
18
  # Definition
20
19
  #
21
20
 
22
- def virtual_delegate(*methods)
23
- options = methods.extract_options!
24
- unless (to = options[:to])
25
- raise ArgumentError, 'Delegation needs an association. Supply an options hash with a :to key as the last argument (e.g. delegate :hello, to: :greeter).'
21
+ def virtual_delegate(*methods, to:, type: nil, prefix: nil, allow_nil: nil, default: nil, **options) # rubocop:disable Naming/MethodParameterName
22
+ unless type
23
+ ActiveRecord::VirtualAttributes.deprecator.warn("Calling virtual_delegate without :type is now deprecated", caller)
26
24
  end
27
25
 
28
26
  to = to.to_s
29
- if to.include?(".") && methods.size > 1
30
- raise ArgumentError, 'Delegation only supports specifying a method name when defining a single virtual method'
27
+ if to.include?(".") && (methods.size > 1 || prefix)
28
+ raise ArgumentError, 'Delegation only supports specifying a target method name when defining a single virtual method with no prefix'
31
29
  end
32
30
 
33
31
  if to.count(".") > 1
34
- raise ArgumentError, 'Delegation needs a single association. Supply an option hash with a :to key with only 1 period (e.g. delegate :hello, to: "greeter.greeting")'
32
+ raise ArgumentError, 'Delegation needs a single association. Supply keyword :to with only 1 period (e.g. delegate :hello, to: "greeter.greeting")'
35
33
  end
36
34
 
37
- allow_nil = options[:allow_nil]
38
- default = options[:default]
39
-
40
35
  # put method entry per method name.
41
36
  # This better supports reloading of the class and changing the definitions
42
37
  methods.each do |method|
43
- method_prefix = virtual_delegate_name_prefix(options[:prefix], to)
44
- method_name = "#{method_prefix}#{method}"
45
- if to.include?(".") # to => "target.method"
46
- to, method = to.split(".").map(&:to_sym)
47
- options[:to] = to
48
- end
49
-
38
+ method_name, to, method = determine_method_names(method, to, prefix)
50
39
  define_delegate(method_name, method, :to => to, :allow_nil => allow_nil, :default => default)
51
40
 
52
41
  self.virtual_delegates_to_define =
53
- virtual_delegates_to_define.merge(method_name => [method, options])
42
+ virtual_delegates_to_define.merge(method_name.to_s => [method, options.merge(:to => to, :type => type)])
54
43
  end
55
44
  end
56
45
 
@@ -80,6 +69,7 @@ module ActiveRecord
80
69
  end
81
70
 
82
71
  # see activesupport module/delegation.rb
72
+ # rubocop:disable Style/TernaryParentheses
83
73
  def define_delegate(method_name, method, to: nil, allow_nil: nil, default: nil) # rubocop:disable Naming/MethodParameterName
84
74
  location = caller_locations(2, 1).first
85
75
  file, line = location.path, location.lineno
@@ -125,9 +115,27 @@ module ActiveRecord
125
115
  method_def = method_def.split("\n").map(&:strip).join(';')
126
116
  module_eval(method_def, file, line)
127
117
  end
118
+ # rubocop:enable Style/TernaryParentheses
119
+
120
+ # Sometimes the `to` contains the column name target.column, split it up to the source method_name and target column
121
+ # If `to` does specify the column name, `to` becomes the target (i.e.: association)
122
+ #
123
+ # @param column [Symbol|String] the name of the column
124
+ # @param to [Symbol|String]
125
+ # @param prefix [Boolean|Nil|Symbol]
126
+ # @return [Symbol, Symbol, Symbol] method_name, relation, relation's column name
127
+ def determine_method_names(column, to, prefix) # rubocop:disable Naming/MethodParameterName
128
+ method_name = column = column.to_sym
129
+
130
+ tos = to.to_s
131
+ if tos.include?(".") # to => "target.method"
132
+ to, column = tos.split(".").map(&:to_sym)
133
+ end
134
+
135
+ method_prefix = "#{prefix == true ? to : prefix}_" if prefix
136
+ method_name = "#{method_prefix}#{method_name}".to_sym
128
137
 
129
- def virtual_delegate_name_prefix(prefix, to) # rubocop:disable Naming/MethodParameterName
130
- "#{prefix == true ? to : prefix}_" if prefix
138
+ [method_name, to.to_sym, column]
131
139
  end
132
140
 
133
141
  # @param col [String] attribute name
@@ -143,7 +143,7 @@ module ActiveRecord
143
143
 
144
144
  module Associations
145
145
  class Preloader
146
- prepend(Module.new {
146
+ prepend(Module.new do
147
147
  # preloader is called with virtual attributes - need to resolve
148
148
  def call
149
149
  # Possibly overkill since all records probably have the same class and associations
@@ -165,11 +165,14 @@ module ActiveRecord
165
165
  end
166
166
  end
167
167
  end
168
- })
168
+ end)
169
169
 
170
170
  class Branch
171
- prepend(Module.new {
171
+ prepend(Module.new do
172
172
  # from branched.rb 7.0
173
+ # not going to modify rails code for rubocops
174
+ # rubocop:disable Lint/AmbiguousOperatorPrecedence
175
+ # rubocop:disable Layout/EmptyLineAfterGuardClause
173
176
  def grouped_records
174
177
  h = {}
175
178
  polymorphic_parent = !root? && parent.polymorphic?
@@ -184,6 +187,8 @@ module ActiveRecord
184
187
  end
185
188
  h
186
189
  end
190
+ # rubocop:enable Layout/EmptyLineAfterGuardClause
191
+ # rubocop:enable Lint/AmbiguousOperatorPrecedence
187
192
 
188
193
  # branched.rb 7.0
189
194
  def preloaders_for_reflection(reflection, reflection_records)
@@ -206,13 +211,13 @@ module ActiveRecord
206
211
  preloader_for(reflection).new(rhs_klass, rs, reflection, scope, reflection_scope, associate_by_default)
207
212
  end
208
213
  end
209
- })
214
+ end)
210
215
  end
211
216
  end
212
217
  end
213
218
 
214
219
  class Relation
215
- include(Module.new {
220
+ include(Module.new do
216
221
  # From ActiveRecord::QueryMethods (rails 5.2 - 6.1)
217
222
  def build_select(arel)
218
223
  if select_values.any?
@@ -243,6 +248,6 @@ module ActiveRecord
243
248
  associations = klass.replace_virtual_fields(associations) || {}
244
249
  super
245
250
  end
246
- })
251
+ end)
247
252
  end
248
253
  end
@@ -25,7 +25,7 @@ module ActiveRecord
25
25
  private
26
26
 
27
27
  def define_virtual_include(name, uses)
28
- self._virtual_includes = _virtual_includes.merge(name => uses)
28
+ self._virtual_includes = _virtual_includes.merge(name.to_s => uses)
29
29
  end
30
30
  end
31
31
  end
@@ -5,31 +5,28 @@ module ActiveRecord
5
5
  include ActiveRecord::VirtualAttributes::VirtualIncludes
6
6
 
7
7
  module ClassMethods
8
-
9
8
  #
10
9
  # Definition
11
10
  #
12
11
 
13
- def virtual_has_one(name, options = {})
14
- uses = options.delete(:uses)
12
+ def virtual_has_one(name, uses: nil, **options)
15
13
  reflection = ActiveRecord::Associations::Builder::HasOne.build(self, name, nil, options)
16
- add_virtual_reflection(reflection, name, uses, options)
14
+ add_virtual_reflection(reflection, name, uses)
17
15
  end
18
16
 
19
- def virtual_has_many(name, options = {})
17
+ def virtual_has_many(name, uses: nil, source: nil, through: nil, **options)
20
18
  define_method(:"#{name.to_s.singularize}_ids") do
21
19
  records = send(name)
22
20
  records.respond_to?(:ids) ? records.ids : records.collect(&:id)
23
21
  end
24
- uses = options.delete(:uses)
22
+ define_delegate(name, source || name, :to => through, :allow_nil => true, :default => []) if through
25
23
  reflection = ActiveRecord::Associations::Builder::HasMany.build(self, name, nil, options)
26
- add_virtual_reflection(reflection, name, uses, options)
24
+ add_virtual_reflection(reflection, name, uses)
27
25
  end
28
26
 
29
- def virtual_belongs_to(name, options = {})
30
- uses = options.delete(:uses)
27
+ def virtual_belongs_to(name, uses: nil, **options)
31
28
  reflection = ActiveRecord::Associations::Builder::BelongsTo.build(self, name, nil, options)
32
- add_virtual_reflection(reflection, name, uses, options)
29
+ add_virtual_reflection(reflection, name, uses)
33
30
  end
34
31
 
35
32
  def virtual_reflection?(name)
@@ -95,7 +92,7 @@ module ActiveRecord
95
92
 
96
93
  private
97
94
 
98
- def add_virtual_reflection(reflection, name, uses, _options)
95
+ def add_virtual_reflection(reflection, name, uses)
99
96
  raise ArgumentError, "macro must be specified" unless reflection
100
97
 
101
98
  reset_virtual_reflection_information
@@ -1,6 +1,7 @@
1
1
  require "active_support/concern"
2
2
  require "active_record"
3
3
 
4
+ require "active_record/virtual_attributes/version"
4
5
  require "active_record/virtual_attributes/virtual_includes"
5
6
  require "active_record/virtual_attributes/virtual_arel"
6
7
  require "active_record/virtual_attributes/virtual_delegates"
@@ -37,9 +38,12 @@ module ActiveRecord
37
38
  ActiveRecord::Type.register(:string_set, Type::StringSet)
38
39
  ActiveRecord::Type.register(:symbol, Type::Symbol)
39
40
 
41
+ def self.deprecator
42
+ @deprecator ||= ActiveSupport::Deprecation.new(ActiveRecord::VirtualAttributes::VERSION, "virtual_attributes")
43
+ end
44
+
40
45
  included do
41
- class_attribute :virtual_attributes_to_define, :instance_accessor => false
42
- self.virtual_attributes_to_define = {}
46
+ class_attribute :virtual_attributes_to_define, :instance_accessor => false, :default => {}
43
47
  end
44
48
 
45
49
  module ClassMethods
@@ -48,10 +52,7 @@ module ActiveRecord
48
52
  #
49
53
 
50
54
  # Compatibility method: `virtual_attribute` is a more accurate name
51
- def virtual_column(name, **options)
52
- type = options.delete(:type)
53
- raise ArgumentError, "missing :type attribute" unless type
54
-
55
+ def virtual_column(name, type:, **options)
55
56
  virtual_attribute(name, type, **options)
56
57
  end
57
58
 
@@ -101,7 +102,7 @@ module ActiveRecord
101
102
  end
102
103
 
103
104
  def define_virtual_attribute(name, cast_type, uses: nil, arel: nil)
104
- attribute_types[name] = cast_type
105
+ attribute_types[name.to_s] = cast_type
105
106
  define_virtual_include(name, uses) if uses
106
107
  define_virtual_arel(name, arel) if arel
107
108
  end
metadata CHANGED
@@ -1,49 +1,35 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: activerecord-virtual_attributes
3
3
  version: !ruby/object:Gem::Version
4
- version: 7.1.0
4
+ version: 7.1.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Keenan Brock
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2025-02-19 00:00:00.000000000 Z
11
+ date: 2025-06-20 00:00:00.000000000 Z
12
12
  dependencies:
13
- - !ruby/object:Gem::Dependency
14
- name: concurrent-ruby
15
- requirement: !ruby/object:Gem::Requirement
16
- requirements:
17
- - - "<"
18
- - !ruby/object:Gem::Version
19
- version: 1.3.5
20
- type: :runtime
21
- prerelease: false
22
- version_requirements: !ruby/object:Gem::Requirement
23
- requirements:
24
- - - "<"
25
- - !ruby/object:Gem::Version
26
- version: 1.3.5
27
13
  - !ruby/object:Gem::Dependency
28
14
  name: activerecord
29
15
  requirement: !ruby/object:Gem::Requirement
30
16
  requirements:
31
17
  - - "~>"
32
18
  - !ruby/object:Gem::Version
33
- version: '7.0'
19
+ version: '7.1'
34
20
  - - ">="
35
21
  - !ruby/object:Gem::Version
36
- version: 7.0.8.7
22
+ version: 7.1.5.1
37
23
  type: :runtime
38
24
  prerelease: false
39
25
  version_requirements: !ruby/object:Gem::Requirement
40
26
  requirements:
41
27
  - - "~>"
42
28
  - !ruby/object:Gem::Version
43
- version: '7.0'
29
+ version: '7.1'
44
30
  - - ">="
45
31
  - !ruby/object:Gem::Version
46
- version: 7.0.8.7
32
+ version: 7.1.5.1
47
33
  - !ruby/object:Gem::Dependency
48
34
  name: byebug
49
35
  requirement: !ruby/object:Gem::Requirement
@@ -92,14 +78,14 @@ dependencies:
92
78
  requirements:
93
79
  - - ">="
94
80
  - !ruby/object:Gem::Version
95
- version: 1.5.3
81
+ version: 1.5.4
96
82
  type: :development
97
83
  prerelease: false
98
84
  version_requirements: !ruby/object:Gem::Requirement
99
85
  requirements:
100
86
  - - ">="
101
87
  - !ruby/object:Gem::Version
102
- version: 1.5.3
88
+ version: 1.5.4
103
89
  - !ruby/object:Gem::Dependency
104
90
  name: mysql2
105
91
  requirement: !ruby/object:Gem::Requirement