view_component 2.23.0 → 2.25.1

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.

Potentially problematic release.


This version of view_component might be problematic. Click here for more details.

checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: fcba3738e1cef136c14cd82cc3dd8301596f576b8891bd668e5216ff0dca9bc6
4
- data.tar.gz: 7bd2112814c640f4b524f557799d1484fcaf88240505e7e09753cdacf7af87bd
3
+ metadata.gz: c411f9f34b25054093f7abe23c5842c7523f083ecdb1ba586429545548eca423
4
+ data.tar.gz: 744c27c0907544dfb93eb37ecf47c74dd7df86855c0e2b91f9619a77bd8eefc8
5
5
  SHA512:
6
- metadata.gz: e97c8b9fe11d78da84c129f99bfa19c8e76596064d76adc78f28127410f7f5b31a856c31a4a1e8444c707d7d228b1ffe4c01d9b70ffcc54a3ef9bd7edba7a61b
7
- data.tar.gz: 6856e490404554040459f57bfab1ae523a00808498230078bc914f97f1bcaf19d1f4a50c5ba66c5d31b0250d2d3185df0f4a93b6761bd875349e0b3a7f643466
6
+ metadata.gz: bee62ecbcfecbc53146b8a8e55207baf2d14769adda2bb2349494a82224acf12fa6584bfc32512e96474f28f011823f2c5712cbc021773d439c43fab8b090503
7
+ data.tar.gz: 3f519b85b066d89fdf75afb17563cb868bb4fb673caa21326661f0738b9b4398af068421064ca6f77abf08b7b46bdc549c132252b111b8fb3009809d430b9682
data/CHANGELOG.md CHANGED
@@ -1,6 +1,52 @@
1
1
  # CHANGELOG
2
2
 
3
- ## master
3
+ ## main
4
+
5
+ ## 2.25.1
6
+
7
+ * Experimental: call `._after_compile` class method after a component is compiled.
8
+
9
+ *Joel Hawksley*
10
+
11
+ * Fix bug where SlotV2 was rendered as an HTML string when using Slim.
12
+
13
+ *Manuel Puyol*
14
+
15
+ ## 2.25.0
16
+
17
+ * Add `--preview` generator option to create an associated preview file.
18
+
19
+ *Bob Maerten*
20
+
21
+ * Add argument validation to avoid `content` override.
22
+
23
+ *Manuel Puyol*
24
+
25
+ ## 2.24.0
26
+
27
+ * Add `--inline` option to the erb generator. Prevents default erb template from being created and creates a component with a call method.
28
+
29
+ *Nachiket Pusalkar*
30
+
31
+ * Add test case for checking presence of `content` in `#render?`.
32
+
33
+ *Joel Hawksley*
34
+
35
+ * Rename `master` branch to `main`.
36
+
37
+ *Joel Hawksley*
38
+
39
+ ## 2.23.2
40
+
41
+ * Fix bug where rendering a component `with_collection` from a controller raised an error.
42
+
43
+ *Joel Hawksley*
44
+
45
+ ## 2.23.1
46
+
47
+ * Fixed out-of-order rendering bug in `ActionView::SlotableV2`
48
+
49
+ *Blake Williams*
4
50
 
5
51
  ## 2.23.0
6
52
 
@@ -7,6 +7,7 @@ module Rails
7
7
 
8
8
  argument :attributes, type: :array, default: [], banner: "attribute"
9
9
  check_class_collision suffix: "Component"
10
+ class_option :inline, type: :boolean, default: false
10
11
 
11
12
  def create_component_file
12
13
  template "component.rb", File.join("app/components", class_path, "#{file_name}_component.rb")
@@ -14,6 +15,8 @@ module Rails
14
15
 
15
16
  hook_for :test_framework
16
17
 
18
+ hook_for :preview, type: :boolean
19
+
17
20
  hook_for :template_engine do |instance, template_engine|
18
21
  instance.invoke template_engine, [instance.name]
19
22
  end
@@ -37,6 +40,10 @@ module Rails
37
40
  def initialize_body
