view_component_storybook 0.10.1 → 0.11.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b6ef1bcb6cf8fd3beccec9242854aa913bd31fe1c7c44c44cdde6b59be8fd67f
4
- data.tar.gz: de047bb6e4e453db106270ba7f28b4d252fed881816266e10b99bb8c2d4b93f0
3
+ metadata.gz: 0dd708afcf2aa165339b0b1fde82ae610665554e3633c1e50b25509088b43e79
4
+ data.tar.gz: 950739b2892877a1451c262dc2110d6885a86c740c7fec9cd626a305feb8313d
5
5
  SHA512:
6
- metadata.gz: 4d96299b59366d1f50d034399299209a7edc01aa99f3ff728b0e6ed1721b1f80679aa8f7bbb953be549baa59fd74d090eb8d5b7e615bdc7b26164ebb0f011373
7
- data.tar.gz: d97204b485ac6d1b61c7848e6c2b68cec798328eef7e78738f3f675daa805dc6db73a0e6d1e6e7f17373de4b5ca90cfe000716bb4b25f29f8ae77d9985f0580e
6
+ metadata.gz: 3f9b37292f202ac1c79fd4d31b9ace6b067efff03bf60a6f6a7b44a241ce5661c3669a382d9e549461dfe391d9c77fe0b9b98d33a3a5a47ce821d47e9c26ec7d
7
+ data.tar.gz: 8e7db14af389ae4d4b2dbcf269269476ac9309c9e518226afedbef769e31f72d32ed44a61382f9830836cab5a4ceba45a701af0a66861de31f928713be9b6c55
@@ -1,7 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "rails"
4
- require "view_component/storybook"
5
4
 
6
5
  module ViewComponent
7
6
  module Storybook
@@ -45,3 +44,14 @@ module ViewComponent
45
44
  end
46
45
  end
47
46
  end
47
+
48
+ # :nocov:
49
+ unless defined?(ViewComponent::Storybook)
50
+ ActiveSupport::Deprecation.warn(
51
+ "This manually engine loading is deprecated and will be removed in v1.0.0. " \
52
+ "Remove `require \"view_component/storybook/engine\"`."
53
+ )
54
+
55
+ require "view_component/storybook"
56
+ end
57
+ # :nocov:
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ViewComponent
4
+ module Storybook
5
+ module MethodArgs
6
+ ##
7
+ # Class representing the constructor args for a Component
8
+ class ComponentConstructorArgs < ControlMethodArgs
9
+ def self.from_component_class(component_class, *args, **kwargs)
10
+ if DryInitializerComponentConstructorArgs.dry_initialize?(component_class)
11
+ DryInitializerComponentConstructorArgs.new(component_class, *args, **kwargs)
12
+ else
13
+ new(component_class, *args, **kwargs)
14
+ end
15
+ end
16
+
17
+ def initialize(component_class, *args, **kwargs)
18
+ super(component_class.instance_method(:initialize), *args, **kwargs)
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ViewComponent
4
+ module Storybook
5
+ module MethodArgs
6
+ ##
7
+ # Class representing the constructor args for a Component the extends dry-initializer
8
+ class DryInitializerComponentConstructorArgs < ControlMethodArgs
9
+ INITIALIZE_METHOD = :__dry_initializer_initialize__
10
+
11
+ ##
12
+ # Method Parameters names that are dry-initialize aware
13
+ # THe main difference is that Dry Initializer keyword args cannot be deduced from the constructor initialize params
14
+ # Instead we have to introspect the dry_initializer config for the option definitions
15
+ class DryConstructorParametersNames < MethodParametersNames
16
+ attr_reader :dry_initializer
17
+
18
+ def initialize(component_class)
19
+ super(component_class.instance_method(INITIALIZE_METHOD))
20
+ @dry_initializer = component_class.dry_initializer
21
+ end
22
+
23
+ # Required keywords are the only thing we need.
24
+ # We could define kwarg_names similarly but wihout the `optional` check. However, dry-initializer
25
+ # always ends has supports_keyrest? == true so kwarg_names isn't needed
26
+ def req_kwarg_names
27
+ @req_kwarg_names ||= dry_initializer.definitions.map do |name, definition|
28
+ name if definition.option && !definition.optional
29
+ end.compact
30
+ end
31
+ end
32
+
33
+ def self.dry_initialize?(component_class)
34
+ component_class.private_method_defined?(INITIALIZE_METHOD)
35
+ end
36
+
37
+ def initialize(component_class, *args, **kwargs)
38
+ super(component_class.instance_method(INITIALIZE_METHOD), *args, **kwargs)
39
+
40
+ @target_method_params_names = DryConstructorParametersNames.new(component_class)
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
@@ -57,7 +57,7 @@ module ViewComponent
57
57
  def kwarg_names
