view_component 4.0.0.alpha4 → 4.0.0.alpha5

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 70feada9d7f9456623bfed2a6c76a9546f8fe5596f81e0f47ed7059808b1a68d
4
- data.tar.gz: 77d8002e2a0fdb344c3647972b9051ce1c3ac3bc299e49442c8631921a6b5437
3
+ metadata.gz: 544de384800ad5d0870666b9b1fdb3a74da9fd59d77f78e0d72ee5e134a3c307
4
+ data.tar.gz: 430c3652f5abc6fef9815b937274f66ebac34de297318e1ca6839589fa290ddf
5
5
  SHA512:
6
- metadata.gz: c3aeae640580d7d5c9192836fbc8ab26932a9527117438f4fa808fed36cd2c4393194fd66e5d01ddbc56bd0f0d5042b1707ee25b94760969b06a9d34a1700f85
7
- data.tar.gz: cb4ee57d927b7b9a27436ec1d736675ee59fe2dfc7aa281e8c6a1b9be87fa517849bc3443a6057a01f1a3e1b97320e8d566681dc989c452fa8c45ff261e058c9
6
+ metadata.gz: f30651af979f6c1c5fd43514d04cef3f6430982198e593375d61ce79190e83b8b2d61d7cccb67607248f0b791346b09db33b4705e81cb257b87bd8255c5b2d63
7
+ data.tar.gz: 956af9c486961785821e9401c9c1ce6b187f3f21a0425d5d6d36602f384f3beb79629f9be2e743e13f525bdc15498480565989cbdb37952a7b0e1cbb2aaabbb0
data/docs/CHANGELOG.md CHANGED
@@ -10,6 +10,20 @@ nav_order: 6
10
10
 
11
11
  ## main
12
12
 
13
+ ## 4.0.0.alpha5
14
+
15
+ * BREAKING: `config.view_component_path` is now `config.generate.path`, as components have long since been able to exist in any directory.
16
+
17
+ *Joel Hawksley*
18
+
19
+ * BREAKING: Remove broken integration with `rails stats` that ignored components outside of `app/components`.
20
+
21
+ *Joel Hawksley*
22
+
23
+ * Add internal optimization for Ruby object shapes.
24
+
25
+ *Adam Hess*, *Joel Hawksley*
26
+
13
27
  ## 4.0.0.alpha4
14
28
 
15
29
  * BREAKING: Remove default initializer from `ViewComponent::Base`. Previously, `ViewComponent::Base` defined a catch-all initializer that allowed components without an initializer defined to be passed arbitrary arguments.
@@ -35,18 +35,51 @@ module ViewComponent
35
35
  class << self
36
36
  delegate(*ViewComponent::Config.defaults.keys, to: :config)
37
37
 
38
+ # Redefine `new` so we can pre-allocate instance variables to optimize
39
+ # for Ruby object shapes.
40
+ def new(...)
41
+ instance = allocate
42
+ instance.__vc_pre_allocate_instance_variables
43
+ instance.send(:initialize, ...)
44
+ instance
45
+ end
46
+
38
47
  # Returns the current config.
39
48
  #
40
49
  # @return [ActiveSupport::OrderedOptions]
41
50
  def config
42
- module_parents.each do |m|
43
- config = m.try(:config).try(:view_component)
44
- return config if config
51
+ module_parents.each do |module_parent|
52
+ next unless module_parent.respond_to?(:config)
53
+ module_parent_config = module_parent.config.try(:view_component)
54
+ return module_parent_config if module_parent_config
45
55
  end
46
56
  ViewComponent::Config.current
47
57
  end
48
58
  end
49
59
 
