view_component 2.47.0 → 2.48.0

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: 2c94e6fdeccccb7180494d100eef8c78a8dc8e3e9bc30e5647017b440788c6eb
4
- data.tar.gz: c3836df9c15e8039ba673895ad5a9544aebe55325f9fbd418b96f4bb4238b8d6
3
+ metadata.gz: 3abce9e08dcb71614178ed68b9c8443211ff78790911057752d8fda6fbb194b7
4
+ data.tar.gz: 3ac0a8ff1d7cafd2eb12e04a24f1d8f3362675833e4fda780bc238b8fc5ed41f
5
5
  SHA512:
6
- metadata.gz: 644f964985c8418371fdcac45e1e7b1771d89ee65ed8a692ec51c50cbed8a578937ba1bb7b9bf1d3b3e3729bd418df5fb2e9d1aee3bbb8215bfbed4504457074
7
- data.tar.gz: c4df9e14be4dc20e529beb794c96baf424087f7e36423b301402325e1b1ce0ae8ab575fe1b69334b3e27b5fa9e2fee227e9bd20e0e99fe5f384f2f535b43f80c
6
+ metadata.gz: dba31d0d37e73b7a1e26863d167f5d1eaefb8c5f53d9f542e47667090802b5f53b5c6b9c4b0a9188bf76f42d375c5d7a2cd3024065620aa9ff40b15911706cb8
7
+ data.tar.gz: f329872b25f36fe8fa0d018c2a5847ed0b6e47b095d16a27e89d2b0c7180f938d09730d0868405483a8e7c4fe4075afed56927a018b7a273ac4c94950d174fac
data/docs/CHANGELOG.md CHANGED
@@ -7,6 +7,60 @@ title: Changelog
7
7
 
8
8
  ## main
9
9
 
10
+ ## 2.48.0
11
+
12
+ * Correct path in example test command in Contributing docs.
13
+
14
+ *Mark Wilkinson*
15
+
16
+ * Update link to GOV.UK Components library in the resources list.
17
+
18
+ *Peter Yates*
19
+
20
+ * Add Lookbook to Resources docs page.
21
+
22
+ *Mark Perkins*
23
+
24
+ * Add blocking compiler mode for use in Rails development and testing modes, improving thread safety.
25
+
26
+ *Horia Radu*
27
+
28
+ * Add generators to support `tailwindcss-rails`.
29
+
30
+ *Dino Maric*, *Hans Lemuet*
31
+
32
+ * Add a namespaced component example to docs.
33
+
34
+ *Hans Lemuet*
35
+
36
+ * Setup `Appraisal` to add flexibility when testing ViewComponent against multiple Rails versions.
37
+
38
+ *Hans Lemuet*
39
+
40
+ * Return correct values for `request.path` and `request.query_string` methods when using the `with_request_url` test helper.
41
+
42
+ *Vasiliy Matyushin*
43
+
44
+ * Improve style in generators docs.
45
+
46
+ *Hans Lemuet*
47
+
48
+ * Correctly type Ruby version strings and update Rails versions used in CI configuration.
49
+
50
+ *Hans Lemuet*
51
+
52
+ * Make `ViewComponent::Collection` act like a collection of view components.
53
+
54
+ *Sammy Henningsson*
55
+
56
+ * Update `@param` of `#render_inline` to include `ViewComponent::Collection`.
57
+
58
+ *Yutaka Kamei*
59
+
60
+ * Add Wecasa to users list.
61
+
62
+ *Mohamed Ziata*
63
+
10
64
  ## 2.47.0
11
65
 
12
66
  * Display preview source on previews that exclusively use templates.
@@ -17,7 +71,7 @@ title: Changelog
17
71
 
18
72
  *Simon Fish*
19
73
 
20
- * Add WEBrick as a depenency to the docs application.
74
+ * Add WEBrick as a depenency to the application.
21
75
 
22
76
  *Connor McQuillan*
23
77
 
@@ -79,6 +133,10 @@ title: Changelog
79
133
 
80
134
  *Bob Maerten*
81
135
 
136
+ * Add config option `config.view_component.generate_sidecar` to always generate in the sidecar directory.
137
+
138
+ *Gleydson Tavares*
139
+
82
140
  ## 2.46.0
83
141
 
84
142
  * Add thread safety to the compiler.
@@ -15,7 +15,7 @@ module ViewComponent
15
15
  end