38
41
  attributes.map { |attr| "@#{attr.name} = #{attr.name}" }.join("\n ")
39
42
  end
43
+
44
+ def initialize_call_method_for_inline?
45
+ options["inline"]
46
+ end
40
47
  end
41
48
  end
42
49
  end
@@ -6,4 +6,10 @@ class <%= class_name %>Component < <%= parent_class %>
6
6
  <%= initialize_body %>
7
7
  end
8
8
  <%- end -%>
9
+ <%- if initialize_call_method_for_inline? -%>
10
+ def call
11
+ content_tag :h1, "Hello world!"
12
+ end
13
+ <%- end -%>
14
+
9
15
  end
@@ -7,6 +7,7 @@ module Erb
7
7
  class ComponentGenerator < Base
8
8
  source_root File.expand_path("templates", __dir__)
9
9
  class_option :sidecar, type: :boolean, default: false
10
+ class_option :inline, type: :boolean, default: false
10
11
 
11
12
  def copy_view_file
12
13
  template "component.html.erb", destination
@@ -15,10 +16,12 @@ module Erb
15
16
  private
16
17
 
17
18
  def destination
18
- if options["sidecar"]
19
- File.join("app/components", class_path, "#{file_name}_component", "#{file_name}_component.html.erb")
20
- else
21
- File.join("app/components", class_path, "#{file_name}_component.html.erb")
19
+ if !options["inline"]
20
+ if options["sidecar"]
21
+ File.join("app/components", class_path, "#{file_name}_component", "#{file_name}_component.html.erb")
22
+ else
23
+ File.join("app/components", class_path, "#{file_name}_component.html.erb")
24
+ end
22
25
  end
23
26
  end
24
27
 
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Preview
4
+ module Generators
5
+ class ComponentGenerator < ::Rails::Generators::NamedBase
6
+ source_root File.expand_path("templates", __dir__)
7
+
8
+ check_class_collision suffix: "ComponentPreview"
9
+
10
+ def create_preview_file
11
+ template "component_preview.rb", File.join("test/components/previews", class_path, "#{file_name}_component_preview.rb")
12
+ end
13
+
14
+ private
15
+
16
+ def file_name
17
+ @_file_name ||= super.sub(/_component\z/i, "")
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,5 @@
1
+ class <%= class_name %>ComponentPreview < ViewComponent::Preview
2
+ def default
3
+ render(<%= class_name %>Component.new)
4
+ end
5
+ end
@@ -15,12 +15,22 @@ module ViewComponent
15
15
 
16
16
  ViewContextCalledBeforeRenderError = Class.new(StandardError)
17
17
 
18
+ RESERVED_PARAMETER = :content
19
+
18
20
  # For CSRF authenticity tokens in forms
19
21
  delegate :form_authenticity_token, :protect_against_forgery?, :config, to: :helpers
20
22
 
21
23
  class_attribute :content_areas
22
24
  self.content_areas = [] # class_attribute:default doesn't work until Rails 5.2
23
25
 
26
+ # EXPERIMENTAL: This API is experimental and may be removed at any time.
27
+ # Hook for allowing components to do work as part of the compilation process.
28
+ #
29
+ # For example, one might compile component-specific assets at this point.
30
+ def self._after_compile
31
+ # noop
32
+ end
33
+
24
34
  # Entrypoint for rendering components.
25
35
  #
26
36
  # view_context: ActionView context from calling view
@@ -264,7 +274,7 @@ module ViewComponent
264
274
  parameter = validate_default ? collection_parameter : provided_collection_parameter
265
275
 
266
276
  return unless parameter
267
- return if initialize_parameters.map(&:last).include?(parameter)
277
+ return if initialize_parameter_names.include?(parameter)
268
278
 
269
279
  # If Ruby cannot parse the component class, then the initalize
270
280
  # parameters will be empty and ViewComponent will not be able to render
@@ -281,8 +291,25 @@ module ViewComponent
281
291
  )
282
292
  end
283
293
 
