view_component 2.47.0 → 2.48.0

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