16
16
 
17
17
  def destination_directory
18
- if options["sidecar"]
18
+ if sidecar?
19
19
  File.join(component_path, class_path, destination_file_name)
20
20
  else
21
21
  File.join(component_path, class_path)
@@ -42,5 +42,9 @@ module ViewComponent
42
42
  gsub("/", "--")
43
43
  end
44
44
  end
45
+
46
+ def sidecar?
47
+ options["sidecar"] || ViewComponent::Base.generate_sidecar
48
+ end
45
49
  end
46
50
  end
@@ -35,7 +35,7 @@ module Locale
35
35
 
36
36
  def destination(locale = nil)
37
37
  extention = ".#{locale}" if locale
38
- if options["sidecar"]
38
+ if sidecar?
39
39
  File.join(component_path, class_path, "#{file_name}_component", "#{file_name}_component#{extention}.yml")
40
40
  else
41
41
  File.join(component_path, class_path, "#{file_name}_component#{extention}.yml")
@@ -23,7 +23,7 @@ module Stimulus
23
23
  private
24
24
 
25
25
  def destination
26
- if options["sidecar"]
26
+ if sidecar?
27
27
  File.join(component_path, class_path, "#{file_name}_component", "#{file_name}_component_controller.js")
28
28
  else
29
29
  File.join(component_path, class_path, "#{file_name}_component_controller.js")
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rails/generators/erb/component_generator"
4
+
5
+ module Tailwindcss
6
+ module Generators
7
+ class ComponentGenerator < Erb::Generators::ComponentGenerator
8
+ source_root File.expand_path("templates", __dir__)
9
+ end
10
+ end
11
+ end
@@ -0,0 +1 @@
1
+ <div<%= data_attributes %>>Add <%= class_name %> template here</div>
@@ -303,6 +303,7 @@ module ViewComponent
303
303
  # config.view_component.view_component_path = "app/my_components"
304
304
  #
305
305
  # Defaults to `app/components`.
306
+ #
306
307
  mattr_accessor :view_component_path, instance_writer: false, default: "app/components"
307
308
 
308
309
  # Parent class for generated components
@@ -310,8 +311,16 @@ module ViewComponent
310
311
  # config.view_component.component_parent_class = "MyBaseComponent"
311
312
  #
312
313
  # Defaults to "ApplicationComponent" if defined, "ViewComponent::Base" otherwise.
313
- mattr_accessor :component_parent_class,
314
- instance_writer: false
314
+ #
315
+ mattr_accessor :component_parent_class, instance_writer: false
316
+
317
+ # Always generate a component with a sidecar directory:
318
+ #
319
+ # config.view_component.generate_sidecar = true
320
+ #
321
+ # Defaults to `false`.
322
+ #
323
+ mattr_accessor :generate_sidecar, instance_writer: false, default: false
315
324
 
316
325
  class << self
317
326
  # @private
@@ -4,20 +4,34 @@ require "action_view/renderer/collection_renderer" if Rails.version.to_f >= 6.1
4
4
 
5
5
  module ViewComponent
6
6
  class Collection
7
+ include Enumerable
7
8
  attr_reader :component
8
9
 
9
10
  delegate :format, to: :component
11
+ delegate :size, to: :@collection
10
12
 
11
13
  def render_in(view_context, &block)
14
+ components.map do |component|
15
+ component.render_in(view_context, &block)
16
+ end.join.html_safe # rubocop:disable Rails/OutputSafety
17
+ end
18
+
19
+ def components
20
+ return @components if defined? @components
21
+
12
22
  iterator = ActionView::PartialIteration.new(@collection.size)
13
23
 
14
24
  component.validate_collection_parameter!(validate_default: true)
15
25
 
16
- @collection.map do |item|
17
- content = component.new(**component_options(item, iterator)).render_in(view_context, &block)
18
- iterator.iterate!
19
- content
20
- end.join.html_safe # rubocop:disable Rails/OutputSafety
26
+ @components = @collection.map do |item|
27
+ component.new(**component_options(item, iterator)).tap do |component|
28
+ iterator.iterate!
29
+ end
30
+ end
31
+ end
32
+
33
+ def each(&block)
34
+ components.each(&block)
21
35
  end
22
36
 
23
37
  private
@@ -42,7 +56,7 @@ module ViewComponent
42
56
  def component_options(item, iterator)
