vident 0.7.0 → 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG.md DELETED
@@ -1,79 +0,0 @@
1
-
2
- # Change Log
3
- All notable changes to this project will be documented in this file.
4
-
5
- The format is based on [Keep a Changelog](http://keepachangelog.com/)
6
- and this project adheres to [Semantic Versioning](http://semver.org/).
7
-
8
- ## [Unreleased]
9
-
10
- ### Added
11
-
12
- ### Changed
13
-
14
- ### Fixed
15
-
16
- ## [0.7.0] - 2023-03-08
17
-
18
- ### Added
19
-
20
- - new `Vident::Tailwind` module which uses [tailwind_merge](https://github.com/gjtorikian/tailwind_merge) to merge TailwindCSS classes
21
-
22
- ### Changed
23
-
24
- - Removed a dependency on intenal constants from `phlex`
25
-
26
- ## [0.6.3] - 2023-03-03
27
-
28
- ### Fixed
29
-
30
- - Fix for changes to HTML tag collection in Phlex
31
-
32
-
33
- ## [0.6.2] - 2023-02-23
34
-
35
- ### Fixed
36
-
37
- - Element tag options are not set when no ID is provided
38
-
39
-
40
- ## [0.6.1] - 2023-02-20
41
-
42
- ### Fixed
43
-
44
- - `better_html` support fix for aliased dsl methods
45
-
46
-
47
- ## [0.6.0] - 2023-02-20
48
-
49
- ### Added
50
-
51
- - Experimental support for `better_html` in the root components (the stimulus attributes are generated with `html_attributes`)
52
-
53
-
54
-
55
- ## [0.5.1] - 2023-02-17
56
-
57
- ### Added
58
-
59
- - N/A
60
-
61
- ### Changed
62
-
63
- - N/A
64
-
65
- ### Fixed
66
-
67
- - Typed attributes was not always using custom coercion methods if they were defined
68
-
69
- ### Removed
70
-
71
- - N/A
72
-
73
- ### Deprecated
74
-
75
- - N/A
76
-
77
- ### Security
78
-
79
- - N/A
data/CODE_OF_CONDUCT.md DELETED
@@ -1,84 +0,0 @@
1
- # Contributor Covenant Code of Conduct
2
-
3
- ## Our Pledge
4
-
5
- We as members, contributors, and leaders pledge to make participation in our community a harassment-free experience for everyone, regardless of age, body size, visible or invisible disability, ethnicity, sex characteristics, gender identity and expression, level of experience, education, socio-economic status, nationality, personal appearance, race, religion, or sexual identity and orientation.
6
-
7
- We pledge to act and interact in ways that contribute to an open, welcoming, diverse, inclusive, and healthy community.
8
-
9
- ## Our Standards
10
-
11
- Examples of behavior that contributes to a positive environment for our community include:
12
-
13
- * Demonstrating empathy and kindness toward other people
14
- * Being respectful of differing opinions, viewpoints, and experiences
15
- * Giving and gracefully accepting constructive feedback
16
- * Accepting responsibility and apologizing to those affected by our mistakes, and learning from the experience
17
- * Focusing on what is best not just for us as individuals, but for the overall community
18
-
19
- Examples of unacceptable behavior include:
20
-
21
- * The use of sexualized language or imagery, and sexual attention or
22
- advances of any kind
23
- * Trolling, insulting or derogatory comments, and personal or political attacks
24
- * Public or private harassment
25
- * Publishing others' private information, such as a physical or email
26
- address, without their explicit permission
27
- * Other conduct which could reasonably be considered inappropriate in a
28
- professional setting
29
-
30
- ## Enforcement Responsibilities
31
-
32
- Community leaders are responsible for clarifying and enforcing our standards of acceptable behavior and will take appropriate and fair corrective action in response to any behavior that they deem inappropriate, threatening, offensive, or harmful.
33
-
34
- Community leaders have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, and will communicate reasons for moderation decisions when appropriate.
35
-
36
- ## Scope
37
-
38
- This Code of Conduct applies within all community spaces, and also applies when an individual is officially representing the community in public spaces. Examples of representing our community include using an official e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event.
39
-
40
- ## Enforcement
41
-
42
- Instances of abusive, harassing, or otherwise unacceptable behavior may be reported to the community leaders responsible for enforcement at stevegeek@gmail.com. All complaints will be reviewed and investigated promptly and fairly.
43
-
44
- All community leaders are obligated to respect the privacy and security of the reporter of any incident.
45
-
46
- ## Enforcement Guidelines
47
-
48
- Community leaders will follow these Community Impact Guidelines in determining the consequences for any action they deem in violation of this Code of Conduct:
49
-
50
- ### 1. Correction
51
-
52
- **Community Impact**: Use of inappropriate language or other behavior deemed unprofessional or unwelcome in the community.
53
-
54
- **Consequence**: A private, written warning from community leaders, providing clarity around the nature of the violation and an explanation of why the behavior was inappropriate. A public apology may be requested.
55
-
56
- ### 2. Warning
57
-
58
- **Community Impact**: A violation through a single incident or series of actions.
59
-
60
- **Consequence**: A warning with consequences for continued behavior. No interaction with the people involved, including unsolicited interaction with those enforcing the Code of Conduct, for a specified period of time. This includes avoiding interactions in community spaces as well as external channels like social media. Violating these terms may lead to a temporary or permanent ban.
61
-
62
- ### 3. Temporary Ban
63
-
64
- **Community Impact**: A serious violation of community standards, including sustained inappropriate behavior.
65
-
66
- **Consequence**: A temporary ban from any sort of interaction or public communication with the community for a specified period of time. No public or private interaction with the people involved, including unsolicited interaction with those enforcing the Code of Conduct, is allowed during this period. Violating these terms may lead to a permanent ban.
67
-
68
- ### 4. Permanent Ban
69
-
70
- **Community Impact**: Demonstrating a pattern of violation of community standards, including sustained inappropriate behavior, harassment of an individual, or aggression toward or disparagement of classes of individuals.
71
-
72
- **Consequence**: A permanent ban from any sort of public interaction within the community.
73
-
74
- ## Attribution
75
-
76
- This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 2.0,
77
- available at https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.
78
-
79
- Community Impact Guidelines were inspired by [Mozilla's code of conduct enforcement ladder](https://github.com/mozilla/diversity).
80
-
81
- [homepage]: https://www.contributor-covenant.org
82
-
83
- For answers to common questions about this code of conduct, see the FAQ at
84
- https://www.contributor-covenant.org/faq. Translations are available at https://www.contributor-covenant.org/translations.
data/Gemfile DELETED
@@ -1,35 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- source "https://rubygems.org"
4
-
5
- # Specify your gem's dependencies in vident.gemspec
6
- gemspec
7
-
8
- gem "puma"
9
-
10
- gem "rails", ">= 7"
11
- # TODO: move examples to another app?
12
- gem "sprockets-rails"
13
- gem "tailwindcss-rails"
14
- gem "turbo-rails"
15
- gem "importmap-rails"
16
- gem "stimulus-rails"
17
-
18
- gem "dry-struct"
19
-
20
- gem "phlex-rails"
21
- gem "better_html"
22
- gem "tailwind_merge"
23
-
24
- # FIXME: versions greater than 2.74 cause issues: https://github.com/ViewComponent/view_component/pull/1571
25
- gem "view_component", "2.74.1"
26
-
27
- gem "sqlite3"
28
-
29
- gem "rake", "~> 13.0"
30
-
31
- gem "minitest", "~> 5.0"
32
- gem "minitest-hooks"
33
- gem "faker"
34
-
35
- gem "standard", "~> 1.3"
data/LICENSE.txt DELETED
@@ -1,21 +0,0 @@
1
- The MIT License (MIT)
2
-
3
- Copyright (c) 2022 Stephen Ierodiaconou
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
11
-
12
- The above copyright notice and this permission notice shall be included in
13
- all copies or substantial portions of the Software.
14
-
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
- THE SOFTWARE.
data/examples/avatar.png DELETED
Binary file
data/examples/ex1.gif DELETED
Binary file
@@ -1,37 +0,0 @@
1
- require "stimulus/manifest"
2
-
3
- namespace :vident do
4
- task :stimulus_controller_imports do
5
- paths = {
6
- "app/components" => "../../../app/components",
7
- "app/views" => "../../../app/views",
8
- "app/javascript/controllers" => "."
9
- }
10
- manifests = []
11
- paths.each do |controllers_path, import_path|
12
- vc_controllers_path = Rails.root.join(controllers_path)
13
- manifests << Stimulus::Manifest.extract_controllers_from(vc_controllers_path).collect do |controller_path|
14
- controller_path = controller_path.relative_path_from(vc_controllers_path).to_s
15
- module_path = controller_path.split(".").first
16
- controller_class_name = module_path.camelize.gsub(/::/, "__")
17
- tag_name = module_path.remove(/_controller/).tr("_", "-").gsub(/\//, "--")
18
-
19
- <<~JS
20
- import #{controller_class_name} from "#{import_path}/#{controller_path.gsub(".ts", "")}"
21
- application.register("#{tag_name}", #{controller_class_name});
22
- JS
23
- end
24
- end
25
-
26
- File.open(Rails.root.join("app/javascript/controllers/index.js"), "w+") do |index|
27
- index.puts "// This file is auto-generated by ./bin/rails stimulus_controller_imports"
28
- index.puts "// Run that command whenever you add a new controller or create them with"
29
- index.puts "// ./bin/rails generate stimulus controllerName"
30
- index.puts
31
- index.puts %(import { application } from "./application")
32
- manifests.each do |manifest|
33
- index.puts manifest
34
- end
35
- end
36
- end
37
- end
@@ -1,229 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "active_support/concern"
4
-
5
- if Gem.loaded_specs.has_key? "dry-struct"
6
- require_relative "./types"
7
- require_relative "./typed_niling_struct"
8
-
9
- module Vident
10
- # Adapts Dry Types to confinus Typed Attributes. We use dry-struct (see TypedNilingStruct) but
11
- # we could probably also use dry-initializer directly, saving us from maintaining the schema.
12
- module Attributes
13
- module Typed
14
- extend ActiveSupport::Concern
15
-
16
- # TODO: better handling of when either class.schema is undefined (as no attributes configured) or when
17
- # other methods ar called before prepare_attributes is called
18
- def prepare_attributes(attributes)
19
- @__attributes = self.class.schema.new(**attributes)
20
- end
21
-
22
- def attributes
23
- @__attributes.attributes
24
- end
25
-
26
- def attribute_names
27
- @attribute_names ||= self.class.attribute_names
28
- end
29
-
30
- def attribute(key)
31
- if Rails.env.development? && !key?(key)
32
- raise StandardError, "Attribute #{key} not found in #{self.class.name}"
33
- end
34
- @__attributes.attributes[key]
35
- end
36
- alias_method :[], :attribute
37
-
38
- def key?(key)
39
- self.class.schema.attribute_names.include?(key)
40
- end
41
-
42
- def to_hash
43
- @__attributes.to_h
44
- end
45
-
46
- class_methods do
47
- def inherited(subclass)
48
- subclass.instance_variable_set(:@schema, @schema.clone)
49
- subclass.instance_variable_set(:@attribute_ivar_names, @attribute_ivar_names.clone)
50
- super
51
- end
52
-
53
- def attribute_names
54
- schema.attribute_names
55
- end
56
-
57
- def attribute_metadata(key)
58
- schema.schema.key(key).meta
59
- end
60
-
61
- attr_reader :schema, :attribute_ivar_names
62
-
63
- def attribute(name, signature = :any, **options, &converter)
64
- strict = !options[:convert]
65
- signatures = extract_member_type_and_subclass(signature, options)
66
- type_info = map_primitive_to_dry_type(signatures, strict, converter)
67
- type_info = set_constraints(type_info, options)
68
- type_info = set_metadata(type_info, signatures, options)
69
- define_on_schema(name, type_info, options)
70
- end
71
-
72
- private
73
-
74
- def set_constraints(type_info, options)
75
- if allows_nil?(options)
76
- type_info = type_info.optional.meta(required: false)
77
- end
78
- unless allows_blank?(options)
79
- type_info = type_info.constrained(filled: true)
80
- end
81
- if options[:default]&.is_a?(Proc)
82
- type_info = type_info.default(options[:default].freeze)
83
- elsif !options[:default].nil?
84
- type_info = type_info.default(->(_) { options[:default] }.freeze)
85
- end
86
- if options[:in]
87
- type_info.constrained(included_in: options[:in].freeze)
88
- end
89
- type_info
90
- end
91
-
92
- def set_metadata(type_info, signatures, options)
93
- metadata = {typed_attribute_type: signatures, typed_attribute_options: options}
94
- type_info.meta(**metadata)
95
- end
96
-
97
- def delegates?(options)
98
- options[:delegates] != false
99
- end
100
-
101
- def define_on_schema(attribute_name, type_info, options)
102
- @attribute_ivar_names ||= {}
103
- @attribute_ivar_names[attribute_name] = :"@#{attribute_name}"
104
- define_attribute_delegate(attribute_name) if delegates?(options)
105
- @schema ||= const_set(:TypedSchema, Class.new(Vident::Attributes::TypedNilingStruct))
106
- @schema.attribute attribute_name, type_info
107
- end
108
-
109
- def define_attribute_delegate(attr_name)
110
- # Define reader & presence check method
111
- class_eval(<<-RUBY, __FILE__, __LINE__ + 1)
112
- def #{attr_name}
113
- @__attributes.attributes[:#{attr_name}]
114
- end
115
-
116
- def #{attr_name}?
117
- send(:#{attr_name}).present?
118
- end
119
- RUBY
120
- end
121
-
122
- def allows_nil?(options)
123
- return true unless options
124
- allow_nil = options[:allow_nil]
125
- return false if allow_nil == false
126
- allow_nil || allows_blank?(options)
127
- end
128
-
129
- def allows_blank?(options)
130
- return true unless options
131
- allow_blank = options[:allow_blank]
132
- allow_blank.nil? ? true : allow_blank
133
- end
134
-
135
- def map_primitive_to_dry_type(signatures, strict, converter)
136
- types = signatures.map do |type, subtype|
137
- dry_type = dry_type_from_primary_type(type, strict, converter)
138
- if subtype && dry_type.respond_to?(:of)
139
- subtype_info = dry_type_from_primary_type(subtype, strict, converter)
140
- # Sub types of collections currently can be nil - this should be an option
141
- dry_type.of(subtype_info.optional.meta(required: false))
142
- else
143
- dry_type
144
- end
145
- end
146
- types.reduce(:|)
147
- end
148
-
149
- def extract_member_type_and_subclass(signature, options)
150
- case signature
151
- when Set
152
- signature.flat_map { |s| extract_member_type_and_subclass(s, options) }
153
- when Array
154
- [[Array, signature.first]]
155
- else
156
- [[signature, options[:type] || options[:sub_type]]]
157
- end
158
- end
159
-
160
- def dry_type_from_primary_type(type, strict, converter)
161
- # If a converter is provided, we should use it to coerce the value
162
- if converter && !strict && !type.is_a?(Symbol)
163
- return Types.Constructor(type) do |value|
164
- next value if value.is_a?(type)
165
-
166
- converter.call(value).tap do |new_value|
167
- unless new_value.is_a?(type)
168
- raise ArgumentError, "Type conversion proc did not convert #{value} to #{type}"
169
- end
170
- end
171
- end
172
- end
173
-
174
- if type == :any
175
- Types::Nominal::Any
176
- elsif type == Integer
177
- strict ? Types::Strict::Integer : Types::Params::Integer
178
- elsif type == BigDecimal
179
- strict ? Types::Strict::Decimal : Types::Params::Decimal
180
- elsif type == Float
181
- strict ? Types::Strict::Float : Types::Params::Float
182
- elsif type == Numeric
183
- if strict
184
- Types::Strict::Float | Types::Strict::Integer | Types::Strict::Decimal
185
- else
186
- Types::Params::Float | Types::Params::Integer | Types::Params::Decimal
187
- end
188
- elsif type == Symbol
189
- strict ? Types::Strict::Symbol : Types::Coercible::Symbol
190
- elsif type == String
191
- strict ? Types::Strict::String : Types::Coercible::String
192
- elsif type == Time
193
- strict ? Types::Strict::Time : Types::Params::Time
194
- elsif type == Date
195
- strict ? Types::Strict::Date : Types::Params::Date
196
- elsif type == Array
197
- strict ? Types::Strict::Array : Types::Params::Array
198
- elsif type == Hash
199
- strict ? Types::Strict::Hash : Types::Coercible::Hash
200
- elsif type == :boolean
201
- strict ? Types::Strict::Bool : Types::Params::Bool
202
- elsif strict
203
- # when strict create a Nominal type with a is_a? constraint, otherwise create a Nominal type which constructs
204
- # values using the default constructor, `new`.
205
- Types.Instance(type)
206
- else
207
- # dry calls this when initialising the Type. Check if type of input is correct or create new instance
208
- Types.Constructor(type) do |value|
209
- next value if value.is_a?(type)
210
-
211
- type.new(**value)
212
- end
213
- end
214
- end
215
- end
216
- end
217
- end
218
- end
219
- else
220
- module Vident
221
- module Attributes
222
- module Typed
223
- def self.included(base)
224
- raise "Vident::Attributes::Typed requires dry-struct to be installed"
225
- end
226
- end
227
- end
228
- end
229
- end
@@ -1,27 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Vident
4
- module Attributes
5
- # A dry struct that is loose about keys provided on initialization. It sets them to nil if not provided.
6
- # It is strict about types but not about provided keys
7
- class TypedNilingStruct < ::Dry::Struct
8
- # convert string keys to symbols
9
- transform_keys(&:to_sym)
10
-
11
- # resolve default types on nil
12
- transform_types do |type|
13
- if type.default?
14
- type.constructor { |value| value.nil? ? ::Dry::Types::Undefined : value }
15
- else
16
- type
17
- end
18
- end
19
-
20
- class << self
21
- def check_schema_duplication(new_keys)
22
- # allow overriding keys
23
- end
24
- end
25
- end
26
- end
27
- end
@@ -1,16 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "dry-struct"
4
-
5
- module Vident
6
- module Attributes
7
- module Types
8
- include ::Dry.Types
9
-
10
- StrippedString = Types::String.constructor(&:strip)
11
- BooleanDefaultFalse = Types::Bool.default(false)
12
- BooleanDefaultTrue = Types::Bool.default(true)
13
- HashDefaultEmpty = Types::Hash.default({}.freeze)
14
- end
15
- end
16
- end
@@ -1,144 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # Rails fragment caching works by either expecting the cached key object to respond to `cache_key` or for that object
4
- # to be an array or hash.
5
- module Vident
6
- module Caching
7
- module CacheKey
8
- extend ActiveSupport::Concern
9
-
10
- class_methods do
11
- def inherited(subclass)
12
- subclass.instance_variable_set(
13
- :@named_cache_key_attributes,
14
- @named_cache_key_attributes.clone
15
- )
16
- super
17
- end
18
-
19
- def with_cache_key(*attrs, name: :_collection)
20
- 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?
21
- # Add view file to cache key
22
- attrs << :component_modified_time
23
- named_cache_key_includes(name, *attrs)
24
- end
25
-
26
- attr_reader :named_cache_key_attributes
27
-
28
- # TypedComponents can be used with fragment caching, but you need to be careful! Read on...
29
- #
30
- # <% cache component do %>
31
- # <%= render component %>
32
- # <% end %>
33
- #
34
- # The most important point is that Rails cannot track dependencies on the component itself, so you need to
35
- # be careful to be explicit on the attributes, and manually specify any sub Viewcomponent dependencies that the
36
- # component has. The assumption is that the subcomponent takes any attributes from the parent, so the cache key
37
- # depends on the parent component attributes. Otherwise changes to the parent or sub component views/Ruby class
38
- # will result in different cache keys too. Of course if you invalidate all cache keys with a modifier on deploy
39
- # then no need to worry about changing the cache key on component changes, only on attribute/data changes.
40
- #
41
- # A big caveat is that the cache key cannot depend on anything related to the view_context of the component (such
42
- # as `helpers` as the key is created before the rending pipline is invoked (which is when the view_context is set).
43
- def depends_on(*klasses)
44
- @component_dependencies ||= []
45
- @component_dependencies += klasses
46
- end
47
-
48
- attr_reader :component_dependencies
49
-
50
- def component_modified_time
51
- return @component_modified_time if Rails.env.production? && @component_modified_time
52
- # FIXME: This could stack overflow if there are circular dependencies
53
- deps = component_dependencies&.map(&:component_modified_time)&.join("-") || ""
54
- @component_modified_time = deps + sidecar_view_modified_time + rb_component_modified_time
55
- end
56
-
57
- def sidecar_view_modified_time
58
- return @sidecar_view_modified_time if Rails.env.production? && defined?(@sidecar_view_modified_time)
59
- @sidecar_view_modified_time = ::File.exist?(template_path) ? ::File.mtime(template_path).to_i.to_s : ""
60
- end
61
-
62
- def rb_component_modified_time
63
- return @rb_component_modified_time if Rails.env.production? && defined?(@rb_component_modified_time)
64
- @rb_component_modified_time = ::File.exist?(component_path) ? ::File.mtime(component_path).to_i.to_s : ""
65
- end
66
-
67
- def template_path
68
- File.join components_base_path, "#{virtual_path}.html.erb"
69
- end
70
-
71
- def component_path
72
- File.join components_base_path, "#{virtual_path}.rb"
73
- end
74
-
75
- def components_base_path
76
- ::Rails.configuration.view_component.view_component_path || "app/components"
77
- end
78
-
79
- private
80
-
81
- def named_cache_key_includes(name, *attrs)
82
- define_cache_key_method unless @named_cache_key_attributes
83
- @named_cache_key_attributes ||= {}
84
- @named_cache_key_attributes[name] = attrs
85
- end
86
-
87
- def define_cache_key_method
88
- # If the presenter defines cache key setup then define the method. Otherwise Rails assumes this
89
- # will return a valid key if the class will respond to this
90
- define_method :cache_key do |n = :_collection|
91
- if defined?(@cache_key)
92
- return @cache_key[n] if @cache_key.key?(n)
93
- else
94
- @cache_key ||= {}
95
- end
96
- generate_cache_key(n)
97
- @cache_key[n]
98
- end
99
- end
100
- end
101
-
102
- # Component modified time which is combined with other cache key attributes to generate cache key for an instance
103
- def component_modified_time
104
- self.class.component_modified_time
105
- end
106
-
107
- def cacheable?
108
- respond_to? :cache_key
109
- end
110
-
111
- def cache_key_modifier
112
- ENV["RAILS_CACHE_ID"]
113
- end
114
-
115
- def cache_keys_for_sources(key_attributes)
116
- sources = key_attributes.flat_map { |n| n.is_a?(Proc) ? instance_eval(&n) : send(n) }
117
- sources.compact.map do |item|
118
- next if item == self
119
- generate_item_cache_key_from(item)
120
- end
121
- end
122
-
123
- def generate_item_cache_key_from(item)
124
- if item.respond_to? :cache_key_with_version
125
- item.cache_key_with_version
126
- elsif item.respond_to? :cache_key
127
- item.cache_key
128
- elsif item.is_a?(String)
129
- Digest::SHA1.hexdigest(item)
130
- else
131
- Digest::SHA1.hexdigest(Marshal.dump(item))
132
- end
133
- end
134
-
135
- def generate_cache_key(index)
136
- key_attributes = self.class.named_cache_key_attributes[index]
137
- return nil unless key_attributes
138
- key = "#{self.class.name}/#{cache_keys_for_sources(key_attributes).join("/")}"
139
- raise StandardError, "Cache key for key #{key} is blank!" if key.blank?
140
- @cache_key[index] = cache_key_modifier.present? ? "#{key}/#{cache_key_modifier}" : key
141
- end
142
- end
143
- end
144
- end