rails_core_extensions 0.12.0 → 0.13.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: 4e362185defe03c222c8b0d0cf77b3281f0fac38fde27f90ed1273d026bb28d7
4
- data.tar.gz: 4f91461d5666fdb4ce836c50e11d0808a27da50605f40343e3c0b17cf53e441f
3
+ metadata.gz: b9a3bc99415c6959119365c5b542dc8ae3c912d004d7a4ae809755c7eeaccc44
4
+ data.tar.gz: 3a3db36a2823a7116674253ede3efe09222829285e038561de663b33bf8b9671
5
5
  SHA512:
6
- metadata.gz: b73a245c3f1039fed5d0b2246d3b758a452364a114af36972ecfbeef970c426389271b9eac2feab4da7d0147b133532477dea28506f5b9cdb486ab943b396b3d
7
- data.tar.gz: 101efda04a0f37b08757be11b4e2d89314e99d3e8935de832d550bd0dae4046d3c69eb9ec124c428dd9c62d59341a2f9015fc98d6619ca8a16329818b2613e83
6
+ metadata.gz: 2b02c74b69ba727097ecea9edbba9db615c517ac15f9573c12770f0ce9893bb31d5beaa8701e259854db15fe41f7f3b49fc269784fabdcf3d51a7c6d0243aec2
7
+ data.tar.gz: deeab7f200cd2439ea720c4c2338dd82d9feb370be4d650bd25675d6cab826c6701e95bdc716f133740a95a083e06d07d977d5c7a7510049a6184ff4a2a10f63
data/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.13.2
4
+
5
+ - [PLAT-390] Fix broken `action_view` extensions
6
+
7
+ ## 0.13.1
8
+
9
+ - [PLAT-384] Fix the liquid extension
10
+
11
+ ## 0.13.0
12
+
13
+ - [PLAT-378] Improve bundler startup time; Drop Concurrency
14
+
3
15
  ## 0.12.0
4
16
 
5
17
  - [PLAT-183] Ruby 3.1, Rails 7.0 and publish coverage with github action
@@ -1,8 +1,6 @@
1
1
  module RailsCoreExtensions
2
2
  module ActionControllerSortable
3
- def self.included(base)
4
- base.extend ClassMethods
5
- end
3
+ extend ActiveSupport::Concern
6
4
 
7
5
  module ClassMethods
8
6
  def sortable
@@ -28,5 +28,7 @@ module RailsCoreExtensions
28
28
  end
29
29
  end
30
30
 
31
- ActionView::Base.send(:include, RailsCoreExtensions::HasManyExtensions::Tags) if defined?(ActionView::Base)
32
- ActionView::Helpers::FormBuilder.send(:include, RailsCoreExtensions::HasManyExtensions::FormBuilder) if defined?(ActionView::Base)
31
+ ActiveSupport.on_load :action_view do
32
+ ActionView::Base.send(:include, RailsCoreExtensions::HasManyExtensions::Tags)
33
+ ActionView::Helpers::FormBuilder.send(:include, RailsCoreExtensions::HasManyExtensions::FormBuilder)
34
+ end
@@ -1,8 +1,6 @@
1
1
  module ActiveModelExtensions
2
2
  module Validations
3
- def self.included(base)
4
- base.extend ClassMethods
5
- end
3
+ extend ActiveSupport::Concern
6
4
 
7
5
  # Validates the presence of the required fields identified in a rule-string.
8
6
  #
@@ -1,7 +1,5 @@
1
1
  module ActiveRecordCloning
2
- def self.included(base)
3
- base.extend(ClassMethods)
4
- end
2
+ extend ActiveSupport::Concern
5
3
 
6
4
  module ClassMethods
7
5
 
@@ -1,7 +1,5 @@
1
1
  module ActiveRecordExtensions
2
- def self.included(base)
3
- base.extend ClassMethods
4
- end
2
+ extend ActiveSupport::Concern
5
3
 
6
4
  module ClassMethods
7
5
  # Like establish_connection but postfixes the key with the rails environment
@@ -1,32 +1,30 @@
1
1
  module RailsCoreExtensions
