view_component 2.27.0 → 2.31.1

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: 47f112ee86431b25865a4793374e8838a1e80966d91150d4b182b38c598a9631
4
- data.tar.gz: 97673827cb5a971d8c769b9566c87055d28af37fa04b06b6e90c5098b64c9388
3
+ metadata.gz: f29c10730d8ec00ec04c0a7236b5f0eefb56235012c866b9af8566f2b4d25a1b
4
+ data.tar.gz: e1ebe3cab15bb375740e012474aef4d31a4d44dbf5cfc302ad2248567b704009
5
5
  SHA512:
6
- metadata.gz: 538a828cd9096fd400cd3b3bc8fa4f63666003221161b22f59a008f62fa5f8d8b311d7152498ff5519004bd960c61d058912fc7241e537d129d9873a4b6c0b63
7
- data.tar.gz: 99de0a2aadb9eb873854b284e0be4f1aa2d20aa8262c5350b3473d536d6e40891d819dff74c73188b1106454a98299511b79e7c406ddebbe05dfdf8ebf69804b
6
+ metadata.gz: 479fc618baf4e945087b0738d0dcf0c621060a8f81f0916149c9f93be0cd7dc2f715fd1f5e45c2ecf365ed5db44bfa4c1e34c406bdfab443556f08c1aaabf2cb
7
+ data.tar.gz: '099ee8077b1d6c866710dc16abe53c9e9159c2966f9505bdf1492a370f411a4f242191feba37d0fb9e74d158b3f87b41e1cb2f812fb0da012ae7a93caccf4818'
data/CHANGELOG.md CHANGED
@@ -2,6 +2,87 @@
2
2
 
3
3
  ## main
4
4
 
