view_component 2.49.1 → 3.23.2

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.
Files changed (63) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE.txt +1 -1
  3. data/app/assets/vendor/prism.css +3 -195
  4. data/app/assets/vendor/prism.min.js +11 -11
  5. data/app/controllers/concerns/view_component/preview_actions.rb +108 -0
  6. data/app/controllers/view_components_controller.rb +1 -87
  7. data/app/controllers/view_components_system_test_controller.rb +30 -0
  8. data/app/helpers/preview_helper.rb +30 -12
  9. data/app/views/view_components/_preview_source.html.erb +3 -3
  10. data/app/views/view_components/preview.html.erb +2 -2
  11. data/docs/CHANGELOG.md +1653 -24
  12. data/lib/rails/generators/abstract_generator.rb +16 -10
  13. data/lib/rails/generators/component/component_generator.rb +8 -4
  14. data/lib/rails/generators/component/templates/component.rb.tt +3 -2
  15. data/lib/rails/generators/erb/component_generator.rb +1 -1
  16. data/lib/rails/generators/locale/component_generator.rb +4 -4
  17. data/lib/rails/generators/preview/component_generator.rb +17 -3
  18. data/lib/rails/generators/preview/templates/component_preview.rb.tt +5 -1
  19. data/lib/rails/generators/rspec/component_generator.rb +15 -3
  20. data/lib/rails/generators/rspec/templates/component_spec.rb.tt +3 -1
  21. data/lib/rails/generators/stimulus/component_generator.rb +8 -3
  22. data/lib/rails/generators/stimulus/templates/component_controller.ts.tt +9 -0
  23. data/lib/rails/generators/test_unit/templates/component_test.rb.tt +3 -1
  24. data/lib/view_component/base.rb +352 -196
  25. data/lib/view_component/capture_compatibility.rb +44 -0
  26. data/lib/view_component/collection.rb +28 -9
  27. data/lib/view_component/compiler.rb +162 -193
  28. data/lib/view_component/config.rb +225 -0
  29. data/lib/view_component/configurable.rb +17 -0
  30. data/lib/view_component/deprecation.rb +8 -0
  31. data/lib/view_component/engine.rb +74 -47
  32. data/lib/view_component/errors.rb +240 -0
  33. data/lib/view_component/inline_template.rb +55 -0
  34. data/lib/view_component/instrumentation.rb +10 -2
  35. data/lib/view_component/preview.rb +21 -19
  36. data/lib/view_component/rails/tasks/view_component.rake +11 -2
  37. data/lib/view_component/render_component_helper.rb +1 -0
  38. data/lib/view_component/render_component_to_string_helper.rb +1 -1
  39. data/lib/view_component/render_to_string_monkey_patch.rb +1 -1
  40. data/lib/view_component/rendering_component_helper.rb +1 -1
  41. data/lib/view_component/rendering_monkey_patch.rb +1 -1
  42. data/lib/view_component/slot.rb +119 -1
  43. data/lib/view_component/slotable.rb +393 -96
  44. data/lib/view_component/slotable_default.rb +20 -0
  45. data/lib/view_component/system_test_case.rb +13 -0
  46. data/lib/view_component/system_test_helpers.rb +27 -0
  47. data/lib/view_component/template.rb +134 -0
  48. data/lib/view_component/test_helpers.rb +208 -47
  49. data/lib/view_component/translatable.rb +51 -33
  50. data/lib/view_component/use_helpers.rb +42 -0
  51. data/lib/view_component/version.rb +5 -4
  52. data/lib/view_component/with_content_helper.rb +3 -8
  53. data/lib/view_component.rb +7 -12
  54. metadata +339 -57
  55. data/lib/rails/generators/component/USAGE +0 -13
  56. data/lib/view_component/content_areas.rb +0 -57
  57. data/lib/view_component/polymorphic_slots.rb +0 -73
  58. data/lib/view_component/preview_template_error.rb +0 -6
  59. data/lib/view_component/previewable.rb +0 -62
  60. data/lib/view_component/slot_v2.rb +0 -104
  61. data/lib/view_component/slotable_v2.rb +0 -307
  62. data/lib/view_component/template_error.rb +0 -9
  63. data/lib/yard/mattr_accessor_handler.rb +0 -19