2
2
  module ActiveRecordLiquidExtensions
3
- def self.included(base)
4
- base.extend ClassMethods
5
- end
6
- end
3
+ extend ActiveSupport::Concern
7
4
 
8
- module ClassMethods
9
- def validates_liquid(field)
10
- field = field.to_sym
11
- before_validation do |record|
12
- begin
13
- Liquid::Template.parse(record.send(field), error_mode: :strict)
14
- rescue Liquid::SyntaxError => e
15
- record.errors.add(field, "Liquid Syntax Error: #{e}")
5
+ module ClassMethods
6
+ def validates_liquid(field)
7
+ field = field.to_sym
8
+ before_validation do |record|
9
+ begin
10
+ Liquid::Template.parse(record.send(field), error_mode: :strict)
11
+ rescue Liquid::SyntaxError => e
12
+ record.errors.add(field, "Liquid Syntax Error: #{e}")
13
+ end
16
14
  end
17
15
  end
18
- end
19
16
 
20
- def liquid_field(field)
21
- class_eval <<-CODE
22
- def parsed_#{field}
23
- Liquid::Template.parse(#{field})
24
- end
17
+ def liquid_field(field)
18
+ class_eval <<-CODE
19
+ def parsed_#{field}
20
+ Liquid::Template.parse(#{field})
21
+ end
25
22
 
26
- def render_#{field}(*args)
27
- parsed_#{field}.render!(*args)
28
- end
29
- CODE
23
+ def render_#{field}(*args)
24
+ parsed_#{field}.render!(*args)
25
+ end
26
+ CODE
27
+ end
30
28
  end
31
29
  end
32
30
  end
@@ -1,8 +1,6 @@
1
1
  module RailsCoreExtensions
2
2
  module Translations
3
- def self.included(base)
4
- base.extend ClassMethods
5
- end
3
+ extend ActiveSupport::Concern
6
4
 
7
5
  module ClassMethods
8
6
  def translate(key, options = {})
@@ -1,3 +1,3 @@
1
1
  module RailsCoreExtensions
2
- VERSION = '0.12.0'
2
+ VERSION = '0.13.2'
3
3
  end
@@ -3,8 +3,6 @@ module RailsCoreExtensions
3
3
  require 'rails_core_extensions/position_initializer'
4
4
  require 'rails_core_extensions/time_with_zone'
5
5
  require 'rails_core_extensions/transfer_records'
6
- require 'rails_core_extensions/active_support_concern'
7
- require 'rails_core_extensions/concurrency'
8
6
 
9
7
  require 'rails_core_extensions/railtie' if defined?(Rails)
10
8
 
@@ -12,15 +10,19 @@ module RailsCoreExtensions
12
10
  require 'rails_core_extensions/activatable'
13
11
  require 'rails_core_extensions/action_controller_sortable'
14
12
 
15
- ActionController::Base.send(:include, Activatable)
16
- ActionController::Base.send(:include, ActionControllerSortable)
13
+ ActiveSupport.on_load(:action_controller) do
14
+ ActionController::Base.send(:include, Activatable)
15
+ ActionController::Base.send(:include, ActionControllerSortable)
16
+ end
17
17
  end
18
18
 
19
19
  if defined? ActionView
20
20
  require 'rails_core_extensions/action_view_extensions'
21
21
  require 'rails_core_extensions/action_view_has_many_extensions'
22
22
 
23
- ActionView::Base.send(:include, RailsCoreExtensions::ActionViewExtensions)
23
+ ActiveSupport.on_load(:action_view) do
24
+ ActionView::Base.send(:include, RailsCoreExtensions::ActionViewExtensions)
25
+ end
24
26
  end
25
27
 
26
28
  if defined? ActiveRecord
@@ -30,11 +32,13 @@ module RailsCoreExtensions
30
32
  require 'rails_core_extensions/translations'
31
33
  require 'rails_core_extensions/active_model_extensions'
32
34
 
33
- ActiveRecord::Base.send(:include, ActiveRecordCloning)
34
- ActiveRecord::Base.send(:include, ActiveRecordExtensions)
35
- ActiveRecord::Base.send(:include, RailsCoreExtensions::ActiveRecordLiquidExtensions)
36
- ActiveRecord::Base.send(:include, ActiveRecordExtensions::InstanceMethods)
37
- ActiveRecord::Base.send(:include, RailsCoreExtensions::Translations)
38
- ActiveRecord::Base.send(:include, ActiveModelExtensions::Validations)
35
+ ActiveSupport.on_load(:active_record) do
36
+ ActiveRecord::Base.send(:include, ActiveRecordCloning)
37
+ ActiveRecord::Base.send(:include, ActiveRecordExtensions)
38
+ ActiveRecord::Base.send(:include, RailsCoreExtensions::ActiveRecordLiquidExtensions)
39
+ ActiveRecord::Base.send(:include, ActiveRecordExtensions::InstanceMethods)
40
+ ActiveRecord::Base.send(:include, RailsCoreExtensions::Translations)
41
+ ActiveRecord::Base.send(:include, ActiveModelExtensions::Validations)
42
+ end
39
43
  end
40
44
  end
@@ -1,3 +1,3 @@
1
1
  require 'coverage/kit'
2
2
 
3
- Coverage::Kit.setup(minimum_coverage: 86.7)
3
+ Coverage::Kit.setup(minimum_coverage: 84.1)
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rails_core_extensions
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.12.0
4
+ version: 0.13.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Michael Noack
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2022-01-25 00:00:00.000000000 Z
12
+ date: 2022-07-04 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: activerecord
@@ -167,8 +167,6 @@ files:
167
167
  - lib/rails_core_extensions/active_record_cloning.rb
168
168
  - lib/rails_core_extensions/active_record_extensions.rb
169
169
  - lib/rails_core_extensions/active_record_liquid_extensions.rb
170
- - lib/rails_core_extensions/active_support_concern.rb
171
- - lib/rails_core_extensions/concurrency.rb
172
170
  - lib/rails_core_extensions/position_initializer.rb
173
171
  - lib/rails_core_extensions/railtie.rb
174
172
  - lib/rails_core_extensions/sortable.rb
@@ -183,7 +181,6 @@ files:
183
181
  - spec/active_model_extensions_spec.rb
184
182
  - spec/active_record_cloning_spec.rb
185
183
  - spec/active_record_extensions_spec.rb
186
- - spec/concurrency_spec.rb
187
184
  - spec/en.yml
188
185
  - spec/position_initializer_spec.rb
189
186
  - spec/schema.rb
@@ -221,7 +218,6 @@ test_files:
221
218
  - spec/active_model_extensions_spec.rb
222
219
  - spec/active_record_cloning_spec.rb
223
220
  - spec/active_record_extensions_spec.rb
224
- - spec/concurrency_spec.rb
225
221
  - spec/en.yml
226
222
  - spec/position_initializer_spec.rb
227
223
  - spec/schema.rb
@@ -1,134 +0,0 @@
1
- module ActiveSupport
2
- # A typical module looks like this:
3
- #
4
- # module M
5
- # def self.included(base)
6
- # base.extend ClassMethods
7
- # base.send(:include, InstanceMethods)
8
- # scope :disabled, where(:disabled => true)
9
- # end
10
- #
11
- # module ClassMethods
12
- # ...
13
- # end
14
- #
15
- # module InstanceMethods
16
- # ...
17
- # end
18
- # end
19
- #
20
- # By using <tt>ActiveSupport::Concern</tt> the above module could instead be written as:
21
- #
22
- # require 'active_support/concern'
23
- #
24
- # module M
25
- # extend ActiveSupport::Concern
26
- #
27
- # included do
28
- # scope :disabled, where(:disabled => true)
29
- # end
30
- #
31
- # module ClassMethods
32
- # ...
33
- # end
34
- #
35
- # module InstanceMethods
36
- # ...
37
- # end
38
- # end
39
- #
40
- # Moreover, it gracefully handles module dependencies. Given a +Foo+ module and a +Bar+
41
- # module which depends on the former, we would typically write the following:
42
- #
43
- # module Foo
44
- # def self.included(base)
45
- # base.class_eval do
46
- # def self.method_injected_by_foo
47
- # ...
48
- # end
49
- # end
50
- # end
51
- # end
52
- #
53
- # module Bar
54
- # def self.included(base)
55
- # base.method_injected_by_foo
56
- # end
57
- # end
58
- #
59
- # class Host
60
- # include Foo # We need to include this dependency for Bar
61
- # include Bar # Bar is the module that Host really needs
62
- # end
63
- #
64
- # But why should +Host+ care about +Bar+'s dependencies, namely +Foo+? We could try to hide
65
- # these from +Host+ directly including +Foo+ in +Bar+:
66
- #
67
- # module Bar
68
- # include Foo
69
- # def self.included(base)
70
- # base.method_injected_by_foo
71
- # end
72
- # end
73
- #
74
- # class Host
75
- # include Bar
76
- # end
77
- #
78
- # Unfortunately this won't work, since when +Foo+ is included, its <tt>base</tt> is the +Bar+ module,
79
- # not the +Host+ class. With <tt>ActiveSupport::Concern</tt>, module dependencies are properly resolved:
80
- #
81
- # require 'active_support/concern'
82
- #
83
- # module Foo
84
- # extend ActiveSupport::Concern
85
- # included do
86
- # class_eval do
87
- # def self.method_injected_by_foo
88
- # ...
89
- # end
90
- # end
91
- # end
92
- # end
93
- #
94
- # module Bar
95
- # extend ActiveSupport::Concern
96
- # include Foo
97
- #
98
- # included do
99
- # self.method_injected_by_foo
100
- # end
101
- # end
102
- #
103
- # class Host
104
- # include Bar # works, Bar takes care now of its dependencies
105
- # end
106
- #
107
- module Concern
108
- def self.extended(base)
109
- base.instance_variable_set("@_dependencies", [])
110
- end
111
-
112
- def append_features(base)
113
- if base.instance_variable_defined?("@_dependencies")
114
- base.instance_variable_get("@_dependencies") << self
115
- return false
116
- else
117
- return false if base < self
118
- @_dependencies.each { |dep| base.send(:include, dep) }
119
- super
120
- base.extend const_get("ClassMethods") if const_defined?("ClassMethods")
121
- base.send :include, const_get("InstanceMethods") if const_defined?("InstanceMethods")
122
- base.class_eval(&@_included_block) if instance_variable_defined?("@_included_block")
123
- end
124
- end
125
-
126
- def included(base = nil, &block)
127
- if base.nil?
128
- @_included_block = block
129
- else
130
- super
131
- end
132
- end
133
- end
134
- end
@@ -1,152 +0,0 @@
1
- module Concurrency
2
- extend ActiveSupport::Concern
3
-
4
- module ClassMethods
5
-
6
- def concurrency_safe(*methods)
7
- options = methods.extract_options!
8
- methods.each do |method|
9
- add_concurrency_check(method, options)
10
- end
11
- end
12
-
13
-
14
- def concurrency_safe_method_locked?(method)
15
- concurrency_cache.read(concurrency_safe_method_cache_name(method)) == 'locked'
16
- end
17
-
18
-
19
- def concurrency_cache
20
- @concurrency_cache ||= ::Rails.cache
21
- end
22
-
23
-
24
- def concurrency_cache=(cache)
25
- [:read,:write,:delete].each do |method|
26
- raise ConcurrencyCacheException, "#{cache} does not implement #{method}" unless cache.respond_to?(method)
27
- end
28
- @concurrency_cache = cache
29
- end
30
-
31
-
32
- private
33
-
34
- def add_concurrency_check(method, options = {})
35
- method_definition = <<-DEFINITION
36
- def #{method}_with_concurrency_lock(*args)
37
- if concurrency_safe_method_locked?(:#{method})
38
- raise ConcurrentCallException.new(self,:#{method}), "#{self.name}.#{method} is already running"
39
- end
40
- lock_concurrency_safe_method(:#{method})
41
- return_value = nil
42
- begin
43
- return_value = #{method}_without_concurrency_lock(*args)
44
- ensure
45
- unlock_concurrency_safe_method(:#{method})
46
- end
47
- return_value
48
- end
49
- alias_method :#{method}_without_concurrency_lock, :#{method}
50
- alias_method :#{method}, :#{method}_with_concurrency_lock
51
- DEFINITION
52
-
53
- if method_type(method, options[:type]) == 'class'
54
- method_definition = <<-DEFINITION
55
- class << self
56
- #{method_definition}
57
- end
58
- DEFINITION
59
- end
60
-
61
- module_eval method_definition
62
- end
63
-
64
-
65
- def lock_concurrency_safe_method(method)
66
- concurrency_cache.write(concurrency_safe_method_cache_name(method), 'locked')
67
- end
68
-
69
-
70
- def unlock_concurrency_safe_method(method)
71
- concurrency_cache.delete(concurrency_safe_method_cache_name(method))
72
- end
73
-
74
-
75
- def concurrency_safe_method_cache_name(method)
76
- "#{self.name.underscore}_concurrency_safe_class_method_#{method}"
77
- end
78
-
79
-
80
- def method_type(method, type = nil)
81
- types = method_types(method, type)
82
- raise AmbiguousMethodException.new(self, method), "#{method} for #{self.name} is ambiguous. Please specify the type (instance/class) option" if types.count == 2
83
- raise NoMethodException.new(self, method), "#{method} is not not a valid method for #{self.name}." if types.blank?
84
- types.first
85
- end
86
-
87
-
88
- def method_types(method, type = nil)
89
- ['class', 'instance'].select do |mt|
90
- (type.blank? || type.to_s == mt) && self.send("#{mt}_method?", method)
91
- end
92
- end
93
-
94
-
95
- def class_method?(method)
96
- self.respond_to?(method, true)
97
- end
98
-
99
-
100
- def instance_method?(method)
101
- (self.instance_methods + self.private_instance_methods).map(&:to_s).include?(method.to_s)
102
- end
103
-
104
- end
105
-
106
-
107
- module InstanceMethods
108
-
109
- def concurrency_cache
110
- self.class.concurrency_cache
111
- end
112
-
113
-
114
- def concurrency_safe_method_locked?(method)
115
- concurrency_cache.read(concurrency_safe_method_cache_name(method)) == 'locked'
116
- end
117
-
118
-
119
- private
120
-
121
- def lock_concurrency_safe_method(method)
122
- concurrency_cache.write(concurrency_safe_method_cache_name(method), 'locked')
123
- end
124
-
125
-
126
- def unlock_concurrency_safe_method(method)
127
- concurrency_cache.delete(concurrency_safe_method_cache_name(method))
128
- end
129
-
130
-
131
- def concurrency_safe_method_cache_name(method)
132
- "#{self.class.name.underscore}_concurrency_safe_instance_method_#{method}"
133
- end
134
-
135
- end
136
-
137
-
138
- class ConcurrencyException < ::Exception; end
139
- class ConcurrencyCacheException < ConcurrencyException; end
140
- class MethodException < ConcurrencyException
141
- attr_reader :object, :method
142
-
143
- def initialize(object, method)
144
- @object = object
145
- @method = method
146
- end
147
- end
148
- class ConcurrentCallException < MethodException; end
149
- class NoMethodException < MethodException; end
150
- class AmbiguousMethodException < MethodException; end
151
-
152
- end
@@ -1,110 +0,0 @@
1
- require 'spec_helper'
2
-
3
- class TestConcurrencyCache
4
- @@cache = {}
5
-
6
- def self.read(key)
7
- @@cache[key]
8
- end
9
-
10
- def self.write(key, value)
11
- @@cache[key] = value
12
- end
13
-
14
- def self.delete(key)
15
- @@cache.delete(key)
16
- end
17
-
18
- def self.clear
19
- @@cache = {}
20
- end
21
- end
22
-
23
- describe Concurrency do
24
- before :each do
25
- TestConcurrencyCache.clear
26
-
27
- class ConcurrencyTest
28
- include Concurrency
29
-
30
- self.concurrency_cache = TestConcurrencyCache
31
-
32
- def self.class_test_method
33
- sleep(1)
34
- end
35
-
36
- def instance_test_method
37
- sleep(1)
38
- end
39
-
40
- def self.both_instance_and_class_test_method; end
41
- def both_instance_and_class_test_method; end
42
- end
43
- end
44
-
45
- after :each do
46
- Object.send(:remove_const, :ConcurrencyTest)
47
- end
48
-
49
- it "should allow specifying which methods should implement the concurrency check" do
50
- expect { ConcurrencyTest.send(:concurrency_safe, :instance_test_method) }
51
- .to_not raise_error
52
- expect { ConcurrencyTest.send(:concurrency_safe, :class_test_method) }
53
- .to_not raise_error
54
- expect { ConcurrencyTest.send(:concurrency_safe, :both_instance_and_class_test_method) }
55
- .to raise_error(Concurrency::AmbiguousMethodException)
56
- expect { ConcurrencyTest.send(:concurrency_safe, :both_instance_and_class_test_method, type: :instance) }
57
- .to_not raise_error
58
- expect { ConcurrencyTest.send(:concurrency_safe, :both_instance_and_class_test_method, type: :class) }
59
- .to_not raise_error
60
- expect { ConcurrencyTest.send(:concurrency_safe, :unknown_method) }
61
- .to raise_error(Concurrency::NoMethodException)
62
- end
63
-
64
- it "should allow identyfying the type of a method" do
65
- expect(ConcurrencyTest.send(:method_types, :class_test_method)).to eq ['class']
66
- expect(ConcurrencyTest.send(:method_types, :instance_test_method)).to eq ['instance']
67
- expect(ConcurrencyTest.send(:method_types, :both_instance_and_class_test_method)).to eq ['class','instance']
68
- expect(ConcurrencyTest.send(:method_types, :unknown_method)).to be_blank
69
- expect(ConcurrencyTest.send(:method_type, :class_test_method)).to eq 'class'
70
- expect(ConcurrencyTest.send(:method_type, :instance_test_method)).to eq 'instance'
71
- expect { ConcurrencyTest.send(:method_type, :both_instance_and_class_test_method) }
72
- .to raise_error(Concurrency::AmbiguousMethodException)
73
- expect { ConcurrencyTest.send(:method_type, :unknown_method) }
74
- .to raise_error(Concurrency::NoMethodException)
75
- end
76
-
77
- it "should allow checking the concurrency lock for specified class methods" do
78
- ConcurrencyTest.send(:concurrency_safe, :class_test_method)
79
- started = false
80
- expect(ConcurrencyTest.concurrency_safe_method_locked?(:class_test_method)).to be false
81
- thread = Thread.new { ConcurrencyTest.send(:class_test_method); started = true }
82
- thread.join
83
- expect(ConcurrencyTest.concurrency_safe_method_locked?(:class_test_method)).to be true until started
84
- end
85
-
86
- it "should allow checking the concurrency lock for specified instance methods" do
87
- ConcurrencyTest.send(:concurrency_safe, :class_test_method)
88
- instance = ConcurrencyTest.new
89
- started = false
90
- expect(instance.concurrency_safe_method_locked?(:instance_test_method)).to be false
91
- thread = Thread.new { instance.send(:instance_test_method); started = true }
92
- thread.join
93
- expect(instance.concurrency_safe_method_locked?(:instance_test_method)).to be true until started
94
- end
95
-
96
- it "should implement the concurrency check for specified class methods" do
97
- ConcurrencyTest.send(:concurrency_safe, :class_test_method)
98
- threads = 2.times.map { Thread.new { ConcurrencyTest.send(:class_test_method) } }
99
- expect { threads.each(&:join) }
100
- .to raise_error(Concurrency::ConcurrentCallException)
101
- end
102
-
103
- it "should implement the concurrency check for specified instance methods" do
104
- ConcurrencyTest.send(:concurrency_safe, :instance_test_method)
105
- instance = ConcurrencyTest.new
106
- threads = 2.times.map { Thread.new { instance.send(:instance_test_method) } }
107
- expect { threads.each(&:join) }
108
- .to raise_error(Concurrency::ConcurrentCallException)
109
- end
110
- end