para 0.12.8 → 0.12.9
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 +4 -4
- data/lib/para/components_configuration.rb +100 -1
- data/lib/para/config.rb +9 -0
- data/lib/para/engine.rb +4 -0
- data/lib/para/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: ebd0ada08791d045fb7437af457ce37ea4d61ffe47d6e809786ebf6ef6c6dff6
|
|
4
|
+
data.tar.gz: ee5e91c50160e3ce4d838f0c530a3917dedff1339cc16d38b64adef87f108eb1
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 30e5d1f8554038eebcc28d3deba64e4ec7677106b760f2e79692b8e01752c5ecbbe9008283ba79335a3229a1415c84dbe4bcc81144272be8d6fc007090e721f8
|
|
7
|
+
data.tar.gz: 2d21b1015f554e2b4c534c871996b334b1bbecf97b074bf4ece24313b77df97533236b56bcc2204509753a7612b0870858a28d519a4df62cd73f59459eca7496
|
|
@@ -3,6 +3,25 @@ module Para
|
|
|
3
3
|
class UndefinedComponentTypeError < StandardError; end
|
|
4
4
|
class ComponentTooDeepError < StandardError; end
|
|
5
5
|
|
|
6
|
+
# Errors that signal the cached component state went stale, usually after a
|
|
7
|
+
# schema migration, a database reset or when a component class was unloaded
|
|
8
|
+
# by the code reloader. When one of these is raised while resolving a
|
|
9
|
+
# component, we reset the caches (and optionally reload the tree) and retry
|
|
10
|
+
# instead of letting it bubble up and break rails commands or the server.
|
|
11
|
+
#
|
|
12
|
+
RELOADABLE_ERRORS = [
|
|
13
|
+
ActiveRecord::RecordNotFound,
|
|
14
|
+
ActiveRecord::StatementInvalid,
|
|
15
|
+
ActiveRecord::SubclassNotFound,
|
|
16
|
+
ActiveModel::MissingAttributeError,
|
|
17
|
+
NameError
|
|
18
|
+
].freeze
|
|
19
|
+
|
|
20
|
+
# Path to the app's `config/components.rb`, set by the engine. Used to
|
|
21
|
+
# rebuild the components tree when auto-reloading after a stale lookup.
|
|
22
|
+
#
|
|
23
|
+
attr_accessor :components_config_path
|
|
24
|
+
|
|
6
25
|
def draw(&block)
|
|
7
26
|
return unless components_installed?
|
|
8
27
|
|
|
@@ -10,6 +29,11 @@ module Para
|
|
|
10
29
|
log_level = Rails.logger.level
|
|
11
30
|
Rails.logger.level = :fatal
|
|
12
31
|
|
|
32
|
+
# Reset any previously drawn definitions so re-drawing (e.g. on reload)
|
|
33
|
+
# rebuilds a clean tree instead of appending duplicates.
|
|
34
|
+
@sections = []
|
|
35
|
+
reset!
|
|
36
|
+
|
|
13
37
|
eager_load_components!
|
|
14
38
|
instance_eval(&block)
|
|
15
39
|
build
|
|
@@ -25,13 +49,45 @@ module Para
|
|
|
25
49
|
end
|
|
26
50
|
|
|
27
51
|
def method_missing(method, *args, &block)
|
|
28
|
-
if (component =
|
|
52
|
+
if (component = resolve_component(method))
|
|
29
53
|
component.tap(&ActiveDecorator::Decorator.instance.method(:decorate))
|
|
30
54
|
else
|
|
31
55
|
super
|
|
32
56
|
end
|
|
33
57
|
end
|
|
34
58
|
|
|
59
|
+
def respond_to_missing?(method, include_private = false)
|
|
60
|
+
# Answer respond_to? from the current state only: never trigger a reload
|
|
61
|
+
# just to probe whether a component exists.
|
|
62
|
+
!resolve_component(method, reload: false).nil? || super
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
# Clears the memoized identifier -> database id maps and the per-request
|
|
66
|
+
# resolved instance caches, so the next lookup rebuilds against fresh data.
|
|
67
|
+
# Keeps the in-memory section/component definitions (pure Ruby, schema
|
|
68
|
+
# independent) untouched.
|
|
69
|
+
#
|
|
70
|
+
def reset!
|
|
71
|
+
@sections_ids_hash = nil
|
|
72
|
+
@components_ids_hash = nil
|
|
73
|
+
RequestStore.store[:components_cache] = nil
|
|
74
|
+
RequestStore.store[:sections_cache] = nil
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
# Re-runs the app's `config/components.rb` to rebuild the whole components
|
|
78
|
+
# tree from scratch. Returns true on success, false if the file is missing
|
|
79
|
+
# or the reload itself fails (e.g. schema still mid-migration).
|
|
80
|
+
#
|
|
81
|
+
def reload!
|
|
82
|
+
path = components_config_path
|
|
83
|
+
return false unless path && File.exist?(path.to_s)
|
|
84
|
+
|
|
85
|
+
load(path.to_s)
|
|
86
|
+
true
|
|
87
|
+
rescue *RELOADABLE_ERRORS
|
|
88
|
+
false
|
|
89
|
+
end
|
|
90
|
+
|
|
35
91
|
def section_for(identifier)
|
|
36
92
|
if (section = sections_cache[identifier])
|
|
37
93
|
section
|
|
@@ -44,6 +100,34 @@ module Para
|
|
|
44
100
|
end
|
|
45
101
|
end
|
|
46
102
|
|
|
103
|
+
# Resolves a component by identifier while healing stale caches. It covers
|
|
104
|
+
# both failure modes seen after a schema migration or a code reload:
|
|
105
|
+
#
|
|
106
|
+
# * `component_for` raises a RELOADABLE_ERROR (stale id, missing column,
|
|
107
|
+
# unloaded STI subclass) ;
|
|
108
|
+
# * `component_for` returns nil because the ids hash is empty/stale, which
|
|
109
|
+
# would otherwise surface as `undefined method 'xxx'` from method_missing.
|
|
110
|
+
#
|
|
111
|
+
# On the first failure it resets the caches and -- in auto-reload mode --
|
|
112
|
+
# rebuilds the tree from config/components.rb, then retries once. If the
|
|
113
|
+
# component still can't be found it returns nil, letting method_missing
|
|
114
|
+
# raise the usual NoMethodError for genuinely unknown components.
|
|
115
|
+
#
|
|
116
|
+
def resolve_component(identifier, reload: true, retried: false)
|
|
117
|
+
component = component_for(identifier)
|
|
118
|
+
return component if component
|
|
119
|
+
return nil if retried || !reload
|
|
120
|
+
|
|
121
|
+
heal_components_cache!
|
|
122
|
+
resolve_component(identifier, reload: reload, retried: true)
|
|
123
|
+
rescue *RELOADABLE_ERRORS => error
|
|
124
|
+
return nil if retried || !reload
|
|
125
|
+
|
|
126
|
+
log_components_failure(error)
|
|
127
|
+
heal_components_cache!
|
|
128
|
+
resolve_component(identifier, reload: reload, retried: true)
|
|
129
|
+
end
|
|
130
|
+
|
|
47
131
|
def component_for(identifier)
|
|
48
132
|
if (component = components_cache[identifier])
|
|
49
133
|
component
|
|
@@ -83,6 +167,21 @@ module Para
|
|
|
83
167
|
|
|
84
168
|
private
|
|
85
169
|
|
|
170
|
+
# Drops the stale caches and, when auto-reload is enabled, rebuilds the
|
|
171
|
+
# whole components tree before the lookup is retried.
|
|
172
|
+
#
|
|
173
|
+
def heal_components_cache!
|
|
174
|
+
reset!
|
|
175
|
+
reload! if Para.config.components_auto_reload
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
def log_components_failure(error)
|
|
179
|
+
Rails.logger.warn(
|
|
180
|
+
"Para components lookup failed (#{error.class}: #{error.message}).\n" \
|
|
181
|
+
'Resetting the components cache and retrying.'
|
|
182
|
+
)
|
|
183
|
+
end
|
|
184
|
+
|
|
86
185
|
def build
|
|
87
186
|
sections.each_with_index do |section, index|
|
|
88
187
|
section.refresh(position: index)
|
data/lib/para/config.rb
CHANGED
|
@@ -25,6 +25,15 @@ module Para
|
|
|
25
25
|
mattr_accessor :components_directory
|
|
26
26
|
@@para_components_directory = 'components'
|
|
27
27
|
|
|
28
|
+
# When a `Para.components.xxx` lookup hits a stale cache (after a schema
|
|
29
|
+
# migration, a database reset or a code reload), Para resets its caches and
|
|
30
|
+
# -- with auto-reload enabled -- re-runs `config/components.rb` to rebuild
|
|
31
|
+
# the whole tree before retrying, so the lookup recovers transparently
|
|
32
|
+
# instead of raising. Enabled by default; set to false to opt out.
|
|
33
|
+
#
|
|
34
|
+
mattr_accessor :components_auto_reload
|
|
35
|
+
@@components_auto_reload = true
|
|
36
|
+
|
|
28
37
|
mattr_reader :plugins
|
|
29
38
|
@@plugins = Para::Plugins::Set.new
|
|
30
39
|
|
data/lib/para/engine.rb
CHANGED
|
@@ -63,6 +63,10 @@ module Para
|
|
|
63
63
|
initializer 'Build components tree' do |app|
|
|
64
64
|
components_config_path = Rails.root.join('config', 'components.rb')
|
|
65
65
|
|
|
66
|
+
# Remember the path so the components configuration can rebuild the tree
|
|
67
|
+
# by itself when auto-reloading after a stale lookup.
|
|
68
|
+
Para::Component.config.components_config_path = components_config_path
|
|
69
|
+
|
|
66
70
|
app.config.to_prepare do
|
|
67
71
|
require components_config_path if File.exist?(components_config_path)
|
|
68
72
|
end
|
data/lib/para/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: para
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.12.
|
|
4
|
+
version: 0.12.9
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Valentin Ballestrino
|
|
@@ -790,7 +790,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
790
790
|
- !ruby/object:Gem::Version
|
|
791
791
|
version: '0'
|
|
792
792
|
requirements: []
|
|
793
|
-
rubygems_version:
|
|
793
|
+
rubygems_version: 4.0.12
|
|
794
794
|
specification_version: 4
|
|
795
795
|
summary: Rails admin engine
|
|
796
796
|
test_files: []
|