58
58
  @kwarg_names ||= parameters.map do |type, name|
59
59
  name if KWARG_TYPES.include?(type)
60
- end.compact.to_set
60
+ end.compact
61
61
  end
62
62
 
63
63
  def arg_names
@@ -9,8 +9,9 @@ module ViewComponent
9
9
 
10
10
  autoload :MethodArgs
11
11
  autoload :MethodParametersNames
12
- autoload :ValidatableMethodArgs
13
12
  autoload :ControlMethodArgs
13
+ autoload :ComponentConstructorArgs
14
+ autoload :DryInitializerComponentConstructorArgs
14
15
  end
15
16
  end
16
17
  end
@@ -4,10 +4,13 @@ module ViewComponent
4
4
  module Storybook
5
5
  module Slots
6
6
  class SlotConfig
7
+ include ActiveModel::Validations
7
8
  include ContentConcern
8
9
 
9
10
  attr_reader :slot_name, :slot_method_args, :param, :content_block
10
11
 
12
+ validate :validate_slot_method_args
13
+
11
14
  def initialize(slot_name, slot_method_args, param, content_block)
12
15
  @slot_name = slot_name
13
16
  @slot_method_args = slot_method_args
@@ -16,11 +19,12 @@ module ViewComponent
16
19
  end
17
20
 
18
21
  def self.from_component(component_class, slot_name, param, *args, **kwargs, &block)
19
- slot_method_args =
20
- MethodArgs::ControlMethodArgs
21
- .new(component_class.instance_method(slot_name), *args, **kwargs)
22
- .with_param_prefix(param)
23
- new(slot_name, slot_method_args, param, block)
22
+ new(
23
+ slot_name,
24
+ slot_method_args(component_class, slot_name, *args, **kwargs).with_param_prefix(param),
25
+ param,
26
+ block
27
+ )
24
28
  end
25
29
 
26
30
  def slot(componeont, params)
@@ -38,6 +42,37 @@ module ViewComponent
38
42
  def content_param
39
43
  "#{param}__content".to_sym
40
44
  end
45
+
46
+ private
47
+
48
+ def validate_slot_method_args
49
+ return if slot_method_args.valid?
50
+
51
+ slot_method_args_errors = slot_method_args.errors.full_messages.join(', ')
52
+ errors.add(:slot_method_args, :invalid, errors: slot_method_args_errors)
53
+ end
54
+
55
+ def self.slot_method_args(component_class, slot_name, *args, **kwargs)
56
+ # Reverse engineer the signature of the slot so that we can validate control args to the slot
57
+ # The slot methods themselves just have rest params so we can't introspect them. Instead we
58
+ # look for 'renderable' details of the registered slot
59
+ # This approach is tightly coupled to internal ViewCopmonent apis and might prove to be brittle
60
+ registred_slot_name = component_class.slot_type(slot_name) == :collection_item ? ActiveSupport::Inflector.pluralize(slot_name).to_sym : slot_name
61
+
62
+ registered_slot = component_class.registered_slots[registred_slot_name]
63
+
64
+ if registered_slot[:renderable] || registered_slot[:renderable_class_name]
65
+ # The slot is a component - either a class or a string representing the class
66
+ component_class = registered_slot[:renderable] || component_class.const_get(registered_slot[:renderable_class_name])
67
+ MethodArgs::ComponentConstructorArgs.from_component_class(component_class, *args, **kwargs)
68
+ else
69
+ # the slot is a lamba or a simple content slot
70
+ slot_lamba = registered_slot[:renderable_function] || proc {}
71
+ MethodArgs::ControlMethodArgs.new(slot_lamba, *args, **kwargs)
72
+ end
73
+ end
74
+
75
+ private_class_method :slot_method_args
41
76
  end
42
77
  end
43
78
  end
@@ -47,9 +47,7 @@ module ViewComponent
47
47
 
48
48
  def write_csf_json
49
49
  json_path = File.join(stories_path, "#{stories_name}.stories.json")
50
- File.open(json_path, "w") do |f|
51
- f.write(JSON.pretty_generate(to_csf_params))
52
- end
50
+ File.write(json_path, JSON.pretty_generate(to_csf_params))
53
51
  json_path
54
52
  end
55
53
 
@@ -9,7 +9,7 @@ module ViewComponent
9
9
 
10
10
  attr_reader :id, :name, :component_class
11
11
 
12
- validate :validate_constructor_args
12
+ validate :validate_constructor_args, :validate_slots_args
13
13
 
