vident-view_component-caching 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 0c92605001e18a9f49a3ba28db60fc0269bb78f74b3333b2484511dc4d240653
4
+ data.tar.gz: 4dd98bc48794cd45f023fdb71beb4b0e1035a1e4bbcd5c6397256d20bf5e1e95
5
+ SHA512:
6
+ metadata.gz: b619b40a8d2ad65ff8bf906cea5b303353de96cd2c7eeef7087d6de439913629e9127dda7e2e8ccf95cfb488af4dc371bcc2ed57f4646f133ca26349d6f7d6f9
7
+ data.tar.gz: 8a87104ad9b01147cc473dbea7b0e950d66d82be3839a223b6829df48bfe1051ada6ee5b1599901e20c77d520e2c6cdadb4d29a780a95eef9730cbb46e848d22
data/README.md ADDED
@@ -0,0 +1,28 @@
1
+ # Vident::ViewComponent::Caching
2
+ Short description and motivation.
3
+
4
+ ## Usage
5
+ How to use my plugin.
6
+
7
+ ## Installation
8
+ Add this line to your application's Gemfile:
9
+
10
+ ```ruby
11
+ gem "vident-view_component-caching"
12
+ ```
13
+
14
+ And then execute:
15
+ ```bash
16
+ $ bundle
17
+ ```
18
+
19
+ Or install it yourself as:
20
+ ```bash
21
+ $ gem install vident-view_component-caching
22
+ ```
23
+
24
+ ## Contributing
25
+ Contribution directions go here.
26
+
27
+ ## License
28
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
data/Rakefile ADDED
@@ -0,0 +1,3 @@
1
+ require "bundler/setup"
2
+
3
+ require "bundler/gem_tasks"
@@ -0,0 +1,4 @@
1
+ # desc "Explaining what the task does"
2
+ # task :vident_view_component_caching do
3
+ # # Task goes here
4
+ # end
@@ -0,0 +1,8 @@
1
+ module Vident
2
+ module ViewComponent
3
+ module Caching
4
+ class Railtie < ::Rails::Railtie
5
+ end
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,7 @@
1
+ module Vident
2
+ module ViewComponent
3
+ module Caching
4
+ VERSION = "0.1.0"
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,145 @@
1
+ require "vident/view_component/caching/version"
2
+ require "vident/view_component/caching/railtie"
3
+
4
+ module Vident
5
+ module ViewComponent
6
+ # Rails fragment caching works by either expecting the cached key object to respond to `cache_key` or for that object
7
+ # to be an array or hash.
8
+ module Caching
9
+ extend ActiveSupport::Concern
10
+
11
+ class_methods do
12
+ def inherited(subclass)
13
+ subclass.instance_variable_set(
14
+ :@named_cache_key_attributes,
15
+ @named_cache_key_attributes.clone
16
+ )
17
+ super
18
+ end
19
+
20
+ def with_cache_key(*attrs, name: :_collection)
21
+ raise StandardError, "with_cache_key can only be used on components *without* slots as there is no eary way to track their content changes so too risky" if respond_to?(:slots?) && slots?
22
+ # Add view file to cache key
23
+ attrs << :component_modified_time
24
+ named_cache_key_includes(name, *attrs)
25
+ end
26
+
27
+ attr_reader :named_cache_key_attributes
28
+
29
+ # TypedComponents can be used with fragment caching, but you need to be careful! Read on...
30
+ #
31
+ # <% cache component do %>
32
+ # <%= render component %>
33
+ # <% end %>
34
+ #
35
+ # The most important point is that Rails cannot track dependencies on the component itself, so you need to
36
+ # be careful to be explicit on the attributes, and manually specify any sub Viewcomponent dependencies that the
37
+ # component has. The assumption is that the subcomponent takes any attributes from the parent, so the cache key
38
+ # depends on the parent component attributes. Otherwise changes to the parent or sub component views/Ruby class
39
+ # will result in different cache keys too. Of course if you invalidate all cache keys with a modifier on deploy
40
+ # then no need to worry about changing the cache key on component changes, only on attribute/data changes.
41
+ #
42
+ # A big caveat is that the cache key cannot depend on anything related to the view_context of the component (such
43
+ # as `helpers` as the key is created before the rending pipline is invoked (which is when the view_context is set).
44
+ def depends_on(*klasses)
45
+ @component_dependencies ||= []
46
+ @component_dependencies += klasses
47
+ end
48
+
49
+ attr_reader :component_dependencies
50
+
51
+ def component_modified_time
52
+ return @component_modified_time if Rails.env.production? && @component_modified_time
53
+ # FIXME: This could stack overflow if there are circular dependencies
54
+ deps = component_dependencies&.map(&:component_modified_time)&.join("-") || ""
55
+ @component_modified_time = deps + sidecar_view_modified_time + rb_component_modified_time
56
+ end
57
+
58
+ def sidecar_view_modified_time
59
+ return @sidecar_view_modified_time if Rails.env.production? && defined?(@sidecar_view_modified_time)
60
+ @sidecar_view_modified_time = ::File.exist?(template_path) ? ::File.mtime(template_path).to_i.to_s : ""
61
+ end
62
+
63
+ def rb_component_modified_time
64
+ return @rb_component_modified_time if Rails.env.production? && defined?(@rb_component_modified_time)
65
+ @rb_component_modified_time = ::File.exist?(component_path) ? ::File.mtime(component_path).to_i.to_s : ""
66
+ end
67
+
68
+ def template_path
69
+ File.join components_base_path, "#{virtual_path}.html.erb"
70
+ end
71
+
72
+ def component_path
73
+ File.join components_base_path, "#{virtual_path}.rb"
74
+ end
75
+
76
+ def components_base_path
77
+ ::Rails.configuration.view_component.view_component_path || "app/components"
78
+ end
79
+
80
+ private
81
+
82
+ def named_cache_key_includes(name, *attrs)
83
+ define_cache_key_method unless @named_cache_key_attributes
84
+ @named_cache_key_attributes ||= {}
85
+ @named_cache_key_attributes[name] = attrs
86
+ end
87
+
88
+ def define_cache_key_method
89
+ # If the presenter defines cache key setup then define the method. Otherwise Rails assumes this
90
+ # will return a valid key if the class will respond to this
91
+ define_method :cache_key do |n = :_collection|
92
+ if defined?(@cache_key)
93
+ return @cache_key[n] if @cache_key.key?(n)
94
+ else
95
+ @cache_key ||= {}
96
+ end
97
+ generate_cache_key(n)
98
+ @cache_key[n]
99
+ end
100
+ end
101
+ end
102
+
103
+ # Component modified time which is combined with other cache key attributes to generate cache key for an instance
104
+ def component_modified_time
105
+ self.class.component_modified_time
106
+ end
107
+
108
+ def cacheable?
109
+ respond_to? :cache_key
110
+ end
111
+
112
+ def cache_key_modifier
113
+ ENV["RAILS_CACHE_ID"]
114
+ end
115
+
116
+ def cache_keys_for_sources(key_attributes)
117
+ sources = key_attributes.flat_map { |n| n.is_a?(Proc) ? instance_eval(&n) : send(n) }
118
+ sources.compact.map do |item|
119
+ next if item == self
120
+ generate_item_cache_key_from(item)
121
+ end
122
+ end
123
+
124
+ def generate_item_cache_key_from(item)
125
+ if item.respond_to? :cache_key_with_version
126
+ item.cache_key_with_version
127
+ elsif item.respond_to? :cache_key
128
+ item.cache_key
129
+ elsif item.is_a?(String)
130
+ Digest::SHA1.hexdigest(item)
131
+ else
132
+ Digest::SHA1.hexdigest(Marshal.dump(item))
133
+ end
134
+ end
135
+
136
+ def generate_cache_key(index)
137
+ key_attributes = self.class.named_cache_key_attributes[index]
138
+ return nil unless key_attributes
139
+ key = "#{self.class.name}/#{cache_keys_for_sources(key_attributes).join("/")}"
140
+ raise StandardError, "Cache key for key #{key} is blank!" if key.blank?
141
+ @cache_key[index] = cache_key_modifier.present? ? "#{key}/#{cache_key_modifier}" : key
142
+ end
143
+ end
144
+ end
145
+ end
metadata ADDED
@@ -0,0 +1,92 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: vident-view_component-caching
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Stephen Ierodiaconou
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2023-04-02 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rails
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '7'
20
+ - - "<"
21
+ - !ruby/object:Gem::Version
22
+ version: '8'
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ version: '7'
30
+ - - "<"
31
+ - !ruby/object:Gem::Version
32
+ version: '8'
33
+ - !ruby/object:Gem::Dependency
34
+ name: vident-view_component
35
+ requirement: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - ">="
38
+ - !ruby/object:Gem::Version
39
+ version: 0.1.0
40
+ - - "<"
41
+ - !ruby/object:Gem::Version
42
+ version: '1'
43
+ type: :runtime
44
+ prerelease: false
45
+ version_requirements: !ruby/object:Gem::Requirement
46
+ requirements:
47
+ - - ">="
48
+ - !ruby/object:Gem::Version
49
+ version: 0.1.0
50
+ - - "<"
51
+ - !ruby/object:Gem::Version
52
+ version: '1'
53
+ description: Cache key computation for Vident components with ViewComponent
54
+ email:
55
+ - stevegeek@gmail.com
56
+ executables: []
57
+ extensions: []
58
+ extra_rdoc_files: []
59
+ files:
60
+ - README.md
61
+ - Rakefile
62
+ - lib/tasks/vident/view_component/caching_tasks.rake
63
+ - lib/vident/view_component/caching.rb
64
+ - lib/vident/view_component/caching/railtie.rb
65
+ - lib/vident/view_component/caching/version.rb
66
+ homepage: https://github.com/stevegeek/vident-view_component-caching
67
+ licenses:
68
+ - MIT
69
+ metadata:
70
+ homepage_uri: https://github.com/stevegeek/vident-view_component-caching
71
+ source_code_uri: https://github.com/stevegeek/vident-view_component-caching
72
+ changelog_uri: https://github.com/stevegeek/vident-view_component-caching/blob/main/CHANGELOG.md
73
+ post_install_message:
74
+ rdoc_options: []
75
+ require_paths:
76
+ - lib
77
+ required_ruby_version: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - ">="
80
+ - !ruby/object:Gem::Version
81
+ version: '0'
82
+ required_rubygems_version: !ruby/object:Gem::Requirement
83
+ requirements:
84
+ - - ">="
85
+ - !ruby/object:Gem::Version
86
+ version: '0'
87
+ requirements: []
88
+ rubygems_version: 3.4.6
89
+ signing_key:
90
+ specification_version: 4
91
+ summary: Cache key computation for Vident components with ViewComponent
92
+ test_files: []