Module: ViewComponent::Slotable
Constant Summary collapse
- RESERVED_NAMES =
{ singular: %i[content render].freeze, plural: %i[contents renders].freeze }.freeze
Instance Method Summary collapse
- #get_slot(slot_name) ⇒ Object
- #set_polymorphic_slot(slot_name, poly_type = nil, *args, &block) ⇒ Object
- #set_slot(slot_name, slot_definition = nil, *args, &block) ⇒ Object
Instance Method Details
#get_slot(slot_name) ⇒ Object
359 360 361 362 363 364 365 366 367 368 369 370 371 372 |
# File 'lib/view_component/slotable.rb', line 359 def get_slot(slot_name) content unless content_evaluated? # ensure content is loaded so slots will be defined slot = self.class.registered_slots[slot_name] @__vc_set_slots ||= {} if @__vc_set_slots[slot_name] return @__vc_set_slots[slot_name] end if slot[:collection] [] end end |
#set_polymorphic_slot(slot_name, poly_type = nil, *args, &block) ⇒ Object
432 433 434 435 436 437 438 439 440 441 442 |
# File 'lib/view_component/slotable.rb', line 432 def set_polymorphic_slot(slot_name, poly_type = nil, *args, &block) slot_definition = self.class.registered_slots[slot_name] if !slot_definition[:collection] && (defined?(@__vc_set_slots) && @__vc_set_slots[slot_name]) raise ContentAlreadySetForPolymorphicSlotError.new(slot_name) end poly_def = slot_definition[:renderable_hash][poly_type] set_slot(slot_name, poly_def, *args, &block) end |
#set_slot(slot_name, slot_definition = nil, *args, &block) ⇒ Object
374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 |
# File 'lib/view_component/slotable.rb', line 374 def set_slot(slot_name, slot_definition = nil, *args, &block) slot_definition ||= self.class.registered_slots[slot_name] slot = Slot.new(self) # Passing the block to the sub-component wrapper like this has two # benefits: # # 1. If this is a `content_area` style sub-component, we will render the # block via the `slot` # # 2. Since we have to pass block content to components when calling # `render`, evaluating the block here would require us to call # `view_context.capture` twice, which is slower slot.__vc_content_block = block if block # If class if slot_definition[:renderable] slot.__vc_component_instance = slot_definition[:renderable].new(*args) # If class name as a string elsif slot_definition[:renderable_class_name] slot.__vc_component_instance = self.class.const_get(slot_definition[:renderable_class_name]).new(*args) # If passed a lambda elsif slot_definition[:renderable_function] # Use `bind(self)` to ensure lambda is executed in the context of the # current component. This is necessary to allow the lambda to access helper # methods like `content_tag` as well as parent component state. renderable_function = slot_definition[:renderable_function].bind(self) renderable_value = if block renderable_function.call(*args) do |*rargs| view_context.capture(*rargs, &block) end else renderable_function.call(*args) end # Function calls can return components, so if it's a component handle it specially if renderable_value.respond_to?(:render_in) slot.__vc_component_instance = renderable_value else slot.__vc_content = renderable_value end end @__vc_set_slots ||= {} if slot_definition[:collection] @__vc_set_slots[slot_name] ||= [] @__vc_set_slots[slot_name].push(slot) else @__vc_set_slots[slot_name] = slot end slot end |