5
+ ## 2.31.1
6
+
7
+ * Fix `DEPRECATION WARNING: before_render_check` when compiling `ViewComponent::Base`
8
+
9
+ *Dave Kroondyk*
10
+
11
+ ## 2.31.0
12
+
13
+ * Add `#with_content` to allow setting content without a block.
14
+
15
+ *Jordan Raine, Manuel Puyol*
16
+
17
+ * Add `with_request_url` test helper.
18
+
19
+ *Mario Schüttel*
20
+
21
+ * Improve feature parity with Rails translations
22
+ * Don't create a translation backend if the component has no translation file
23
+ * Mark translation keys ending with `html` as HTML-safe
24
+ * Always convert keys to String
25
+ * Support multiple keys
26
+
27
+ *Elia Schito*
28
+
29
+ * Fix errors on `asset_url` helpers when `asset_host` has no protocol.
30
+
31
+ *Elia Schito*
32
+
33
+ * Prevent slots from overriding the `#content` method when registering a slot with that name.
34
+
35
+ *Blake Williams*
36
+
37
+ * Deprecate `with_slot` in favor of the new [slots API](https://viewcomponent.org/guide/slots.html).
38
+
39
+ *Manuel Puyol*
40
+
41
+ ## 2.30.0
42
+
43
+ * Deprecate `with_content_areas` in favor of [slots](https://viewcomponent.org/guide/slots.html).
44
+
45
+ *Joel Hawksley*
46
+
47
+ ## 2.29.0
48
+
49
+ * Allow Slot lambdas to share data from the parent component and allow chaining on the returned component.
50
+
51
+ *Sjors Baltus, Blake Williams*
52
+
53
+ * Experimental: Add `ViewComponent::Translatable`
54
+ * `t` and `translate` now will look first into the sidecar YAML translations file.
55
+ * `helpers.t` and `I18n.t` still reference the global Rails translation files.
56
+ * `l` and `localize` will still reference the global Rails translation files.
57
+
58
+ *Elia Schito*
59
+
60
+ * Fix rendering output of pass through slots when using HAML.
61
+
62
+ *Alex Robbin, Blake Williams*
63
+
64
+ * Experimental: call `._sidecar_files` to fetch the sidecar files for a given list of extensions, e.g. passing `["yml", "yaml"]`.
65
+
66
+ *Elia Schito*
67
+
68
+ * Fix bug where a single `jbuilder` template matched multiple template handlers.
69
+
70
+ *Niels Slot*
71
+
72
+ ## 2.28.0
73
+
74
+ * Include SlotableV2 by default in Base. **Note:** It's no longer necessary to include `ViewComponent::SlotableV2` to use Slots.
75
+
76
+ *Joel Hawksley*
77
+
78
+ * Prepend Preview routes instead of appending, accounting for cases where host application has catchall route.
79
+
80
+ *Joel Hawksley*
81
+
82
+ * Fix bug where blocks passed to lambda slots will render incorrectly in certain situations.
83
+
84
+ *Blake Williams*
85
+
5
86
  ## 2.27.0
6
87
 
7
88
  * Allow customization of the controller used in component tests.
data/README.md CHANGED
@@ -6,14 +6,6 @@ A framework for building reusable, testable & encapsulated view components in Ru
6
6
 
7
7
  See [viewcomponent.org](https://viewcomponent.org/) for documentation.
8
8
 
9
- ## Installation
10
-
11
- In `Gemfile`, add:
12
-
13
- ```ruby
14
- gem "view_component", require: "view_component/engine"
15
- ```
16
-
17
9
  ## Contributing
18
10
 
19
11
  This project is intended to be a safe, welcoming space for collaboration. Contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct. We recommend reading the [contributing guide](./CONTRIBUTING.md) as well.
@@ -7,9 +7,11 @@ module ViewComponent
7
7
 
8
8
  autoload :Base
9
9
  autoload :Compiler
10
+ autoload :ComponentError
10
11
  autoload :Preview
11
12
  autoload :PreviewTemplateError
12
13
  autoload :TestHelpers
13
14
  autoload :TestCase
14
15
  autoload :TemplateError
16
+ autoload :Translatable
15
17
  end
@@ -7,11 +7,14 @@ require "view_component/compile_cache"
7
7
  require "view_component/previewable"
8
8
  require "view_component/slotable"
9
9
  require "view_component/slotable_v2"
10
+ require "view_component/with_content_helper"
10
11
 
11
12
  module ViewComponent
12
13
  class Base < ActionView::Base
13
14
  include ActiveSupport::Configurable
14
15
  include ViewComponent::Previewable
16
+ include ViewComponent::SlotableV2
17
+ include ViewComponent::WithContentHelper
15
18
 
16
19
  ViewContextCalledBeforeRenderError = Class.new(StandardError)
17
20
 
@@ -78,6 +81,8 @@ module ViewComponent
78
81
  old_current_template = @current_template
79
82
  @current_template = self
80
83
 
84
+ raise ArgumentError.new("Block provided after calling `with_content`. Use one or the other.") if block && defined?(@_content_set_by_with_content)
85
+
81
86
  @_content_evaluated = false
82
87
  @_render_in_block = block
83
88
 
@@ -130,7 +135,7 @@ module ViewComponent
130
135
  @helpers ||= controller.view_context
131
136
  end
132
137
 
133
- # Exposes .virutal_path as an instance method
138
+ # Exposes .virtual_path as an instance method
134
139
  def virtual_path
135
140
  self.class.virtual_path
136
141
  end
@@ -168,8 +173,6 @@ module ViewComponent
168
173
  self
169
174
  end
170
175
 
171
- private
172
-
173
176
  # Exposes the current request to the component.
174
177
  # Use sparingly as doing so introduces coupling
175
178
  # that inhibits encapsulation & reuse.
@@ -177,6 +180,8 @@ module ViewComponent
177
180
  @request ||= controller.request
178
181
  end
179
182
 
183
+ private
184
+
180
185
  attr_reader :view_context
181
186
 
182
187
  def content
@@ -185,6 +190,8 @@ module ViewComponent
185
190
 
186
191
  @_content = if @view_context && @_render_in_block
187
192
  view_context.capture(self, &@_render_in_block)
193
+ elsif defined?(@_content_set_by_with_content)
194
+ @_content_set_by_with_content
188
195
  end
189
196
  end
190
197
 
@@ -205,6 +212,47 @@ module ViewComponent
205
212
  class << self
206
213
  attr_accessor :source_location, :virtual_path
207
214
 
215
+ # EXPERIMENTAL: This API is experimental and may be removed at any time.
216
+ # Find sidecar files for the given extensions.
217
+ #
218
+ # The provided array of extensions is expected to contain
219
+ # strings starting without the "dot", example: `["erb", "haml"]`.
220
+ #
221
+ # For example, one might collect sidecar CSS files that need to be compiled.
222
+ def _sidecar_files(extensions)
223
+ return [] unless source_location
224
+
225
+ extensions = extensions.join(",")
226
+
227
+ # view files in a directory named like the component
228
+ directory = File.dirname(source_location)
229
+ filename = File.basename(source_location, ".rb")
230
+ component_name = name.demodulize.underscore
231
+
232
+ # Add support for nested components defined in the same file.
233
+ #
234
+ # e.g.
235
+ #
236
+ # class MyComponent < ViewComponent::Base
237
+ # class MyOtherComponent < ViewComponent::Base
238
+ # end
239
+ # end
240
+ #
241
+ # Without this, `MyOtherComponent` will not look for `my_component/my_other_component.html.erb`
242
+ nested_component_files = if name.include?("::") && component_name != filename
243
+ Dir["#{directory}/#{filename}/#{component_name}.*{#{extensions}}"]
244
+ else
245
+ []
246
+ end
247
+
248
+ # view files in the same directory as the component
249
+ sidecar_files = Dir["#{directory}/#{component_name}.*{#{extensions}}"]
250
+
251
+ sidecar_directory_files = Dir["#{directory}/#{component_name}/#{filename}.*{#{extensions}}"]
252
+
253
+ (sidecar_files - [source_location] + sidecar_directory_files + nested_component_files).uniq
254
+ end
255
+
208
256
  # Render a component collection.
209
257
  def with_collection(collection, **args)
210
258
  Collection.new(self, collection, **args)
@@ -238,7 +286,7 @@ module ViewComponent
238
286
  end
239
287
 
240
288
  def compiled?
241
- template_compiler.compiled?
289
+ compiler.compiled?
242
290
  end
243
291
 
244
292
  # Compile templates to instance methods, assuming they haven't been compiled already.
@@ -246,11 +294,11 @@ module ViewComponent
246
294
  # Do as much work as possible in this step, as doing so reduces the amount
247
295
  # of work done each time a component is rendered.
248
296
  def compile(raise_errors: false)
249
- template_compiler.compile(raise_errors: raise_errors)
297
+ compiler.compile(raise_errors: raise_errors)
250
298
  end
251
299
 
252
- def template_compiler
253
- @_template_compiler ||= Compiler.new(self)
300
+ def compiler
301
+ @_compiler ||= Compiler.new(self)
254
302
  end
255
303
 
256
304
  # we'll eventually want to update this to support other types
@@ -267,6 +315,11 @@ module ViewComponent
267
315
  end
268
316
 
269
317
  def with_content_areas(*areas)
318
+ ActiveSupport::Deprecation.warn(
319
+ "`with_content_areas` is deprecated and will be removed in ViewComponent v3.0.0.\n" \
320
+ "Use slots (https://viewcomponent.org/guide/slots.html) instead."
321
+ )
322
+
270
323
  if areas.include?(:content)
271
324
  raise ArgumentError.new ":content is a reserved content area name. Please use another name, such as ':body'"
272
325
  end
@@ -318,7 +371,7 @@ module ViewComponent
318
371
  def validate_initialization_parameters!
319
372
  return unless initialize_parameter_names.include?(RESERVED_PARAMETER)
320
373
 
321
- raise ArgumentError.new(
374
+ raise ViewComponent::ComponentError.new(
322
375
  "#{self} initializer cannot contain " \
323
376
  "`#{RESERVED_PARAMETER}` since it will override a " \
324
377
  "public ViewComponent method."
@@ -338,7 +391,7 @@ module ViewComponent
338
391
  end
339
392
 
340
393
  def counter_argument_present?
341
- instance_method(:initialize).parameters.map(&:second).include?(collection_counter_parameter)
394
+ initialize_parameter_names.include?(collection_counter_parameter)
342
395
  end
343
396
 
344
397
  private
@@ -13,12 +13,18 @@ module ViewComponent
13
13
  def compile(raise_errors: false)
14
14
  return if compiled?
15
15
 
16
+ subclass_instance_methods = component_class.instance_methods(false)
17
+
18
+ if subclass_instance_methods.include?(:with_content) && raise_errors
19
+ raise ViewComponent::ComponentError.new("#{component_class} implements a reserved method, `with_content`.")
20
+ end
21
+
16
22
  if template_errors.present?
17
23
  raise ViewComponent::TemplateError.new(template_errors) if raise_errors
18
24
  return false
19
25
  end
20
26
 
21
- if component_class.instance_methods(false).include?(:before_render_check)
27
+ if subclass_instance_methods.include?(:before_render_check)
22
28
  ActiveSupport::Deprecation.warn(
23
29
  "`before_render_check` will be removed in v3.0.0. Use `before_render` instead."
24
30
  )
@@ -61,7 +67,7 @@ module ViewComponent
61
67
  "elsif variant.to_sym == :#{variant}\n #{call_method_name(variant)}"
62
68
  end.join("\n")
63
69
 
64
- component_class.class_eval <<-RUBY
70
+ component_class.class_eval <<-RUBY, __FILE__, __LINE__ + 1
65
71
  def render_template_for(variant = nil)
66
72
  if variant.nil?
67
73
  call
@@ -114,50 +120,18 @@ module ViewComponent
114
120
  end
115
121
 
116
122
  def templates
117
- @templates ||= matching_views_in_source_location.each_with_object([]) do |path, memo|
118
- pieces = File.basename(path).split(".")
119
-
120
- memo << {
121
- path: path,
122
- variant: pieces.second.split("+").second&.to_sym,
123
- handler: pieces.last
124
- }
125
- end
126
- end
127
-
128
- def matching_views_in_source_location
129
- source_location = component_class.source_location
130
- return [] unless source_location
131
-
132
- extensions = ActionView::Template.template_handler_extensions.join(",")
133
-
134
- # view files in a directory named like the component
135
- directory = File.dirname(source_location)
136
- filename = File.basename(source_location, ".rb")
137
- component_name = component_class.name.demodulize.underscore
138
-
139
- # Add support for nested components defined in the same file.
140
- #
141
- # e.g.
142
- #
143
- # class MyComponent < ViewComponent::Base
144
- # class MyOtherComponent < ViewComponent::Base
145
- # end
146
- # end
147
- #
148
- # Without this, `MyOtherComponent` will not look for `my_component/my_other_component.html.erb`
149
- nested_component_files = if component_class.name.include?("::") && component_name != filename
150
- Dir["#{directory}/#{filename}/#{component_name}.*{#{extensions}}"]
151
- else
152
- []
123
+ @templates ||= begin
124
+ extensions = ActionView::Template.template_handler_extensions
125
+
126
+ component_class._sidecar_files(extensions).each_with_object([]) do |path, memo|
127
+ pieces = File.basename(path).split(".")
128
+ memo << {
129
+ path: path,
130
+ variant: pieces.second.split("+").second&.to_sym,
131
+ handler: pieces.last
132
+ }
133
+ end
153
134
  end
154
-
155
- # view files in the same directory as the component
156
- sidecar_files = Dir["#{directory}/#{component_name}.*{#{extensions}}"]
157
-
158
- sidecar_directory_files = Dir["#{directory}/#{component_name}/#{filename}.*{#{extensions}}"]
159
-
160
- (sidecar_files - [source_location] + sidecar_directory_files + nested_component_files)
161
135
  end
162
136
 
163
137
  def inline_calls
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ViewComponent
4
+ class ComponentError < StandardError
5
+ end
6
+ end
@@ -90,7 +90,7 @@ module ViewComponent
90
90
  options = app.config.view_component
91
91
 
92
92
  if options.show_previews
93
- app.routes.append do
93
+ app.routes.prepend do
94
94
  preview_controller = options.preview_controller.sub(/Controller$/, "").underscore
95
95
 
96
96
  get options.preview_route, to: "#{preview_controller}#index", as: :preview_view_components, internal: true
@@ -1,7 +1,11 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "view_component/with_content_helper"
4
+
3
5
  module ViewComponent
4
6
  class SlotV2
7
+ include ViewComponent::WithContentHelper
8
+
5
9
  attr_writer :_component_instance, :_content_block, :_content
6
10
 
7
11
  def initialize(parent)
@@ -25,19 +29,32 @@ module ViewComponent
25
29
  return @content if defined?(@content)
26
30
 
27
31
  view_context = @parent.send(:view_context)
28
- @content = view_context.capture do
29
- if defined?(@_component_instance)
30
- # render_in is faster than `parent.render`
31
- if defined?(@_content_block)
32
- @_component_instance.render_in(view_context, &@_content_block)
33
- else
32
+
33
+ raise ArgumentError.new("Block provided after calling `with_content`. Use one or the other.") if defined?(@_content_block) && defined?(@_content_set_by_with_content)
34
+
35
+ @content = if defined?(@_component_instance)
36
+ if defined?(@_content_set_by_with_content)
37
+ @_component_instance.with_content(@_content_set_by_with_content)
38
+
39
+ view_context.capture do
34
40
  @_component_instance.render_in(view_context)
35
41
  end
36
- elsif defined?(@_content)
37
- @_content
38
42
  elsif defined?(@_content_block)
39
- @_content_block.call
43
+ view_context.capture do
44
+ # render_in is faster than `parent.render`
45
+ @_component_instance.render_in(view_context, &@_content_block)
46
+ end
47
+ else
48
+ view_context.capture do
49
+ @_component_instance.render_in(view_context)
50
+ end
40
51
  end
52
+ elsif defined?(@_content)
53
+ @_content
54
+ elsif defined?(@_content_block)
55
+ view_context.capture(&@_content_block)
56
+ elsif defined?(@_content_set_by_with_content)
57
+ @_content_set_by_with_content
41
58
  end
42
59
 
43
60
  @content
@@ -23,6 +23,11 @@ module ViewComponent
23
23
  # class_name: "Header" # class name string, used to instantiate Slot
24
24
  # )
25
25
  def with_slot(*slot_names, collection: false, class_name: nil)
26
+ ActiveSupport::Deprecation.warn(
27
+ "`with_slot` is deprecated and will be removed in ViewComponent v3.0.0.\n" \
28
+ "Use the new slots API (https://viewcomponent.org/guide/slots.html) instead."
29
+ )
30
+
26
31
  slot_names.each do |slot_name|
27
32
  # Ensure slot_name is not already declared
28
33
  if self.slots.key?(slot_name)
@@ -49,14 +54,14 @@ module ViewComponent
49
54
 
50
55
  # If the slot is a collection, define an accesor that defaults to an empty array
51
56
  if collection
52
- class_eval <<-RUBY
57
+ class_eval <<-RUBY, __FILE__, __LINE__ + 1
53
58
  def #{accessor_name}
54
59
  content unless content_evaluated? # ensure content is loaded so slots will be defined
55
60
  #{instance_variable_name} ||= []
56
61
  end
57
62
  RUBY
58
63
  else
59
- class_eval <<-RUBY
64
+ class_eval <<-RUBY, __FILE__, __LINE__ + 1
60
65
  def #{accessor_name}
61
66
  content unless content_evaluated? # ensure content is loaded so slots will be defined
62
67
  #{instance_variable_name} if defined?(#{instance_variable_name})
@@ -175,6 +175,10 @@ module ViewComponent
175
175
  end
176
176
 
177
177
  def validate_slot_name(slot_name)
178
+ if slot_name.to_sym == :content
179
+ raise ArgumentError.new("#{slot_name} is not a valid slot name.")
180
+ end
181
+
178
182
  if self.registered_slots.key?(slot_name)
179
183
  # TODO remove? This breaks overriding slots when slots are inherited
180
184
  raise ArgumentError.new("#{slot_name} slot declared multiple times")
@@ -226,7 +230,13 @@ module ViewComponent
226
230
  # Use `bind(self)` to ensure lambda is executed in the context of the
227
231
  # current component. This is necessary to allow the lambda to access helper
228
232
  # methods like `content_tag` as well as parent component state.
229
- renderable_value = slot_definition[:renderable_function].bind(self).call(*args, **kwargs, &block)
233
+ renderable_value = if block_given?
234
+ slot_definition[:renderable_function].bind(self).call(*args, **kwargs) do |*args, **kwargs|
235
+ view_context.capture(*args, **kwargs, &block)
236
+ end
237
+ else
238
+ slot_definition[:renderable_function].bind(self).call(*args, **kwargs)
239
+ end
230
240
 
231
241
  # Function calls can return components, so if it's a component handle it specially
232
242
  if renderable_value.respond_to?(:render_in)
@@ -245,7 +255,7 @@ module ViewComponent
245
255
  @_set_slots[slot_name] = slot
246
256
  end
247
257
 
248
- nil
258
+ slot
249
259
  end
250
260
  end
251
261
  end
@@ -60,6 +60,17 @@ module ViewComponent
60
60
  @controller = old_controller
61
61
  end
62
62
 
63
+ def with_request_url(path)
64
+ old_request_path_parameters = request.path_parameters
65
+ old_controller = defined?(@controller) && @controller
66
+
67
+ request.path_parameters = Rails.application.routes.recognize_path(path)
68
+ yield
69
+ ensure
70
+ request.path_parameters = old_request_path_parameters
71
+ @controller = old_controller
72
+ end
73
+
63
74
  def build_controller(klass)
64
75
  klass.new.tap { |c| c.request = request }.extend(Rails.application.routes.url_helpers)
65
76
  end
@@ -0,0 +1,95 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "set"
4
+ require "i18n"
5
+ require "action_view/helpers/translation_helper"
6
+ require "active_support/concern"
7
+
8
+ module ViewComponent
9
+ module Translatable
10
+ extend ActiveSupport::Concern
11
+
12
+ HTML_SAFE_TRANSLATION_KEY = /(?:_|\b)html\z/.freeze
13
+
14
+ included do
15
+ class_attribute :i18n_backend, instance_writer: false, instance_predicate: false
16
+ end
17
+
18
+ class_methods do
19
+ def i18n_scope
20
+ @i18n_scope ||= virtual_path.sub(%r{^/}, "").gsub(%r{/_?}, ".")
21
+ end
22
+
23
+ def _after_compile
24
+ super
25
+
26
+ return if CompileCache.compiled? self
27
+
28
+ if (translation_files = _sidecar_files(%w[yml yaml])).any?
29
+ self.i18n_backend = I18nBackend.new(
30
+ i18n_scope: i18n_scope,
31
+ load_paths: translation_files,
32
+ )
33
+ else
34
+ # Cleanup if translations file has been removed since the last compilation
35
+ self.i18n_backend = nil
36
+ end
37
+ end
38
+ end
39
+
40
+ class I18nBackend < ::I18n::Backend::Simple
41
+ EMPTY_HASH = {}.freeze
42
+
43
+ def initialize(i18n_scope:, load_paths:)
44
+ @i18n_scope = i18n_scope.split(".")
45
+ @load_paths = load_paths
46
+ end
47
+
48
+ # Ensure the Simple backend won't load paths from ::I18n.load_path
49
+ def load_translations
50
+ super(@load_paths)
51
+ end
52
+
53
+ def scope_data(data)
54
+ @i18n_scope.reverse_each do |part|
55
+ data = { part => data}
56
+ end
57
+ data
58
+ end
59
+
60
+ def store_translations(locale, data, options = EMPTY_HASH)
61
+ super(locale, scope_data(data), options)
62
+ end
63
+ end
64
+
65
+ def translate(key = nil, **options)
66
+ return super unless i18n_backend
67
+ return key.map { |k| translate(k, **options) } if key.is_a?(Array)
68
+
69
+ locale = options.delete(:locale) || ::I18n.locale
70
+ key = key&.to_s unless key.is_a?(String)
71
+ key = "#{i18n_scope}#{key}" if key.start_with?(".")
72
+
73
+ translated = catch(:exception) do
74
+ i18n_backend.translate(locale, key, options)
75
+ end
76
+
77
+ # Fallback to the global translations
78
+ if translated.is_a? ::I18n::MissingTranslation
79
+ return super(key, locale: locale, **options)
80
+ end
81
+
82
+ if HTML_SAFE_TRANSLATION_KEY.match?(key)
83
+ translated = translated.html_safe
84
+ end
85
+
86
+ translated
87
+ end
88
+ alias :t :translate
89
+
90
+ # Exposes .i18n_scope as an instance method
91
+ def i18n_scope
92
+ self.class.i18n_scope
93
+ end
94
+ end
95
+ end
@@ -3,9 +3,11 @@
3
3
  module ViewComponent
4
4
  module VERSION
5
5
  MAJOR = 2
6
- MINOR = 27
7
- PATCH = 0
6
+ MINOR = 31
7
+ PATCH = 1
8
8
 
9
9
  STRING = [MAJOR, MINOR, PATCH].join(".")
10
10
  end
11
11
  end
12
+
13
+ puts ViewComponent::VERSION::STRING if __FILE__ == $PROGRAM_NAME
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ViewComponent
4
+ module WithContentHelper
5
+ def with_content(value)
6
+ if value.nil?
7
+ raise ArgumentError.new("No content provided.")
8
+ else
9
+ @_content_set_by_with_content = value
10
+ end
11
+
12
+ self
13
+ end
14
+ end
15
+ end
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.27.0
4
+ version: 2.31.1
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: 2021-03-08 00:00:00.000000000 Z
11
+ date: 2021-04-27 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -128,6 +128,20 @@ dependencies:
128
128
  - - "~>"
129
129
  - !ruby/object:Gem::Version
130
130
  version: '1'
131
+ - !ruby/object:Gem::Dependency
132
+ name: jbuilder
133
+ requirement: !ruby/object:Gem::Requirement
134
+ requirements:
135
+ - - "~>"
136
+ - !ruby/object:Gem::Version
137
+ version: '2'
138
+ type: :development
139
+ prerelease: false
140
+ version_requirements: !ruby/object:Gem::Requirement
141
+ requirements:
142
+ - - "~>"
143
+ - !ruby/object:Gem::Version
144
+ version: '2'
131
145
  - !ruby/object:Gem::Dependency
132
146
  name: rubocop
133
147
  requirement: !ruby/object:Gem::Requirement
@@ -232,6 +246,7 @@ files:
232
246
  - lib/view_component/collection.rb
233
247
  - lib/view_component/compile_cache.rb
234
248
  - lib/view_component/compiler.rb
249
+ - lib/view_component/component_error.rb
235
250
  - lib/view_component/engine.rb
236
251
  - lib/view_component/preview.rb
237
252
  - lib/view_component/preview_template_error.rb
@@ -249,7 +264,9 @@ files:
249
264
  - lib/view_component/template_error.rb
250
265
  - lib/view_component/test_case.rb
251
266
  - lib/view_component/test_helpers.rb
267
+ - lib/view_component/translatable.rb
252
268
  - lib/view_component/version.rb
269
+ - lib/view_component/with_content_helper.rb
253
270
  homepage: https://github.com/github/view_component
254
271
  licenses:
255
272
  - MIT