294
+ # Ensure the component initializer does not define
295
+ # invalid parameters that could override the framework's
296
+ # methods.
297
+ def validate_initialization_parameters!
298
+ return unless initialize_parameter_names.include?(RESERVED_PARAMETER)
299
+
300
+ raise ArgumentError.new(
301
+ "#{self} initializer cannot contain " \
302
+ "`#{RESERVED_PARAMETER}` since it will override a " \
303
+ "public ViewComponent method."
304
+ )
305
+ end
306
+
284
307
  private
285
308
 
309
+ def initialize_parameter_names
310
+ initialize_parameters.map(&:last)
311
+ end
312
+
286
313
  def initialize_parameters
287
314
  instance_method(:initialize).parameters
288
315
  end
@@ -4,14 +4,17 @@ require "action_view/renderer/collection_renderer" if Rails.version.to_f >= 6.1
4
4
 
5
5
  module ViewComponent
6
6
  class Collection
7
+ attr_reader :component
8
+ delegate :format, to: :component
9
+
7
10
  def render_in(view_context, &block)
8
11
  iterator = ActionView::PartialIteration.new(@collection.size)
9
12
 
10
- @component.compile(raise_errors: true)
11
- @component.validate_collection_parameter!(validate_default: true)
13
+ component.compile(raise_errors: true)
14
+ component.validate_collection_parameter!(validate_default: true)
12
15
 
13
16
  @collection.map do |item|
14
- content = @component.new(**component_options(item, iterator)).render_in(view_context, &block)
17
+ content = component.new(**component_options(item, iterator)).render_in(view_context, &block)
15
18
  iterator.iterate!
16
19
  content
17
20
  end.join.html_safe
@@ -34,8 +37,8 @@ module ViewComponent
34
37
  end
35
38
 
36
39
  def component_options(item, iterator)
37
- item_options = { @component.collection_parameter => item }
38
- item_options[@component.collection_counter_parameter] = iterator.index + 1 if @component.counter_argument_present?
40
+ item_options = { component.collection_parameter => item }
41
+ item_options[component.collection_counter_parameter] = iterator.index + 1 if component.counter_argument_present?
39
42
 
40
43
  @options.merge(item_options)
41
44
  end
@@ -46,7 +46,10 @@ module ViewComponent
46
46
  instance_method(:initialize).parameters.map(&:second).include?(collection_counter_parameter)
47
47
  end
48
48
 
49
- component_class.validate_collection_parameter! if raise_errors
49
+ if raise_errors
50
+ component_class.validate_initialization_parameters!
51
+ component_class.validate_collection_parameter!
52
+ end
50
53
 
51
54
  templates.each do |template|
52
55
  # Remove existing compiled template methods,
@@ -64,6 +67,8 @@ module ViewComponent
64
67
 
65
68
  define_render_template_for
66
69
 
70
+ component_class._after_compile
71
+
67
72
  CompileCache.register(component_class)
68
73
  end
69
74
 
@@ -163,9 +168,8 @@ module ViewComponent
163
168
  # end
164
169
  #
165
170
  # Without this, `MyOtherComponent` will not look for `my_component/my_other_component.html.erb`
166
- nested_component_files = if component_class.name.include?("::")
167
- nested_component_path = component_class.name.deconstantize.underscore
168
- Dir["#{directory}/#{nested_component_path}/#{component_name}.*{#{extensions}}"]
171
+ nested_component_files = if component_class.name.include?("::") && component_name != filename
172
+ Dir["#{directory}/#{filename}/#{component_name}.*{#{extensions}}"]
169
173
  else
170
174
  []
171
175
  end
@@ -205,7 +209,6 @@ module ViewComponent
205
209
  end
206
210
  end
207
211
 
208
- # :nocov:
209
212
  def compiled_template(file_path)
210
213
  handler = ActionView::Template.handler_for_extension(File.extname(file_path).gsub(".", ""))
211
214
  template = File.read(file_path)
