view_component 2.23.0 → 2.25.1

Sign up to get free protection for your applications and to get access to all the features.

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: []