60
+ def __vc_pre_allocate_instance_variables
61
+ @__vc_parent_render_level = 0
62
+ @__vc_set_slots = {}
63
+ @__vc_content_evaluated = false
64
+ @current_template = nil
65
+ @output_buffer = nil
66
+ @lookup_context = nil
67
+ @view_flow = nil
68
+ @view_context = nil
69
+ @virtual_path = nil
70
+ @__vc_ancestor_calls = nil
71
+ @__vc_controller = nil
72
+ @__vc_content = :unset # some behaviors depend on checking for nil
73
+ @__vc_content_set_by_with_content = nil
74
+ @__vc_helpers = nil
75
+ @__vc_inline_template = nil
76
+ @__vc_inline_template_defined = nil
77
+ @__vc_render_in_block = nil
78
+ @__vc_request = nil
79
+ @__vc_requested_details = nil
80
+ @__vc_original_view_context = nil
81
+ end
82
+
50
83
  include ActionView::Helpers
51
84
  include ERB::Escape
52
85
  include ActiveSupport::CoreExt::ERBUtil
@@ -113,14 +146,12 @@ module ViewComponent
113
146
  @__vc_requested_details ||= @lookup_context.vc_requested_details
114
147
 
115
148
  # For caching, such as #cache_if
116
- @current_template = nil unless defined?(@current_template)
117
149
  old_current_template = @current_template
118
150
 
119
- if block && defined?(@__vc_content_set_by_with_content)
151
+ if block && __vc_content_set_by_with_content?
120
152
  raise DuplicateContentError.new(self.class.name)
121
153
  end
122
154
 
123
- @__vc_content_evaluated = false
124
155
  @__vc_render_in_block = block
125
156
 
126
157
  before_render
@@ -174,16 +205,12 @@ module ViewComponent
174
205
  #
175
206
  # When rendering the parent inside an .erb template, use `#render_parent` instead.
176
207
  def render_parent_to_string
177
- @__vc_parent_render_level ||= 0 # ensure a good starting value
178
-
179
- begin
180
- target_render = self.class.instance_variable_get(:@__vc_ancestor_calls)[@__vc_parent_render_level]
181
- @__vc_parent_render_level += 1
208
+ target_render = self.class.instance_variable_get(:@__vc_ancestor_calls)[@__vc_parent_render_level]
209
+ @__vc_parent_render_level += 1
182
210
 
183
- target_render.bind_call(self, @__vc_requested_details)
184
- ensure
185
- @__vc_parent_render_level -= 1
186
- end
211
+ target_render.bind_call(self, @__vc_requested_details)
212
+ ensure
213
+ @__vc_parent_render_level -= 1
187
214
  end
188
215
 
189
216
  # Optional content to be returned before the rendered template.
@@ -306,12 +333,12 @@ module ViewComponent
306
333
  # @return [String]
307
334
  def content
308
335
  @__vc_content_evaluated = true
309
- return @__vc_content if defined?(@__vc_content)
336
+ return @__vc_content if @__vc_content != :unset
310
337
 
311
338
  @__vc_content =
312
339
  if __vc_render_in_block_provided?
313
340
  view_context.capture(self, &@__vc_render_in_block)
314
- elsif __vc_content_set_by_with_content_defined?
341
+ elsif __vc_content_set_by_with_content?
315
342
  @__vc_content_set_by_with_content
316
343
  end
317
344
  end
@@ -320,7 +347,7 @@ module ViewComponent
320
347
  #
321
348
  # @return [Boolean]
322
349
  def content?
323
- __vc_render_in_block_provided? || __vc_content_set_by_with_content_defined?
350
+ __vc_render_in_block_provided? || __vc_content_set_by_with_content?
324
351
  end
325
352
 
326
353
  private
@@ -328,15 +355,15 @@ module ViewComponent
328
355
  attr_reader :view_context
329
356
 
330
357
  def __vc_render_in_block_provided?
331
- defined?(@view_context) && @view_context && @__vc_render_in_block
358
+ @view_context && @__vc_render_in_block
332
359
  end
333
360
 
334
- def __vc_content_set_by_with_content_defined?
335
- defined?(@__vc_content_set_by_with_content)
361
+ def __vc_content_set_by_with_content?
362
+ !@__vc_content_set_by_with_content.nil?
336
363
  end
337
364
 
338
365
  def content_evaluated?