43
57
  item_options = { component.collection_parameter => item }
44
58
  item_options[component.collection_counter_parameter] = iterator.index + 1 if component.counter_argument_present?
45
- item_options[component.collection_iteration_parameter] = iterator if component.iteration_argument_present?
59
+ item_options[component.collection_iteration_parameter] = iterator.dup if component.iteration_argument_present?
46
60
 
47
61
  @options.merge(item_options)
48
62
  end
@@ -5,6 +5,15 @@ module ViewComponent
5
5
  # Lock required to be obtained before compiling the component
6
6
  attr_reader :__vc_compiler_lock
7
7
 
8
+ # Compiler mode. Can be either:
9
+ # * development (a blocking mode which ensures thread safety when redefining the `call` method for components,
10
+ # default in Rails development and test mode)
11
+ # * production (a non-blocking mode, default in Rails production mode)
12
+ DEVELOPMENT_MODE = :development
13
+ PRODUCTION_MODE = :production
14
+
15
+ class_attribute :mode, default: PRODUCTION_MODE
16
+
8
17
  def initialize(component_class)
9
18
  @component_class = component_class
10
19
  @__vc_compiler_lock = Monitor.new
@@ -14,10 +23,14 @@ module ViewComponent
14
23
  CompileCache.compiled?(component_class)
15
24
  end
16
25
 
26
+ def development?
27
+ self.class.mode == DEVELOPMENT_MODE
28
+ end
29
+
17
30
  def compile(raise_errors: false)
18
31
  return if compiled?
19
32
 
20
- __vc_compiler_lock.synchronize do
33
+ with_lock do
21
34
  CompileCache.invalidate_class!(component_class)
22
35
 
23
36
  subclass_instance_methods = component_class.instance_methods(false)
@@ -57,10 +70,10 @@ module ViewComponent
57
70
  end
58
71
 
59
72
  component_class.class_eval <<-RUBY, template[:path], -1
60
- def #{method_name}
61
- @output_buffer = ActionView::OutputBuffer.new
62
- #{compiled_template(template[:path])}
63
- end
73
+ def #{method_name}
74
+ @output_buffer = ActionView::OutputBuffer.new
75
+ #{compiled_template(template[:path])}
76
+ end
64
77
  RUBY
65
78
  end
66
79
 
@@ -72,6 +85,14 @@ module ViewComponent
72
85
  end
73
86
  end
74
87
 
88
+ def with_lock(&block)
89
+ if development?
90
+ __vc_compiler_lock.synchronize(&block)
91
+ else
92
+ block.call
93
+ end
94
+ end
95
+
75
96
  private
76
97
 
77
98
  attr_reader :component_class
@@ -85,16 +106,30 @@ module ViewComponent
85
106
  "elsif variant.to_sym == :#{variant}\n #{call_method_name(variant)}"
86
107
  end.join("\n")
87
108
 
88
- component_class.class_eval <<-RUBY, __FILE__, __LINE__ + 1
109
+ body = <<-RUBY
110
+ if variant.nil?
111
+ call
112
+ #{variant_elsifs}
113
+ else
114
+ call
115
+ end
116
+ RUBY
117
+
118
+ if development?
119
+ component_class.class_eval <<-RUBY, __FILE__, __LINE__ + 1
89
120
  def render_template_for(variant = nil)
90
- if variant.nil?
91
- call
92
- #{variant_elsifs}
93
- else
94
- call
121
+ self.class.compiler.with_lock do
122
+ #{body}
95
123
  end
96
124
  end
97
- RUBY
125
+ RUBY
126
+ else
127
+ component_class.class_eval <<-RUBY, __FILE__, __LINE__ + 1
128
+ def render_template_for(variant = nil)
129
+ #{body}
130
+ end
131
+ RUBY
132
+ end
98
133
  end
99
134
 
100
135
  def template_errors
@@ -115,6 +115,14 @@ module ViewComponent
115
115
  end
116
116
  end
117
117
 
118
+ initializer "compiler mode" do |app|
119
+ ViewComponent::Compiler.mode = if Rails.env.development? || Rails.env.test?
120
+ ViewComponent::Compiler::DEVELOPMENT_MODE
121
+ else
122
+ ViewComponent::Compiler::PRODUCTION_MODE
123
+ end
124
+ end
125
+
118
126
  config.after_initialize do |app|
