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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8bc0f4ab66dfca6a89f9882d0df39f5f4a84f479f26dfd0b3334b43fe4f9b4ed
4
- data.tar.gz: 39128211a1338af6c78a54085b59f48a98411dc282e6248f03fc56229a6d7cd0
3
+ metadata.gz: eec4666da3c79cf466b01641169db9055d1201684acf30169d05cfb9129a7dc2
4
+ data.tar.gz: 6cfe7e0dee9f5becab077ba05093ea04a38927d2b4cf22d58bff9c4a3cbcd0e3
5
5
  SHA512:
6
- metadata.gz: 1aa9fb3d7361efa6a98465c1513e3296abc4495ad30393ed9fbf3febc919a8669184fe2e28fe5afa9666a42b71958787b2bf091b71d4e9889b020d0495769abf
7
- data.tar.gz: 2ce5ece866ddc50d8aa01cd139c230c10b26aee9d8bbc49f7421b8d191e5b84dbd57d1247b9973f936932dcde9bd925f96c2d3114ac201d98511157b7643bac0
6
+ metadata.gz: f3a49b502f6f62c611ff8f700d4a84a2fe30e2a203a57a81964a2d99b005bd20ce431a93ba2319d7ac0dd1a358147d4bec97747b97ea3c386b2e27b5a4a4c241
7
+ data.tar.gz: 4c98f7b14919f9d56ec3a73e179be99f19cd2ec4157591bf3d1661cd5e8fd9a893110b4ba67dc8f0e79095b8d13974ed8a59904df41016f59515998316c03f2b
@@ -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`, assertion against the return values of `render_inline`, which is an instance of `Nokogiri::HTML::DocumentFragment`:
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
 
@@ -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
- before_render_check
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
- @compiled ||= false
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?(:annotate_template_file_names) &&
243
- ActionView::Base.annotate_template_file_names
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
- @compiled = true
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 instance_method(:initialize).parameters.map(&:last).include?(parameter)
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
- (Dir["#{source_location.chomp(File.extname(source_location))}.*{#{ActionView::Template.template_handler_extensions.join(',')}}"] - [source_location])
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(@raw)
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
- @raw = controller.view_context.render(component, args, &block)
23
+ @rendered_component = controller.view_context.render(component, args, &block)
22
24
 
23
- Nokogiri::HTML.fragment(@raw)
25
+ Nokogiri::HTML.fragment(@rendered_component)
24
26
  end
25
27
 
26
28
  def controller
@@ -3,7 +3,7 @@
3
3
  module ViewComponent
4
4
  module VERSION
5
5
  MAJOR = 2
6
- MINOR = 6
6
+ MINOR = 11
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.6.0
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-05-14 00:00:00.000000000 Z
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