@@ -216,7 +219,6 @@ module ViewComponent
216
219
  handler.call(OpenStruct.new(source: template, identifier: component_class.identifier, type: component_class.type))
217
220
  end
218
221
  end
219
- # :nocov:
220
222
 
221
223
  def call_method_name(variant)
222
224
  if variant.present? && variants.include?(variant)
@@ -22,17 +22,21 @@ module ViewComponent
22
22
  # If there is no slot renderable, we evaluate the block passed to
23
23
  # the slot and return it.
24
24
  def to_s
25
- if defined?(@_component_instance)
26
- # render_in is faster than `parent.render`
27
- @_component_instance.render_in(
28
- @parent.send(:view_context),
29
- &@_content_block
30
- )
31
- elsif defined?(@_content)
32
- @_content
33
- elsif defined?(@_content_block)
34
- @_content_block.call
25
+ return @content if defined?(@content)
26
+
27
+ view_context = @parent.send(:view_context)
28
+ @content = view_context.capture do
29
+ if defined?(@_component_instance)
30
+ # render_in is faster than `parent.render`
31
+ @_component_instance.render_in(view_context, &@_content_block)
32
+ elsif defined?(@_content)
33
+ @_content
34
+ elsif defined?(@_content_block)
35
+ @_content_block.call
36
+ end
35
37
  end
38
+
39
+ @content
36
40
  end
37
41
 
38
42
  # Allow access to public component methods via the wrapper
@@ -58,8 +62,12 @@ module ViewComponent
58
62
  @_component_instance.public_send(symbol, *args, &block)
59
63
  end
60
64
 
65
+ def html_safe?
66
+ to_s.html_safe?
67
+ end
68
+
61
69
  def respond_to_missing?(symbol, include_all = false)
62
- @_component_instance.respond_to?(symbol, include_all)
70
+ defined?(@_component_instance) && @_component_instance.respond_to?(symbol, include_all)
63
71
  end
64
72
  end
65
73
  end
@@ -3,8 +3,8 @@
3
3
  module ViewComponent
4
4
  module VERSION
5
5
  MAJOR = 2
6
- MINOR = 23
7
- PATCH = 0
6
+ MINOR = 25
7
+ PATCH = 1
8
8
 
9
9
  STRING = [MAJOR, MINOR, PATCH].join(".")
10
10
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: view_component
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.23.0
4
+ version: 2.25.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - GitHub Open Source
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-12-09 00:00:00.000000000 Z
11
+ date: 2021-02-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -198,7 +198,7 @@ dependencies:
198
198
  - - "~>"
199
199
  - !ruby/object:Gem::Version
200
200
  version: '0.13'
201
- description:
201
+ description:
202
202
  email:
203
203
  - opensource+view_component@github.com
204
204
  executables: []
@@ -219,6 +219,8 @@ files:
219
219
  - lib/rails/generators/erb/templates/component.html.erb.tt
220
220
  - lib/rails/generators/haml/component_generator.rb
221
221
  - lib/rails/generators/haml/templates/component.html.haml.tt
222
+ - lib/rails/generators/preview/component_generator.rb
223
+ - lib/rails/generators/preview/templates/component_preview.rb.tt
222
224
  - lib/rails/generators/rspec/component_generator.rb
223
225
  - lib/rails/generators/rspec/templates/component_spec.rb.tt
224
226
  - lib/rails/generators/slim/component_generator.rb
@@ -253,7 +255,7 @@ licenses:
253
255
  - MIT
254
256
  metadata:
255
257
  allowed_push_host: https://rubygems.org
256
- post_install_message:
258
+ post_install_message:
257
259
  rdoc_options: []
258
260
  require_paths:
259
261
  - lib
@@ -268,8 +270,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
268
270
  - !ruby/object:Gem::Version
269
271
  version: '0'
270
272
  requirements: []
271
- rubygems_version: 3.1.2
272
- signing_key:
273
+ rubygems_version: 3.0.3
274
+ signing_key:
273
275
  specification_version: 4
274
276
  summary: View components for Rails
275
277
  test_files: []