14
14
  def initialize(id, name, component_class, layout)
15
15
  @id = id
@@ -20,8 +20,8 @@ module ViewComponent
20
20
  end
21
21
 
22
22
  def constructor(*args, **kwargs, &block)
23
- @constructor_args = MethodArgs::ControlMethodArgs.new(
24
- component_constructor,
23
+ @constructor_args = MethodArgs::ComponentConstructorArgs.from_component_class(
24
+ component_class,
25
25
  *args,
26
26
  **kwargs
27
27
  )
@@ -117,11 +117,7 @@ module ViewComponent
117
117
  private
118
118
 
119
119
  def constructor_args
120
- @constructor_args ||= MethodArgs::ControlMethodArgs.new(component_constructor)
121
- end
122
-
123
- def component_constructor
124
- component_class.instance_method(:initialize)
120
+ @constructor_args ||= MethodArgs::ComponentConstructorArgs.from_component_class(component_class)
125
121
  end
126
122
 
127
123
  def slots
@@ -135,6 +131,13 @@ module ViewComponent
135
131
  errors.add(:constructor_args, :invalid, errors: constructor_args_errors)
136
132
  end
137
133
 
134
+ def validate_slots_args
135
+ slots.reject(&:valid?).each do |slot_config|
136
+ slot_errors = slot_config.errors.full_messages.join(', ')
137
+ errors.add(:slots, :invalid, errors: slot_errors)
138
+ end
139
+ end
140
+
138
141
  def slot(slot_name, *args, **kwargs, &block)
139
142
  # if the name is a slot then build a SlotConfig with slot_name and param the same
140
143
  if component_class.slot_type(slot_name) == :collection_item
@@ -2,6 +2,6 @@
2
2
 
3
3
  module ViewComponent
4
4
  module Storybook
5
- VERSION = "0.10.1"
5
+ VERSION = "0.11.0"
6
6
  end
7
7
  end
@@ -41,6 +41,17 @@ module ViewComponent
41
41
  "/rails/stories"
42
42
  end
43
43
 
44
+ # :nocov:
45
+ if defined?(ViewComponent::Storybook::Engine)
46
+ ActiveSupport::Deprecation.warn(
47
+ "This manually engine loading is deprecated and will be removed in v1.0.0. " \
48
+ "Remove `require \"view_component/storybook/engine\"`."
49
+ )
50
+ elsif defined?(Rails::Engine)
51
+ require "view_component/storybook/engine"
52
+ end
53
+ # :nocov:
54
+
44
55
  ActiveSupport.run_load_hooks(:view_component_storybook, self)
45
56
  end
46
57
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: view_component_storybook
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.10.1
4
+ version: 0.11.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jon Palmer
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-08-08 00:00:00.000000000 Z
11
+ date: 2022-02-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: view_component
@@ -52,6 +52,20 @@ dependencies:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
54
  version: '3'
55
+ - !ruby/object:Gem::Dependency
56
+ name: dry-initializer
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: 3.0.4
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: 3.0.4
55
69
  - !ruby/object:Gem::Dependency
56
70
  name: rake
57
71
  requirement: !ruby/object:Gem::Requirement
@@ -210,7 +224,9 @@ files:
210
224
  - lib/view_component/storybook/dsl/legacy_controls_dsl.rb
211
225
  - lib/view_component/storybook/engine.rb
212
226
  - lib/view_component/storybook/method_args.rb
227
+ - lib/view_component/storybook/method_args/component_constructor_args.rb
213
228
  - lib/view_component/storybook/method_args/control_method_args.rb
229
+ - lib/view_component/storybook/method_args/dry_initializer_component_constructor_args.rb
214
230
  - lib/view_component/storybook/method_args/method_args.rb
215
231
  - lib/view_component/storybook/method_args/method_parameters_names.rb
216
232
  - lib/view_component/storybook/slots.rb
@@ -228,6 +244,7 @@ metadata:
228
244
  allowed_push_host: https://rubygems.org
229
245
  homepage_uri: https://github.com/jonspalmer/view_component_storybook
230
246
  source_code_uri: https://github.com/jonspalmer/view_component_storybook
247
+ rubygems_mfa_required: 'true'
231
248
  post_install_message:
232
249
  rdoc_options: []
233
250
  require_paths:
@@ -243,7 +260,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
243
260
  - !ruby/object:Gem::Version
244
261
  version: '0'
245
262
  requirements: []
246
- rubygems_version: 3.1.6
263
+ rubygems_version: 3.0.6
247
264
  signing_key:
248
265
  specification_version: 4
249
266
  summary: Storybook for Rails View Components