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 +4 -4
- data/docs/CHANGELOG.md +14 -0
- data/lib/view_component/base.rb +51 -39
- data/lib/view_component/config.rb +10 -10
- data/lib/view_component/engine.rb +0 -18
- data/lib/view_component/inline_template.rb +3 -3
- data/lib/view_component/slot.rb +15 -10
- data/lib/view_component/slotable.rb +1 -3
- data/lib/view_component/slotable_default.rb +18 -0
- data/lib/view_component/version.rb +1 -1
- metadata +2 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 544de384800ad5d0870666b9b1fdb3a74da9fd59d77f78e0d72ee5e134a3c307
|
4
|
+
data.tar.gz: 430c3652f5abc6fef9815b937274f66ebac34de297318e1ca6839589fa290ddf
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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.
|
data/lib/view_component/base.rb
CHANGED
@@ -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 |
|
43
|
-
|
44
|
-
|
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 &&
|
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
|
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
|
-
|
184
|
-
|
185
|
-
|
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
|
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
|
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? ||
|
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
|
-
|
358
|
+
@view_context && @__vc_render_in_block
|
332
359
|
end
|
333
360
|
|
334
|
-
def
|
335
|
-
|
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
|
-
|
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 =
|
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
|
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 `
|
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 `
|
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
|
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
|
41
|
+
@__vc_inline_template
|
42
42
|
end
|
43
43
|
|
44
44
|
def __vc_inline_template_language
|
45
|
-
@__vc_inline_template_language
|
45
|
+
@__vc_inline_template_language
|
46
46
|
end
|
47
47
|
|
48
48
|
def inherited(subclass)
|
data/lib/view_component/slot.rb
CHANGED
@@ -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
|
17
|
-
return true if
|
18
|
-
return true if
|
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
|
51
|
+
return @content if !@content.nil?
|
47
52
|
|
48
53
|
view_context = @parent.send(:view_context)
|
49
54
|
|
50
|
-
if
|
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
|
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
|
71
|
+
elsif !@__vc_content.nil?
|
67
72
|
@__vc_content
|
68
|
-
elsif
|
73
|
+
elsif !@__vc_content_block.nil?
|
69
74
|
view_context.capture(&@__vc_content_block)
|
70
|
-
elsif
|
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
|
-
|
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] &&
|
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
|
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.
|
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
|