119
127
  options = app.config.view_component
120
128
 
@@ -38,7 +38,7 @@ module ViewComponent
38
38
  # assert_text("Hello, World!")
39
39
  # ```
40
40
  #
41
- # @param component [ViewComponent::Base] The instance of the component to be rendered.
41
+ # @param component [ViewComponent::Base, ViewComponent::Collection] The instance of the component to be rendered.
42
42
  # @return [Nokogiri::HTML]
43
43
  def render_inline(component, **args, &block)
44
44
  @rendered_component =
@@ -113,16 +113,22 @@ module ViewComponent
113
113
  #
114
114
  # @param path [String] The path to set for the current request.
115
115
  def with_request_url(path)
116
+ old_request_path_info = request.path_info
116
117
  old_request_path_parameters = request.path_parameters
117
118
  old_request_query_parameters = request.query_parameters
119
+ old_request_query_string = request.query_string
118
120
  old_controller = defined?(@controller) && @controller
119
121
 
122
+ request.path_info = path
120
123
  request.path_parameters = Rails.application.routes.recognize_path(path)
121
124
  request.set_header("action_dispatch.request.query_parameters", Rack::Utils.parse_query(path.split("?")[1]))
125
+ request.set_header(Rack::QUERY_STRING, path.split("?")[1])
122
126
  yield
123
127
  ensure
128
+ request.path_info = old_request_path_info
124
129
  request.path_parameters = old_request_path_parameters
125
130
  request.set_header("action_dispatch.request.query_parameters", old_request_query_parameters)
131
+ request.set_header(Rack::QUERY_STRING, old_request_query_string)
126
132
  @controller = old_controller
127
133
  end
128
134
 
@@ -3,7 +3,7 @@
3
3
  module ViewComponent
4
4
  module VERSION
5
5
  MAJOR = 2
6
- MINOR = 47
6
+ MINOR = 48
7
7
  PATCH = 0
8
8
 
9
9
  STRING = [MAJOR, MINOR, PATCH].join(".")
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.47.0
4
+ version: 2.48.0
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: 2021-12-20 00:00:00.000000000 Z
11
+ date: 2022-01-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -44,6 +44,20 @@ dependencies:
44
44
  - - "~>"
45
45
  - !ruby/object:Gem::Version
46
46
  version: '1.0'
47
+ - !ruby/object:Gem::Dependency
48
+ name: appraisal
49
+ requirement: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - "~>"
52
+ - !ruby/object:Gem::Version
53
+ version: '2.4'
54
+ type: :development
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - "~>"
59
+ - !ruby/object:Gem::Version
60
+ version: '2.4'
47
61
  - !ruby/object:Gem::Dependency
48
62
  name: benchmark-ips
49
63
  requirement: !ruby/object:Gem::Requirement
@@ -268,7 +282,7 @@ dependencies:
268
282
  - - ">="
269
283
  - !ruby/object:Gem::Version
270
284
  version: '0'
271
- description:
285
+ description:
272
286
  email:
273
287
  - opensource+view_component@github.com
274
288
  executables: []
@@ -304,6 +318,8 @@ files:
304
318
  - lib/rails/generators/slim/templates/component.html.slim.tt
305
319
  - lib/rails/generators/stimulus/component_generator.rb
306
320
  - lib/rails/generators/stimulus/templates/component_controller.js.tt
321
+ - lib/rails/generators/tailwindcss/component_generator.rb
322
+ - lib/rails/generators/tailwindcss/templates/component.html.erb.tt
307
323
  - lib/rails/generators/test_unit/component_generator.rb
308
324
  - lib/rails/generators/test_unit/templates/component_test.rb.tt
309
325
  - lib/view_component.rb
@@ -342,7 +358,7 @@ licenses:
342
358
  - MIT
343
359
  metadata:
344
360
  allowed_push_host: https://rubygems.org
345
- post_install_message:
361
+ post_install_message:
346
362
  rdoc_options: []
347
363
  require_paths:
348
364
  - lib
@@ -357,8 +373,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
357
373
  - !ruby/object:Gem::Version
358
374
  version: '0'
359
375
  requirements: []
360
- rubygems_version: 3.1.2
361
- signing_key:
376
+ rubygems_version: 3.1.4
377
+ signing_key:
362
378
  specification_version: 4
363
379
  summary: View components for Rails
364
380
  test_files: []