view_component 2.6.0 → 2.11.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 +4 -4
- data/CHANGELOG.md +38 -0
- data/README.md +81 -5
- data/lib/view_component/base.rb +49 -12
- data/lib/view_component/compile_cache.rb +24 -0
- data/lib/view_component/engine.rb +4 -0
- data/lib/view_component/test_helpers.rb +5 -3
- data/lib/view_component/version.rb +1 -1
- metadata +31 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: eec4666da3c79cf466b01641169db9055d1201684acf30169d05cfb9129a7dc2
|
4
|
+
data.tar.gz: 6cfe7e0dee9f5becab077ba05093ea04a38927d2b4cf22d58bff9c4a3cbcd0e3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f3a49b502f6f62c611ff8f700d4a84a2fe30e2a203a57a81964a2d99b005bd20ce431a93ba2319d7ac0dd1a358147d4bec97747b97ea3c386b2e27b5a4a4c241
|
7
|
+
data.tar.gz: 4c98f7b14919f9d56ec3a73e179be99f19cd2ec4157591bf3d1661cd5e8fd9a893110b4ba67dc8f0e79095b8d13974ed8a59904df41016f59515998316c03f2b
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,43 @@
|
|
1
1
|
# master
|
2
2
|
|
3
|
+
# 2.11.0
|
4
|
+
|
5
|
+
* Ensure Rails configuration is available within components.
|
6
|
+
|
7
|
+
*Trevor Broaddus*
|
8
|
+
|
9
|
+
* Fix bug where global Rails helpers are inaccessible from nested components. Before, `helpers` was pointing to parent component.
|
10
|
+
|
11
|
+
*Franco Sebregondi*
|
12
|
+
|
13
|
+
# 2.10.0
|
14
|
+
|
15
|
+
* Raise an `ArgumentError` with a helpful message when Ruby cannot parse a component class.
|
16
|
+
|
17
|
+
*Max Beizer*
|
18
|
+
|
19
|
+
# 2.9.0
|
20
|
+
|
21
|
+
* Cache components per-request in development, preventing unnecessary recompilation during a single request.
|
22
|
+
|
23
|
+
*Felipe Sateler*
|
24
|
+
|
25
|
+
# 2.8.0
|
26
|
+
|
27
|
+
* Add `before_render`, deprecating `before_render_check`.
|
28
|
+
|
29
|
+
*Joel Hawksley*
|
30
|
+
|
31
|
+
# 2.7.0
|
32
|
+
|
33
|
+
* Add `rendered_component` method to `ViewComponent::TestHelpers` which exposes the raw output of the rendered component.
|
34
|
+
|
35
|
+
*Richard Macklin*
|
36
|
+
|
37
|
+
* Support sidecar directories for views and other assets.
|
38
|
+
|
39
|
+
*Jon Palmer*
|
40
|
+
|
3
41
|
# 2.6.0
|
4
42
|
|
5
43
|
* Add `config.view_component.preview_route` to set the endpoint for component previews. By default `/rails/view_components` is used.
|
data/README.md
CHANGED
@@ -191,6 +191,38 @@ class InlineVariantComponent < ViewComponent::Base
|
|
191
191
|
end
|
192
192
|
```
|
193
193
|
|
194
|
+
### Sidecar Assets
|
195
|
+
|
196
|
+
ViewComponents supports two options for defining view files.
|
197
|
+
|
198
|
+
#### Sidecar view
|
199
|
+
|
200
|
+
The simplest option is to place the view next to the Ruby component:
|
201
|
+
|
202
|
+
```
|
203
|
+
app/components
|
204
|
+
├── ...
|
205
|
+
├── test_component.rb
|
206
|
+
├── test_component.html.erb
|
207
|
+
├── ...
|
208
|
+
```
|
209
|
+
|
210
|
+
#### Sidecar directory
|
211
|
+
|
212
|
+
As an alternative, views and other assets can be placed in a sidecar directory with the same name as the component, which can be useful for organizing views alongside other assets like Javascript and CSS.
|
213
|
+
|
214
|
+
```
|
215
|
+
app/components
|
216
|
+
├── ...
|
217
|
+
├── test_component.rb
|
218
|
+
├── test_component
|
219
|
+
| ├── test_component.css
|
220
|
+
| ├── test_component.html.erb
|
221
|
+
| └── test_component.js
|
222
|
+
├── ...
|
223
|
+
|
224
|
+
```
|
225
|
+
|
194
226
|
### Conditional Rendering
|
195
227
|
|
196
228
|
Components can implement a `#render?` method to be called after initialization to determine if the component should render.
|
@@ -242,6 +274,19 @@ end
|
|
242
274
|
|
243
275
|
_To assert that a component has not been rendered, use `refute_component_rendered` from `ViewComponent::TestHelpers`._
|
244
276
|
|
277
|
+
### `before_render`
|
278
|
+
|
279
|
+
Components can define a `before_render` method to be called before a component is rendered, when `helpers` is able to be used:
|
280
|
+
|
281
|
+
`app/components/confirm_email_component.rb`
|
282
|
+
```ruby
|
283
|
+
class MyComponent < ViewComponent::Base
|
284
|
+
def before_render
|
285
|
+
@my_icon = helpers.star_icon
|
286
|
+
end
|
287
|
+
end
|
288
|
+
```
|
289
|
+
|
245
290
|
### Rendering collections
|
246
291
|
|
247
292
|
Use `with_collection` to render a ViewComponent with a collection:
|
@@ -387,7 +432,7 @@ class MyComponentTest < ViewComponent::TestCase
|
|
387
432
|
end
|
388
433
|
```
|
389
434
|
|
390
|
-
In the absence of `capybara`,
|
435
|
+
In the absence of `capybara`, assert against the return value of `render_inline`, which is an instance of `Nokogiri::HTML::DocumentFragment`:
|
391
436
|
|
392
437
|
```ruby
|
393
438
|
test "render component" do
|
@@ -397,6 +442,31 @@ test "render component" do
|
|
397
442
|
end
|
398
443
|
```
|
399
444
|
|
445
|
+
Alternatively, assert against the raw output of the component, which is exposed as `rendered_component`:
|
446
|
+
|
447
|
+
```ruby
|
448
|
+
test "render component" do
|
449
|
+
render_inline(TestComponent.new(title: "my title")) { "Hello, World!" }
|
450
|
+
|
451
|
+
assert_includes rendered_component, "Hello, World!"
|
452
|
+
end
|
453
|
+
```
|
454
|
+
|
455
|
+
To test components that use `with_content_areas`:
|
456
|
+
|
457
|
+
```ruby
|
458
|
+
test "renders content_areas template with content " do
|
459
|
+
render_inline(ContentAreasComponent.new(footer: "Bye!")) do |component|
|
460
|
+
component.with(:title, "Hello!")
|
461
|
+
component.with(:body) { "Have a nice day." }
|
462
|
+
end
|
463
|
+
|
464
|
+
assert_selector(".title", text: "Hello!")
|
465
|
+
assert_selector(".body", text: "Have a nice day.")
|
466
|
+
assert_selector(".footer", text: "Bye!")
|
467
|
+
end
|
468
|
+
```
|
469
|
+
|
400
470
|
#### Action Pack Variants
|
401
471
|
|
402
472
|
Use the `with_variant` helper to test specific variants:
|
@@ -661,6 +731,7 @@ ViewComponent is far from a novel idea! Popular implementations of view componen
|
|
661
731
|
## Resources
|
662
732
|
|
663
733
|
- [Encapsulating Views, RailsConf 2020](https://youtu.be/YVYRus_2KZM)
|
734
|
+
- [Rethinking the View Layer with Components - Ruby Rogues Podcast](https://devchat.tv/ruby-rogues/rr-461-rethinking-the-view-layer-with-components-with-joel-hawksley/)
|
664
735
|
- [ViewComponent at GitHub with Joel Hawksley](https://the-ruby-blend.fireside.fm/9)
|
665
736
|
- [Components, HAML vs ERB, and Design Systems](https://the-ruby-blend.fireside.fm/4)
|
666
737
|
- [Choosing the Right Tech Stack with Dave Paola](https://5by5.tv/rubyonrails/307)
|
@@ -708,10 +779,15 @@ ViewComponent is built by:
|
|
708
779
|
|@blakewilliams|@seanpdoyle|@tclem|@nashby|@jaredcwhite|
|
709
780
|
|Boston, MA|New York, NY|San Francisco, CA|Minsk|Portland, OR|
|
710
781
|
|
711
|
-
|<img src="https://avatars.githubusercontent.com/simonrand?s=256" alt="simonrand" width="128" />|<img src="https://avatars.githubusercontent.com/fugufish?s=256" alt="fugufish" width="128" />|<img src="https://avatars.githubusercontent.com/cover?s=256" alt="cover" width="128" />|<img src="https://avatars.githubusercontent.com/franks921?s=256" alt="franks921" width="128" />|
|
712
|
-
|
713
|
-
|@simonrand|@fugufish|@cover|@franks921|
|
714
|
-
|Dublin, Ireland|Salt Lake City, Utah|Barcelona|South Africa|
|
782
|
+
|<img src="https://avatars.githubusercontent.com/simonrand?s=256" alt="simonrand" width="128" />|<img src="https://avatars.githubusercontent.com/fugufish?s=256" alt="fugufish" width="128" />|<img src="https://avatars.githubusercontent.com/cover?s=256" alt="cover" width="128" />|<img src="https://avatars.githubusercontent.com/franks921?s=256" alt="franks921" width="128" />|<img src="https://avatars.githubusercontent.com/fsateler?s=256" alt="fsateler" width="128" />|
|
783
|
+
|:---:|:---:|:---:|:---:|:---:|
|
784
|
+
|@simonrand|@fugufish|@cover|@franks921|@fsateler|
|
785
|
+
|Dublin, Ireland|Salt Lake City, Utah|Barcelona|South Africa|Chile|
|
786
|
+
|
787
|
+
|<img src="https://avatars.githubusercontent.com/maxbeizer?s=256" alt="maxbeizer" width="128" />|<img src="https://avatars.githubusercontent.com/franco?s=256" alt="franco" width="128" />|<img src="https://avatars.githubusercontent.com/tbroad-ramsey?s=256" alt="tbroad-ramsey" width="128" />|
|
788
|
+
|:---:|:---:|:---:|
|
789
|
+
|@maxbeizer|@franco|@tbroad-ramsey|
|
790
|
+
|Nashville, TN|Switzerland|Spring Hill, TN|
|
715
791
|
|
716
792
|
## License
|
717
793
|
|
data/lib/view_component/base.rb
CHANGED
@@ -3,6 +3,7 @@
|
|
3
3
|
require "action_view"
|
4
4
|
require "active_support/configurable"
|
5
5
|
require "view_component/collection"
|
6
|
+
require "view_component/compile_cache"
|
6
7
|
require "view_component/previewable"
|
7
8
|
|
8
9
|
module ViewComponent
|
@@ -11,7 +12,7 @@ module ViewComponent
|
|
11
12
|
include ViewComponent::Previewable
|
12
13
|
|
13
14
|
# For CSRF authenticity tokens in forms
|
14
|
-
delegate :form_authenticity_token, :protect_against_forgery?, to: :helpers
|
15
|
+
delegate :form_authenticity_token, :protect_against_forgery?, :config, to: :helpers
|
15
16
|
|
16
17
|
class_attribute :content_areas
|
17
18
|
self.content_areas = [] # class_attribute:default doesn't work until Rails 5.2
|
@@ -66,7 +67,7 @@ module ViewComponent
|
|
66
67
|
# Assign captured content passed to component as a block to @content
|
67
68
|
@content = view_context.capture(self, &block) if block_given?
|
68
69
|
|
69
|
-
|
70
|
+
before_render
|
70
71
|
|
71
72
|
if render?
|
72
73
|
send(self.class.call_method_name(@variant))
|
@@ -77,6 +78,10 @@ module ViewComponent
|
|
77
78
|
@current_template = old_current_template
|
78
79
|
end
|
79
80
|
|
81
|
+
def before_render
|
82
|
+
before_render_check
|
83
|
+
end
|
84
|
+
|
80
85
|
def before_render_check
|
81
86
|
# noop
|
82
87
|
end
|
@@ -101,9 +106,9 @@ module ViewComponent
|
|
101
106
|
@controller ||= view_context.controller
|
102
107
|
end
|
103
108
|
|
104
|
-
# Provides a proxy to access helper methods
|
109
|
+
# Provides a proxy to access helper methods from the context of the current controller
|
105
110
|
def helpers
|
106
|
-
@helpers ||= view_context
|
111
|
+
@helpers ||= controller.view_context
|
107
112
|
end
|
108
113
|
|
109
114
|
# Removes the first part of the path and the extension.
|
@@ -188,9 +193,7 @@ module ViewComponent
|
|
188
193
|
end
|
189
194
|
|
190
195
|
def compiled?
|
191
|
-
|
192
|
-
|
193
|
-
@compiled && ActionView::Base.cache_template_loading
|
196
|
+
CompileCache.compiled?(self)
|
194
197
|
end
|
195
198
|
|
196
199
|
# Compile templates to instance methods, assuming they haven't been compiled already.
|
@@ -205,6 +208,12 @@ module ViewComponent
|
|
205
208
|
return false
|
206
209
|
end
|
207
210
|
|
211
|
+
if instance_methods(false).include?(:before_render_check)
|
212
|
+
ActiveSupport::Deprecation.warn(
|
213
|
+
"`before_render_check` will be removed in v3.0.0. Use `before_render` instead."
|
214
|
+
)
|
215
|
+
end
|
216
|
+
|
208
217
|
# Remove any existing singleton methods,
|
209
218
|
# as Ruby warns when redefining a method.
|
210
219
|
remove_possible_singleton_method(:variants)
|
@@ -239,8 +248,8 @@ module ViewComponent
|
|
239
248
|
# starting line number so errors that are raised will point to the
|
240
249
|
# correct line in the component template.
|
241
250
|
line_number =
|
242
|
-
if ActionView::Base.respond_to?(:
|
243
|
-
ActionView::Base.
|
251
|
+
if ActionView::Base.respond_to?(:annotate_rendered_view_with_filenames) &&
|
252
|
+
ActionView::Base.annotate_rendered_view_with_filenames
|
244
253
|
-2
|
245
254
|
else
|
246
255
|
-1
|
@@ -260,7 +269,7 @@ module ViewComponent
|
|
260
269
|
RUBY
|
261
270
|
end
|
262
271
|
|
263
|
-
|
272
|
+
CompileCache.register self
|
264
273
|
end
|
265
274
|
|
266
275
|
# we'll eventually want to update this to support other types
|
@@ -298,7 +307,16 @@ module ViewComponent
|
|
298
307
|
parameter = validate_default ? collection_parameter : provided_collection_parameter
|
299
308
|
|
300
309
|
return unless parameter
|
301
|
-
return if
|
310
|
+
return if initialize_parameters.map(&:last).include?(parameter)
|
311
|
+
|
312
|
+
# If Ruby cannot parse the component class, then the initalize
|
313
|
+
# parameters will be empty and ViewComponent will not be able to render
|
314
|
+
# the component.
|
315
|
+
if initialize_parameters.empty?
|
316
|
+
raise ArgumentError.new(
|
317
|
+
"#{self} initializer is empty or invalid."
|
318
|
+
)
|
319
|
+
end
|
302
320
|
|
303
321
|
raise ArgumentError.new(
|
304
322
|
"#{self} initializer must accept " \
|
@@ -308,6 +326,10 @@ module ViewComponent
|
|
308
326
|
|
309
327
|
private
|
310
328
|
|
329
|
+
def initialize_parameters
|
330
|
+
instance_method(:initialize).parameters
|
331
|
+
end
|
332
|
+
|
311
333
|
def provided_collection_parameter
|
312
334
|
@provided_collection_parameter ||= nil
|
313
335
|
end
|
@@ -341,7 +363,22 @@ module ViewComponent
|
|
341
363
|
|
342
364
|
def matching_views_in_source_location
|
343
365
|
return [] unless source_location
|
344
|
-
|
366
|
+
|
367
|
+
location_without_extension = source_location.chomp(File.extname(source_location))
|
368
|
+
|
369
|
+
extenstions = ActionView::Template.template_handler_extensions.join(",")
|
370
|
+
|
371
|
+
# view files in the same directory as te component
|
372
|
+
sidecar_files = Dir["#{location_without_extension}.*{#{extenstions}}"]
|
373
|
+
|
374
|
+
# view files in a directory named like the component
|
375
|
+
directory = File.dirname(source_location)
|
376
|
+
filename = File.basename(source_location, ".rb")
|
377
|
+
component_name = name.demodulize.underscore
|
378
|
+
|
379
|
+
sidecar_directory_files = Dir["#{directory}/#{component_name}/#{filename}.*{#{extenstions}}"]
|
380
|
+
|
381
|
+
(sidecar_files - [source_location] + sidecar_directory_files)
|
345
382
|
end
|
346
383
|
|
347
384
|
def templates
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ViewComponent
|
4
|
+
# Keeps track of which templates have already been compiled
|
5
|
+
# This is not part of the public API
|
6
|
+
module CompileCache
|
7
|
+
mattr_accessor :cache, instance_reader: false, instance_accessor: false do
|
8
|
+
Set.new
|
9
|
+
end
|
10
|
+
module_function
|
11
|
+
|
12
|
+
def register(klass)
|
13
|
+
cache << klass
|
14
|
+
end
|
15
|
+
|
16
|
+
def compiled?(klass)
|
17
|
+
cache.include? klass
|
18
|
+
end
|
19
|
+
|
20
|
+
def invalidate!
|
21
|
+
cache.clear
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -69,6 +69,10 @@ module ViewComponent
|
|
69
69
|
get "#{options.preview_route}/*path", to: "view_components#previews", as: :preview_view_component, internal: true
|
70
70
|
end
|
71
71
|
end
|
72
|
+
|
73
|
+
app.executor.to_run :before do
|
74
|
+
CompileCache.invalidate! unless ActionView::Base.cache_template_loading
|
75
|
+
end
|
72
76
|
end
|
73
77
|
end
|
74
78
|
end
|
@@ -7,7 +7,7 @@ module ViewComponent
|
|
7
7
|
include Capybara::Minitest::Assertions
|
8
8
|
|
9
9
|
def page
|
10
|
-
Capybara::Node::Simple.new(@
|
10
|
+
Capybara::Node::Simple.new(@rendered_component)
|
11
11
|
end
|
12
12
|
|
13
13
|
def refute_component_rendered
|
@@ -17,10 +17,12 @@ module ViewComponent
|
|
17
17
|
warn "WARNING in `ViewComponent::TestHelpers`: You must add `capybara` to your Gemfile to use Capybara assertions."
|
18
18
|
end
|
19
19
|
|
20
|
+
attr_reader :rendered_component
|
21
|
+
|
20
22
|
def render_inline(component, **args, &block)
|
21
|
-
@
|
23
|
+
@rendered_component = controller.view_context.render(component, args, &block)
|
22
24
|
|
23
|
-
Nokogiri::HTML.fragment(@
|
25
|
+
Nokogiri::HTML.fragment(@rendered_component)
|
24
26
|
end
|
25
27
|
|
26
28
|
def controller
|
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.
|
4
|
+
version: 2.11.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- GitHub Open Source
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-
|
11
|
+
date: 2020-06-16 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -142,6 +142,34 @@ dependencies:
|
|
142
142
|
- - "~>"
|
143
143
|
- !ruby/object:Gem::Version
|
144
144
|
version: 0.13.0
|
145
|
+
- !ruby/object:Gem::Dependency
|
146
|
+
name: simplecov
|
147
|
+
requirement: !ruby/object:Gem::Requirement
|
148
|
+
requirements:
|
149
|
+
- - "~>"
|
150
|
+
- !ruby/object:Gem::Version
|
151
|
+
version: 0.18.0
|
152
|
+
type: :development
|
153
|
+
prerelease: false
|
154
|
+
version_requirements: !ruby/object:Gem::Requirement
|
155
|
+
requirements:
|
156
|
+
- - "~>"
|
157
|
+
- !ruby/object:Gem::Version
|
158
|
+
version: 0.18.0
|
159
|
+
- !ruby/object:Gem::Dependency
|
160
|
+
name: simplecov-erb
|
161
|
+
requirement: !ruby/object:Gem::Requirement
|
162
|
+
requirements:
|
163
|
+
- - "~>"
|
164
|
+
- !ruby/object:Gem::Version
|
165
|
+
version: '0.1'
|
166
|
+
type: :development
|
167
|
+
prerelease: false
|
168
|
+
version_requirements: !ruby/object:Gem::Requirement
|
169
|
+
requirements:
|
170
|
+
- - "~>"
|
171
|
+
- !ruby/object:Gem::Version
|
172
|
+
version: '0.1'
|
145
173
|
description:
|
146
174
|
email:
|
147
175
|
- opensource+view_component@github.com
|
@@ -172,6 +200,7 @@ files:
|
|
172
200
|
- lib/view_component.rb
|
173
201
|
- lib/view_component/base.rb
|
174
202
|
- lib/view_component/collection.rb
|
203
|
+
- lib/view_component/compile_cache.rb
|
175
204
|
- lib/view_component/engine.rb
|
176
205
|
- lib/view_component/preview.rb
|
177
206
|
- lib/view_component/previewable.rb
|