@@ -1,57 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "active_support/concern"
4
-
5
- require "view_component/slot"
6
-
7
- # DEPRECATED - ContentAreas is deprecated and will be removed in v3.0.0
8
- module ViewComponent
9
- module ContentAreas
10
- extend ActiveSupport::Concern
11
-
12
- # Assign the provided content to the content area accessor
13
- #
14
- # @private
15
- def with(area, content = nil, &block)
16
- unless content_areas.include?(area)
17
- raise ArgumentError.new(
18
- "Unknown content_area '#{area}' for #{self} - expected one of '#{content_areas}'.\n\n" \
19
- "To fix this issue, add `with_content_area :#{area}` to #{self} or reference " \
20
- "a valid content area."
21
- )
22
- end
23
-
24
- if block_given?
25
- content = view_context.capture(&block)
26
- end
27
-
28
- instance_variable_set("@#{area}".to_sym, content)
29
- nil
30
- end
31
-
32
- class_methods do
33
- def with_content_areas(*areas)
34
- ActiveSupport::Deprecation.warn(
35
- "`with_content_areas` is deprecated and will be removed in ViewComponent v3.0.0.\n\n" \
36
- "Use slots (https://viewcomponent.org/guide/slots.html) instead."
37
- )
38
-
39
- if areas.include?(:content)
40
- raise ArgumentError.new(
41
- "#{self} defines a content area called :content, which is a reserved name. \n\n" \
42
- "To fix this issue, use another name, such as `:body`."
43
- )
44
- end
45
-
46
- areas.each do |area|
47
- define_method area.to_sym do
48
- content unless content_evaluated? # ensure content is loaded so content_areas will be defined
49
- instance_variable_get(:"@#{area}") if instance_variable_defined?(:"@#{area}")
50
- end
51
- end
52
-
53
- self.content_areas = areas
54
- end
55
- end
56
- end
57
- end
@@ -1,73 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module ViewComponent
4
- module PolymorphicSlots
5
- # In older rails versions, using a concern isn't a good idea here because they appear to not work with
6
- # Module#prepend and class methods.
7
- def self.included(base)
8
- base.singleton_class.prepend(ClassMethods)
9
- base.include(InstanceMethods)
10
- end
11
-
12
- module ClassMethods
13
- def renders_one(slot_name, callable = nil)
14
- return super unless callable.is_a?(Hash) && callable.key?(:types)
15
-
16
- validate_singular_slot_name(slot_name)
17
- register_polymorphic_slot(slot_name, callable[:types], collection: false)
18
- end
19
-
20
- def renders_many(slot_name, callable = nil)
21
- return super unless callable.is_a?(Hash) && callable.key?(:types)
22
-
23
- validate_plural_slot_name(slot_name)
24
- register_polymorphic_slot(slot_name, callable[:types], collection: true)
25
- end
26
-
27
- def register_polymorphic_slot(slot_name, types, collection:)
28
- renderable_hash = types.each_with_object({}) do |(poly_type, poly_callable), memo|
29
- memo[poly_type] = define_slot(
30
- "#{slot_name}_#{poly_type}", collection: collection, callable: poly_callable
31
- )
32
-
33
- getter_name = slot_name
34
- setter_name =
35
- if collection
36
- "#{ActiveSupport::Inflector.singularize(slot_name)}_#{poly_type}"
37
- else
38
- "#{slot_name}_#{poly_type}"
39
- end
40
-
41
- define_method(getter_name) do
42
- get_slot(slot_name)
43
- end
44
-
45
- define_method(setter_name) do |*args, &block|
46
- set_polymorphic_slot(slot_name, poly_type, *args, &block)
47
- end
48
- ruby2_keywords(setter_name.to_sym) if respond_to?(:ruby2_keywords, true)
49
- end
50
-
51
- self.registered_slots[slot_name] = {
52
- collection: collection,
53
- renderable_hash: renderable_hash
54
- }
55
- end
56
- end
57
-
58
- module InstanceMethods
59
- def set_polymorphic_slot(slot_name, poly_type = nil, *args, &block)
60
- slot_definition = self.class.registered_slots[slot_name]
61
-
62
- if !slot_definition[:collection] && get_slot(slot_name)
63
- raise ArgumentError, "content for slot '#{slot_name}' has already been provided"
64
- end
65
-
66
- poly_def = slot_definition[:renderable_hash][poly_type]
67
-
68
- set_slot(slot_name, poly_def, *args, &block)
69
- end
70
- ruby2_keywords(:set_polymorphic_slot) if respond_to?(:ruby2_keywords, true)
71
- end
72
- end
73
- end
@@ -1,6 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module ViewComponent
4
- class PreviewTemplateError < StandardError
5
- end
6
- end
@@ -1,62 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "active_support/concern"
4
-
5
- module ViewComponent
6
- module Previewable
7
- extend ActiveSupport::Concern
8
-
9
- included do
10
- # Enable or disable component previews:
11
- #
12
- # config.view_component.show_previews = true
13
- #
14
- # Defaults to `true` in development.
15
- #
16
- mattr_accessor :show_previews, instance_writer: false
17
-
18
- # Enable or disable source code previews in component previews:
19
- #
20
- # config.view_component.show_previews_source = true
21
- #
22
- # Defaults to `false`.
23
- #
24
- mattr_accessor :show_previews_source, instance_writer: false, default: false
25
-
26
- # Set a custom default layout used for preview index and individual previews:
27
- #
28
- # config.view_component.default_preview_layout = "component_preview"
29
- #
30
- mattr_accessor :default_preview_layout, instance_writer: false
31
-
32
- # Set the location of component previews:
33
- #
34
- # config.view_component.preview_paths << "#{Rails.root}/lib/component_previews"
35
- #
36
- mattr_accessor :preview_paths, instance_writer: false
37
-
38
- # @deprecated Use `preview_paths` instead. Will be removed in v3.0.0.
39
- mattr_accessor :preview_path, instance_writer: false
40
-
41
- # Set the entry route for component previews:
42
- #
43
- # config.view_component.preview_route = "/previews"
44
- #
45
- # Defaults to `/rails/view_components` when `show_previews` is enabled.
46
- #
47
- mattr_accessor :preview_route, instance_writer: false do
48
- "/rails/view_components"
49
- end
50
-
51
- # Set the controller used for previewing components:
52
- #
53
- # config.view_component.preview_controller = "MyPreviewController"
54
- #
55
- # Defaults to `ViewComponentsController`.
56
- #
57
- mattr_accessor :preview_controller, instance_writer: false do
58
- "ViewComponentsController"
59
- end
60
- end
61
- end
62
- end
@@ -1,104 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "view_component/with_content_helper"
4
-
5
- module ViewComponent
6
- class SlotV2
7
- include ViewComponent::WithContentHelper
8
-
9
- attr_writer :__vc_component_instance, :__vc_content_block, :__vc_content
10
-
11
- def initialize(parent)
12
- @parent = parent
13
- end
14
-
15
- # Used to render the slot content in the template
16
- #
17
- # There's currently 3 different values that may be set, that we can render.
18
- #
19
- # If the slot renderable is a component, the string class name of a
20
- # component, or a function that returns a component, we render that
21
- # component instance, returning the string.
22
- #
23
- # If the slot renderable is a function and returns a string, it's
24
- # set as `@__vc_content` and is returned directly.
25
- #
26
- # If there is no slot renderable, we evaluate the block passed to
27
- # the slot and return it.
28
- def to_s
29
- return @content if defined?(@content)
30
-
31
- view_context = @parent.send(:view_context)
32
-
33
- if defined?(@__vc_content_block) && defined?(@__vc_content_set_by_with_content)
34
- raise ArgumentError.new(
35
- "It looks like a block was provided after calling `with_content` on #{self.class.name}, " \
36
- "which means that ViewComponent doesn't know which content to use.\n\n" \
37
- "To fix this issue, use either `with_content` or a block."
38
- )
39
- end
40
-
41
- @content =
42
- if defined?(@__vc_component_instance)
43
- @__vc_component_instance.__vc_original_view_context = @parent.__vc_original_view_context
44
-
45
- if defined?(@__vc_content_set_by_with_content)
46
- @__vc_component_instance.with_content(@__vc_content_set_by_with_content)
47
-
48
- view_context.capture do
49
- @__vc_component_instance.render_in(view_context)
50
- end
51
- elsif defined?(@__vc_content_block)
52
- view_context.capture do
53
- # render_in is faster than `parent.render`
54
- @__vc_component_instance.render_in(view_context, &@__vc_content_block)
55
- end
56
- else
57
- view_context.capture do
58
- @__vc_component_instance.render_in(view_context)
59
- end
60
- end
61
- elsif defined?(@__vc_content)
62
- @__vc_content
63
- elsif defined?(@__vc_content_block)
64
- view_context.capture(&@__vc_content_block)
65
- elsif defined?(@__vc_content_set_by_with_content)
66
- @__vc_content_set_by_with_content
67
- end
68
-
69
- @content = @content.to_s
70
- end
71
-
72
- # Allow access to public component methods via the wrapper
73
- #
74
- # for example
75
- #
76
- # calling `header.name` (where `header` is a slot) will call `name`
77
- # on the `HeaderComponent` instance.
78
- #
79
- # Where the component may look like:
80
- #
81
- # class MyComponent < ViewComponent::Base
82
- # has_one :header, HeaderComponent
83
- #
84
- # class HeaderComponent < ViewComponent::Base
85
- # def name
86
- # @name
87
- # end
88
- # end
89
- # end
90
- #
91
- def method_missing(symbol, *args, &block)
92
- @__vc_component_instance.public_send(symbol, *args, &block)
93
- end
94
- ruby2_keywords(:method_missing) if respond_to?(:ruby2_keywords, true)
95
-
96
- def html_safe?
97
- to_s.html_safe?
98
- end
99
-
100
- def respond_to_missing?(symbol, include_all = false)
101
- defined?(@__vc_component_instance) && @__vc_component_instance.respond_to?(symbol, include_all)
102
- end
103
- end
104
- end
@@ -1,307 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "active_support/concern"
4
- require "view_component/slot_v2"
5
-
6
- module ViewComponent
7
- module SlotableV2
8
- extend ActiveSupport::Concern
9
-
10
- # Setup component slot state
11
- included do
12
- # Hash of registered Slots
13
- class_attribute :registered_slots
14
- self.registered_slots = {}
15
- end
16
-
17
- class_methods do
18
- ##
19
- # Registers a sub-component
20
- #
21
- # = Example
22
- #
23
- # renders_one :header -> (classes:) do
24
- # HeaderComponent.new(classes: classes)
25
- # end
26
- #
27
- # # OR
28
- #
29
- # renders_one :header, HeaderComponent
30
- #
31
- # where `HeaderComponent` is defined as:
32
- #
33
- # class HeaderComponent < ViewComponent::Base
34
- # def initialize(classes:)
35
- # @classes = classes
36
- # end
37
- # end
38
- #
39
- # and has the following template:
40
- #
41
- # <header class="<%= @classes %>">
42
- # <%= content %>
43
- # </header>
44
- #
45
- # = Rendering sub-component content
46
- #
47
- # The component's sidecar template can access the sub-component by calling a
48
- # helper method with the same name as the sub-component.
49
- #
50
- # <h1>
51
- # <%= header do %>
52
- # My header title
53
- # <% end %>
54
- # </h1>
55
- #
56
- # = Setting sub-component content
57
- #
58
- # Consumers of the component can render a sub-component by calling a
59
- # helper method with the same name as the slot.
60
- #
61
- # <%= render_inline(MyComponent.new) do |component| %>
62
- # <% component.header(classes: "Foo") do %>
63
- # <p>Bar</p>
64
- # <% end %>
65
- # <% end %>
66
- def renders_one(slot_name, callable = nil)
67
- validate_singular_slot_name(slot_name)
68
-
69
- define_method slot_name do |*args, &block|
70
- if args.empty? && block.nil?
71
- get_slot(slot_name)
72
- else
73
- set_slot(slot_name, nil, *args, &block)
74
- end
75
- end
76
- ruby2_keywords(slot_name.to_sym) if respond_to?(:ruby2_keywords, true)
77
-
78
- register_slot(slot_name, collection: false, callable: callable)
79
- end
80
-
81
- ##
82
- # Registers a collection sub-component
83
- #
84
- # = Example
85
- #
86
- # render_many :items, -> (name:) { ItemComponent.new(name: name }
87
- #
88
- # # OR
89
- #
90
- # render_many :items, ItemComponent
91
- #
92
- # = Rendering sub-components
93
- #
94
- # The component's sidecar template can access the slot by calling a
95
- # helper method with the same name as the slot.
96
- #
97
- # <h1>
98
- # <% items.each do |item| %>
99
- # <%= item %>
100
- # <% end %>
101
- # </h1>
102
- #
103
- # = Setting sub-component content
104
- #
105
- # Consumers of the component can set the content of a slot by calling a
106
- # helper method with the same name as the slot. The method can be
107
- # called multiple times to append to the slot.
108
- #
109
- # <%= render_inline(MyComponent.new) do |component| %>
110
- # <% component.item(name: "Foo") do %>
111
- # <p>One</p>
112
- # <% end %>
113
- #
114
- # <% component.item(name: "Bar") do %>
115
- # <p>two</p>
116
- # <% end %>
117
- # <% end %>
118
- def renders_many(slot_name, callable = nil)
119
- validate_plural_slot_name(slot_name)
120
-
121
- singular_name = ActiveSupport::Inflector.singularize(slot_name)
122
-
123
- # Define setter for singular names
124
- # for example `renders_many :items` allows fetching all tabs with
125
- # `component.tabs` and setting a tab with `component.tab`
126
- define_method singular_name do |*args, &block|
127
- set_slot(slot_name, nil, *args, &block)
128
- end
129
- ruby2_keywords(singular_name.to_sym) if respond_to?(:ruby2_keywords, true)
130
-
131
- # Instantiates and and adds multiple slots forwarding the first
132
- # argument to each slot constructor
133
- define_method slot_name do |collection_args = nil, &block|
134
- if collection_args.nil? && block.nil?
135
- get_slot(slot_name)
136
- else
137
- collection_args.map do |args|
138
- set_slot(slot_name, nil, **args, &block)
139
- end
140
- end
141
- end
142
-
143
- register_slot(slot_name, collection: true, callable: callable)
144
- end
145
-
146
- def slot_type(slot_name)
147
- registered_slot = registered_slots[slot_name]
148
- if registered_slot
149
- registered_slot[:collection] ? :collection : :single
150
- else
151
- plural_slot_name = ActiveSupport::Inflector.pluralize(slot_name).to_sym
152
- plural_registered_slot = registered_slots[plural_slot_name]
153
- plural_registered_slot&.fetch(:collection) ? :collection_item : nil
154
- end
155
- end
156
-
157
- # Clone slot configuration into child class
158
- # see #test_slots_pollution
159
- def inherited(child)
160
- child.registered_slots = self.registered_slots.clone
161
- super
162
- end
163
-
164
- private
165
-
166
- def register_slot(slot_name, **kwargs)
167
- self.registered_slots[slot_name] = define_slot(slot_name, **kwargs)
168
- end
169
-
170
- def define_slot(slot_name, collection:, callable:)
171
- # Setup basic slot data
172
- slot = {
173
- collection: collection,
174
- }
175
- return slot unless callable
176
-
177
- # If callable responds to `render_in`, we set it on the slot as a renderable
178
- if callable.respond_to?(:method_defined?) && callable.method_defined?(:render_in)
179
- slot[:renderable] = callable
180
- elsif callable.is_a?(String)
181
- # If callable is a string, we assume it's referencing an internal class
182
- slot[:renderable_class_name] = callable
183
- elsif callable.respond_to?(:call)
184
- # If slot doesn't respond to `render_in`, we assume it's a proc,
185
- # define a method, and save a reference to it to call when setting
186
- method_name = :"_call_#{slot_name}"
187
- define_method method_name, &callable
188
- slot[:renderable_function] = instance_method(method_name)
189
- else
190
- raise(
191
- ArgumentError,
192
- "invalid slot definition. Please pass a class, string, or callable (i.e. proc, lambda, etc)"
193
- )
194
- end
195
-
196
- slot
197
- end
198
-
199
- def validate_plural_slot_name(slot_name)
200
- if slot_name.to_sym == :contents
201
- raise ArgumentError.new(
202
- "#{self} declares a slot named #{slot_name}, which is a reserved word in the ViewComponent framework.\n\n" \
203
- "To fix this issue, choose a different name."
204
- )
205
- end
206
-
207
- raise_if_slot_registered(slot_name)
208
- end
209
-
210
- def validate_singular_slot_name(slot_name)
211
- if slot_name.to_sym == :content
212
- raise ArgumentError.new(
213
- "#{self} declares a slot named #{slot_name}, which is a reserved word in the ViewComponent framework.\n\n" \
214
- "To fix this issue, choose a different name."
215
- )
216
- end
217
-
218
- raise_if_slot_registered(slot_name)
219
- end
220
-
221
- def raise_if_slot_registered(slot_name)
222
- if self.registered_slots.key?(slot_name)
223
- # TODO remove? This breaks overriding slots when slots are inherited
224
- raise ArgumentError.new(
225
- "#{self} declares the #{slot_name} slot multiple times.\n\n" \
226
- "To fix this issue, choose a different slot name."
227
- )
228
- end
229
- end
230
- end
231
-
232
- def get_slot(slot_name)
233
- content unless content_evaluated? # ensure content is loaded so slots will be defined
234
-
235
- slot = self.class.registered_slots[slot_name]
236
- @__vc_set_slots ||= {}
237
-
238
- if @__vc_set_slots[slot_name]
239
- return @__vc_set_slots[slot_name]
240
- end
241
-
242
- if slot[:collection]
243
- []
244
- else
245
- nil
246
- end
247
- end
248
-
249
- def set_slot(slot_name, slot_definition = nil, *args, &block)
250
- slot_definition ||= self.class.registered_slots[slot_name]
251
- slot = SlotV2.new(self)
252
-
253
- # Passing the block to the sub-component wrapper like this has two
254
- # benefits:
255
- #
256
- # 1. If this is a `content_area` style sub-component, we will render the
257
- # block via the `slot`
258
- #
259
- # 2. Since we've to pass block content to components when calling
260
- # `render`, evaluating the block here would require us to call
261
- # `view_context.capture` twice, which is slower
262
- slot.__vc_content_block = block if block_given?
263
-
264
- # If class
265
- if slot_definition[:renderable]
266
- slot.__vc_component_instance = slot_definition[:renderable].new(*args)
267
- # If class name as a string
268
- elsif slot_definition[:renderable_class_name]
269
- slot.__vc_component_instance =
270
- self.class.const_get(slot_definition[:renderable_class_name]).new(*args)
271
- # If passed a lambda
272
- elsif slot_definition[:renderable_function]
273
- # Use `bind(self)` to ensure lambda is executed in the context of the
274
- # current component. This is necessary to allow the lambda to access helper
275
- # methods like `content_tag` as well as parent component state.
276
- renderable_function = slot_definition[:renderable_function].bind(self)
277
- renderable_value =
278
- if block_given?
279
- renderable_function.call(*args) do |*args|
280
- view_context.capture(*args, &block)
281
- end
282
- else
283
- renderable_function.call(*args)
284
- end
285
-
286
- # Function calls can return components, so if it's a component handle it specially
287
- if renderable_value.respond_to?(:render_in)
288
- slot.__vc_component_instance = renderable_value
289
- else
290
- slot.__vc_content = renderable_value
291
- end
292
- end
293
-
294
- @__vc_set_slots ||= {}
295
-
296
- if slot_definition[:collection]
297
- @__vc_set_slots[slot_name] ||= []
298
- @__vc_set_slots[slot_name].push(slot)
299
- else
300
- @__vc_set_slots[slot_name] = slot
301
- end
302
-
303
- slot
304
- end
305
- ruby2_keywords(:set_slot) if respond_to?(:ruby2_keywords, true)
306
- end
307
- end
@@ -1,9 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module ViewComponent
4
- class TemplateError < StandardError
5
- def initialize(errors)
6
- super(errors.join(", "))
7
- end
8
- end
9
- end
@@ -1,19 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module YARD
4
- # YARD Handler to parse `mattr_accessor` calls.
5
- class MattrAccessorHandler < YARD::Handlers::Ruby::Base
6
- handles method_call(:mattr_accessor)
7
- namespace_only
8
-
9
- process do
10
- name = statement.parameters.first.jump(:tstring_content, :ident).source
11
- object = YARD::CodeObjects::MethodObject.new(namespace, name)
12
- register(object)
13
- parse_block(statement.last, owner: object)
14
-
15
- object.dynamic = true
16
- object[:mattr_accessor] = true
17
- end
18
- end
19
- end