339
- defined?(@__vc_content_evaluated) && @__vc_content_evaluated
366
+ @__vc_content_evaluated
340
367
  end
341
368
 
342
369
  def maybe_escape_html(text)
@@ -373,15 +400,6 @@ module ViewComponent
373
400
  # configured on a per-test basis using `with_controller_class`.
374
401
  #
375
402
 
376
- # Path for component files
377
- #
378
- # ```ruby
379
- # config.view_component.view_component_path = "app/my_components"
380
- # ```
381
- #
382
- # Defaults to `nil`. If this is falsy, `app/components` is used.
383
- #
384
-
385
403
  # Parent class for generated components
386
404
  #
387
405
  # ```ruby
@@ -551,19 +569,13 @@ module ViewComponent
551
569
  # We use `base_label` method here instead of `label` to avoid cases where the method
552
570
  # owner is included in a prefix like `ApplicationComponent.inherited`.
553
571
  child.identifier = caller_locations(1, 10).reject { |l| l.base_label == "inherited" }[0].path
554
-
555
- # If Rails application is loaded, removes the first part of the path and the extension.
556
- if defined?(Rails) && Rails.application
557
- child.virtual_path = child.identifier.gsub(
558
- /(.*#{Regexp.quote(ViewComponent::Base.config.view_component_path)})|(\.rb)/, ""
559
- )
560
- end
572
+ child.virtual_path = child.name&.underscore
561
573
 
562
574
  # Set collection parameter to the extended component
563
575
  child.with_collection_parameter provided_collection_parameter
564
576
 
565
577
  if instance_methods(false).include?(:render_template_for)
566
- vc_ancestor_calls = defined?(@__vc_ancestor_calls) ? @__vc_ancestor_calls.dup : []
578
+ vc_ancestor_calls = (!@__vc_ancestor_calls.nil?) ? @__vc_ancestor_calls.dup : []
567
579
 
568
580
  vc_ancestor_calls.unshift(instance_method(:render_template_for))
569
581
  child.instance_variable_set(:@__vc_ancestor_calls, vc_ancestor_calls)
@@ -16,7 +16,6 @@ module ViewComponent
16
16
  preview_controller: "ViewComponentsController",
17
17
  preview_route: "/rails/view_components",
18
18
  instrumentation_enabled: false,
19
- view_component_path: "app/components",
20
19
  component_parent_class: nil,
21
20
  show_previews: Rails.env.development? || Rails.env.test?,
22
21
  preview_paths: default_preview_paths,
@@ -32,6 +31,12 @@ module ViewComponent
32
31
  # All options under this namespace default to `false` unless otherwise
33
32
  # stated.
34
33
  #
34
+ # #### `#path`
35
+ #
36
+ # Where to put generated components. Defaults to `app/components`:
37
+ #
38
+ # config.view_component.generate.path = "lib/components"
39
+ #
35
40
  # #### `#sidecar`
36
41
  #
37
42
  # Always generate a component with a sidecar directory:
@@ -84,14 +89,14 @@ module ViewComponent
84
89
  #
85
90
  # #### `#use_component_path_for_rspec_tests`
86
91
  #
87
- # Whether to use the `config.view_component_path` when generating new
92
+ # Whether to use `config.generate.path` when generating new
88
93
  # RSpec component tests:
89
94
  #
90
95
  # config.view_component.generate.use_component_path_for_rspec_tests = true
91
96
  #
92
- # When set to `true`, the generator will use the `view_component_path` to
97
+ # When set to `true`, the generator will use the `path` to
93
98
  # decide where to generate the new RSpec component test.
94
- # For example, if the `view_component_path` is
99
+ # For example, if the `path` is
95
100
  # `app/views/components`, then the generator will create a new spec file
96
101
  # in `spec/views/components/` rather than the default `spec/components/`.
97
102
 
@@ -110,12 +115,6 @@ module ViewComponent
110
115
  # Whether ActiveSupport notifications are enabled.
111
116
  # Defaults to `false`.
112
117
 
113
- # @!attribute view_component_path
114
- # @return [String]
115
- # The path in which components, their templates, and their sidecars should
116
- # be stored.
117
- # Defaults to `"app/components"`.
118
-
119
118
  # @!attribute component_parent_class
120
119
  # @return [String]
121
120
  # The parent class from which generated components will inherit.
@@ -171,6 +170,7 @@ module ViewComponent
171
170
  def default_generate_options
172
171
  options = ActiveSupport::OrderedOptions.new(false)
173
172
  options.preview_path = ""
173
+ options.path = "app/components"
174
174
  options
175
175
  end
176
176
  end
@@ -8,24 +8,6 @@ module ViewComponent
8
8
  class Engine < Rails::Engine # :nodoc:
9
9
  config.view_component = ViewComponent::Config.current
10
10
 
11
- if Rails.version.to_f < 8.0
12
- rake_tasks do
13
- load "view_component/rails/tasks/view_component.rake"
14
- end
15
- else
16
- initializer "view_component.stats_directories" do |app|
17
- require "rails/code_statistics"
18
-
19
- if Rails.root.join(ViewComponent::Base.view_component_path).directory?
20
- Rails::CodeStatistics.register_directory("ViewComponents", ViewComponent::Base.view_component_path)
21
- end
22
-
23
- if Rails.root.join("test/components").directory?
24
- Rails::CodeStatistics.register_directory("ViewComponent tests", "test/components", test_directory: true)
25
- end
26
- end
27
- end
28
-
29
11
  initializer "view_component.set_configs" do |app|
30
12
  options = app.config.view_component
31
13
 
@@ -9,7 +9,7 @@ module ViewComponent # :nodoc:
9
9
  def method_missing(method, *args)
10
10
  return super if !method.end_with?("_template")
11
11
 
12
- if defined?(@__vc_inline_template_defined) && @__vc_inline_template_defined
12
+ if @__vc_inline_template_defined
13
13
  raise MultipleInlineTemplatesError
14
14
  end
15
15
 
@@ -38,11 +38,11 @@ module ViewComponent # :nodoc:
38
38
  end
39
39
 
40
40
  def inline_template
41
- @__vc_inline_template if defined?(@__vc_inline_template)
41
+ @__vc_inline_template
42
42
  end
43
43
 
44
44
  def __vc_inline_template_language
45
- @__vc_inline_template_language if defined?(@__vc_inline_template_language)
45
+ @__vc_inline_template_language
46
46
  end
47
47
 
48
48
  def inherited(subclass)
@@ -9,13 +9,18 @@ module ViewComponent
9
9
  attr_writer :__vc_component_instance, :__vc_content_block, :__vc_content
10
10
 
11
11
  def initialize(parent)
12
+ @content = nil
13
+ @__vc_component_instance = nil
14
+ @__vc_content = nil
15
+ @__vc_content_block = nil
16
+ @__vc_content_set_by_with_content = nil
12
17
  @parent = parent
13
18
  end
14
19
 
15
20
  def content?
16
- return true if defined?(@__vc_content) && @__vc_content.present?
17
- return true if defined?(@__vc_content_set_by_with_content) && @__vc_content_set_by_with_content.present?
18
- return true if defined?(@__vc_content_block) && @__vc_content_block.present?
21
+ return true if @__vc_content.present?
22
+ return true if @__vc_content_set_by_with_content.present?
23
+ return true if @__vc_content_block.present?
19
24
  return false if !__vc_component_instance?
20
25
 
21
26
  @__vc_component_instance.content?
@@ -43,11 +48,11 @@ module ViewComponent
43
48
  # If there is no slot renderable, we evaluate the block passed to
44
49
  # the slot and return it.
45
50
  def to_s
46
- return @content if defined?(@content)
51
+ return @content if !@content.nil?
47
52
 
48
53
  view_context = @parent.send(:view_context)
49
54
 
50
- if defined?(@__vc_content_block) && defined?(@__vc_content_set_by_with_content)
55
+ if !@__vc_content_block.nil? && !@__vc_content_set_by_with_content.nil? && !@__vc_content_set_by_with_content.nil?
51
56
  raise DuplicateSlotContentError.new(self.class.name)
52
57
  end
53
58
 
@@ -55,7 +60,7 @@ module ViewComponent
55
60
  if __vc_component_instance?
56
61
  @__vc_component_instance.__vc_original_view_context = @parent.__vc_original_view_context
57
62
 
58
- if defined?(@__vc_content_block)
63
+ if !@__vc_content_block.nil?
59
64
  # render_in is faster than `parent.render`
60
65
  @__vc_component_instance.render_in(view_context) do |*args|
61
66
  @__vc_content_block.call(*args)
@@ -63,11 +68,11 @@ module ViewComponent
63
68
  else
64
69
  @__vc_component_instance.render_in(view_context)
65
70
  end
66
- elsif defined?(@__vc_content)
71
+ elsif !@__vc_content.nil?
67
72
  @__vc_content
68
- elsif defined?(@__vc_content_block)
73
+ elsif !@__vc_content_block.nil?
69
74
  view_context.capture(&@__vc_content_block)
70
- elsif defined?(@__vc_content_set_by_with_content)
75
+ elsif !@__vc_content_set_by_with_content.nil?
71
76
  @__vc_content_set_by_with_content
72
77
  end
73
78
 
@@ -108,7 +113,7 @@ module ViewComponent
108
113
  private
109
114
 
110
115
  def __vc_component_instance?
111
- defined?(@__vc_component_instance)
116
+ !@__vc_component_instance.nil?
112
117
  end
113
118
  end
114
119
  end
@@ -420,8 +420,6 @@ module ViewComponent
420
420
  end
421
421
  end
422
422
 
423
- @__vc_set_slots ||= {}
424
-
425
423
  if slot_definition[:collection]
426
424
  @__vc_set_slots[slot_name] ||= []
427
425
  @__vc_set_slots[slot_name].push(slot)
@@ -435,7 +433,7 @@ module ViewComponent
435
433
  def set_polymorphic_slot(slot_name, poly_type = nil, *args, **kwargs, &block)
436
434
  slot_definition = self.class.registered_slots[slot_name]
437
435
 
438
- if !slot_definition[:collection] && defined?(@__vc_set_slots) && @__vc_set_slots[slot_name]
436
+ if !slot_definition[:collection] && @__vc_set_slots[slot_name]
439
437
  raise ContentAlreadySetForPolymorphicSlotError.new(slot_name)
440
438
  end
441
439
 
@@ -0,0 +1,18 @@
1
+ module ViewComponent
2
+ module SlotableDefault
3
+ def get_slot(slot_name)
4
+ return super unless !@__vc_set_slots[slot_name] && (default_method = registered_slots[slot_name][:default_method])
5
+
6
+ renderable_value = send(default_method)
7
+ slot = Slot.new(self)
8
+
9
+ if renderable_value.respond_to?(:render_in)
10
+ slot.__vc_component_instance = renderable_value
11
+ else
12
+ slot.__vc_content = renderable_value
13
+ end
14
+
15
+ slot
16
+ end
17
+ end
18
+ end
@@ -5,7 +5,7 @@ module ViewComponent
5
5
  MAJOR = 4
6
6
  MINOR = 0
7
7
  PATCH = 0
8
- PRE = "alpha4"
8
+ PRE = "alpha5"
9
9
 
10
10
  STRING = [MAJOR, MINOR, PATCH, PRE].compact.join(".")
11
11
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: view_component
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.0.0.alpha4
4
+ version: 4.0.0.alpha5
5
5
  platform: ruby
6
6
  authors:
7
7
  - ViewComponent Team
@@ -481,6 +481,7 @@ files:
481
481
  - lib/view_component/request_details.rb
482
482
  - lib/view_component/slot.rb
483
483
  - lib/view_component/slotable.rb
484
+ - lib/view_component/slotable_default.rb
484
485
  - lib/view_component/system_test_case.rb
485
486
  - lib/view_component/system_test_helpers.rb
486
487
  - lib/view_component/template.rb