Module: Plushie::Widget::CustomDSL
- Defined in:
- lib/plushie/widget.rb
Overview
DSL methods added to classes that include Plushie::Widget or are created via Widget.define.
Constant Summary collapse
- VALID_KINDS =
This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.
Valid widget kind values.
%i[widget native_widget].freeze
Instance Method Summary collapse
-
#a11y_defaults ⇒ Hash?
Returns the default a11y annotations, or nil.
-
#cache_key(fn) ⇒ Object
Declares a cache key function for view-level caching.
-
#cache_key_fn ⇒ Proc?
Returns the cache key function, or nil.
-
#children(mode)
Declare children mode.
-
#children_mode ⇒ Symbol, ...
Returns the children mode (:none, :single, :many, or Integer).
-
#command(name, **params)
Declares a command (for native widgets, informational in Ruby).
-
#container? ⇒ Boolean
Whether this is a container widget (accepts children).
-
#default_a11y(**defaults)
Declare default a11y annotations for this widget type.
-
#event(name, fields: nil)
Declares an event that this widget can emit.
-
#finalize!
Finalize the widget class by generating initialize, setters, and build.
-
#native? ⇒ Boolean
Whether this is a native (Rust-backed) widget.
-
#native_crate ⇒ String?
Rust crate path.
-
#positional(name, default: REQUIRED)
Declare a positional constructor argument.
-
#prop(*names, type: nil, doc: nil, default: nil)
Declare one or more props.
-
#prop_meta ⇒ Hash{Symbol => Hash}
Returns metadata for declared props (type, doc).
-
#prop_names ⇒ Array<Symbol>
Returns all declared prop names (plus auto-added :a11y, :event_rate).
-
#rust_constructor(expr)
Declares the Rust constructor expression used in the generated main.rs.
-
#rust_constructor_expr ⇒ String?
Rust constructor expression.
-
#rust_crate(path)
Declares the relative path to the Rust crate directory.
-
#state(name, default: nil)
Declares a state field with a default value.
-
#stateful? ⇒ Boolean
Whether this widget is stateful (has state, events, or handle_event).
-
#type_names ⇒ Array<Symbol>
Returns the widget type names this widget handles.
- #validate_composite_type(name, value, type_spec) ⇒ Object
-
#validate_prop_type(name, value, type) ⇒ Object
Validate a prop value against its declared type.
-
#widget(type_name, **opts)
Declares the widget type name.
-
#widget_event_specs ⇒ Array<Hash{Symbol => Object}>
Returns the declared event specs with field definitions.
-
#widget_events ⇒ Array<Symbol>
Returns the declared event names.
-
#widget_positionals ⇒ Array<Hash>
private
Positional argument declarations.
-
#widget_props ⇒ Array<Hash{Symbol => Object}>
Returns the declared props metadata.
-
#widget_state_fields ⇒ Array<Hash{Symbol => Object}>
Returns the declared state fields.
Instance Method Details
#a11y_defaults ⇒ Hash?
Returns the default a11y annotations, or nil.
381 |
# File 'lib/plushie/widget.rb', line 381 def a11y_defaults = @_a11y_defaults |
#cache_key(fn) ⇒ Object
Declares a cache key function for view-level caching.
When the cache key proc returns the same value as the previous render, the widget's view is skipped and the cached normalized output is reused. Complementary to memo (subtree-level caching).
244 245 246 |
# File 'lib/plushie/widget.rb', line 244 def cache_key(fn) @_widget_cache_key = fn end |
#cache_key_fn ⇒ Proc?
Returns the cache key function, or nil.
373 |
# File 'lib/plushie/widget.rb', line 373 def cache_key_fn = @_widget_cache_key |
#children(mode)
This method returns an undefined value.
Declare children mode.
202 203 204 205 |
# File 'lib/plushie/widget.rb', line 202 def children(mode) @_widget_children_mode = mode @_widget_container = mode && mode != :none end |
#children_mode ⇒ Symbol, ...
Returns the children mode (:none, :single, :many, or Integer).
369 |
# File 'lib/plushie/widget.rb', line 369 def children_mode = @_widget_children_mode |
#command(name, **params)
This method returns an undefined value.
Declares a command (for native widgets, informational in Ruby).
296 297 298 |
# File 'lib/plushie/widget.rb', line 296 def command(name, **params) @_widget_commands << {name: name.to_sym, params: params} end |
#container? ⇒ Boolean
Whether this is a container widget (accepts children).
365 |
# File 'lib/plushie/widget.rb', line 365 def container? = @_widget_container |
#default_a11y(**defaults)
This method returns an undefined value.
Declare default a11y annotations for this widget type.
Merged into the widget's a11y prop during build when the user hasn't provided explicit overrides. User values win per field.
218 219 220 |
# File 'lib/plushie/widget.rb', line 218 def default_a11y(**defaults) @_a11y_defaults = defaults.freeze end |
#event(name, fields: nil)
This method returns an undefined value.
Declares an event that this widget can emit.
Event declarations document the widget's public event contract. Widgets with event declarations or +handle_event+ participate in the event dispatch chain.
With +fields:+, declares typed fields that are validated at emit time. Fields are required by default. Use +Class, required: false+ to make a field optional.
274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 |
# File 'lib/plushie/widget.rb', line 274 def event(name, fields: nil) name = name.to_sym spec = if fields && !fields.empty? resolved_fields = fields.each_with_object({}) do |(k, v), h| h[k] = if v.is_a?(Hash) {type: v[:type], required: v.fetch(:required, true)} else {type: v, required: true} end end {name: name, fields: resolved_fields} else {name: name, fields: nil} end @_widget_events << spec end |
#finalize!
This method returns an undefined value.
Finalize the widget class by generating initialize, setters, and build.
Called automatically on first instantiation, or explicitly by Widget.define after the block has been evaluated.
394 395 396 397 398 399 400 401 402 403 404 405 |
# File 'lib/plushie/widget.rb', line 394 def finalize! return if @_finalized _validate! _set_defaults! _generate_readers! _generate_initialize! _generate_setters! _generate_push! if container? _generate_build! @_finalized = true end |
#native? ⇒ Boolean
Whether this is a native (Rust-backed) widget.
326 |
# File 'lib/plushie/widget.rb', line 326 def native? = @_widget_kind == :native_widget |
#native_crate ⇒ String?
Returns Rust crate path.
319 |
# File 'lib/plushie/widget.rb', line 319 def native_crate = @_widget_native_crate |
#positional(name, default: REQUIRED)
This method returns an undefined value.
Declare a positional constructor argument.
Call order determines argument order after +id+. The name must also be a declared prop.
194 195 196 |
# File 'lib/plushie/widget.rb', line 194 def positional(name, default: REQUIRED) @_widget_positionals << {name: name.to_sym, default: default} end |
#prop(*names, type: nil, doc: nil, default: nil)
This method returns an undefined value.
Declare one or more props.
Supports three forms:
- Simple: +prop :label, :width, :height+ (names only, untyped)
- Typed: +prop :value, :number, default: 0+ (name + type)
- Rich: +prop :label, type: :string, doc: "Text label"+ (name + metadata)
Types are informational: they document the prop for introspection and future tooling. Values pass through to the wire protocol where the renderer handles validation.
147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 |
# File 'lib/plushie/widget.rb', line 147 def prop(*names, type: nil, doc: nil, default: nil) if names.length == 1 && (type || doc) # Rich form: prop :name, type: :string, doc: "..." name = names[0].to_sym if type && !KNOWN_PROP_TYPES.include?(type.to_sym) raise ArgumentError, "unsupported prop type #{type.inspect} for #{name.inspect}. " \ "Known types: #{KNOWN_PROP_TYPES.inspect}" end is_auto = _check_prop_name!(name) unless is_auto @_widget_props << {name: name, type: type, default: default} (@_prop_meta ||= {})[name] = {type: type, doc: doc}.compact end elsif names.length == 2 && KNOWN_PROP_TYPES.include?(names[1].to_sym) # Typed form: prop :name, :string, default: 0 name = names[0].to_sym type_val = names[1].to_sym is_auto = _check_prop_name!(name) unless is_auto @_widget_props << {name: name, type: type_val, default: default} end else # Simple form: prop :name1, :name2, ... if default raise ArgumentError, "default: cannot be used with the multi-name prop form. " \ "Use `prop :#{names.first}, type: :any, default: ...` for a single prop with a default" end names.each do |n| sym = n.to_sym is_auto = _check_prop_name!(sym) next if is_auto @_widget_props << {name: sym, type: nil, default: nil} end end end |
#prop_meta ⇒ Hash{Symbol => Hash}
Returns metadata for declared props (type, doc).
377 |
# File 'lib/plushie/widget.rb', line 377 def = @_prop_meta || {} |
#prop_names ⇒ Array<Symbol>
Returns all declared prop names (plus auto-added :a11y, :event_rate).
343 344 345 |
# File 'lib/plushie/widget.rb', line 343 def prop_names @_widget_props.map { _1[:name] } + %i[a11y event_rate] end |
#rust_constructor(expr)
This method returns an undefined value.
Declares the Rust constructor expression used in the generated main.rs. Required for +:native_widget+ widgets.
312 313 314 |
# File 'lib/plushie/widget.rb', line 312 def rust_constructor(expr) @_widget_rust_constructor = expr.to_s end |
#rust_constructor_expr ⇒ String?
Returns Rust constructor expression.
322 |
# File 'lib/plushie/widget.rb', line 322 def rust_constructor_expr = @_widget_rust_constructor |
#rust_crate(path)
This method returns an undefined value.
Declares the relative path to the Rust crate directory. Required for +:native_widget+ widgets.
304 305 306 |
# File 'lib/plushie/widget.rb', line 304 def rust_crate(path) @_widget_native_crate = path.to_s end |
#state(name, default: nil)
This method returns an undefined value.
Declares a state field with a default value.
Declaring any state field makes the widget stateful: the runtime manages its state via a registry, renders it during tree normalization, and dispatches events through +handle_event+.
231 232 233 |
# File 'lib/plushie/widget.rb', line 231 def state(name, default: nil) @_widget_state_fields << {name: name.to_sym, default: default} end |
#stateful? ⇒ Boolean
Whether this widget is stateful (has state, events, or handle_event).
330 331 332 333 334 335 |
# File 'lib/plushie/widget.rb', line 330 def stateful? !@_widget_state_fields.empty? || !@_widget_events.empty? || _owns_singleton_method?(:init) || _owns_singleton_method?(:handle_event) end |
#type_names ⇒ Array<Symbol>
Returns the widget type names this widget handles.
339 |
# File 'lib/plushie/widget.rb', line 339 def type_names = [@_widget_type] |
#validate_composite_type(name, value, type_spec) ⇒ Object
595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 |
# File 'lib/plushie/widget.rb', line 595 def validate_composite_type(name, value, type_spec) if (tuple_types = type_spec[:tuple]) unless value.is_a?(Array) && value.length == tuple_types.length raise ArgumentError, "#{name} expects a #{tuple_types.length}-element Array, " \ "got #{value.inspect}" end tuple_types.each_with_index do |elem_type, i| validate_prop_type("#{name}[#{i}]", value[i], elem_type) end elsif (enum_values = type_spec[:enum]) unless enum_values.include?(value) raise ArgumentError, "#{name} expects one of #{enum_values.inspect}, got #{value.inspect}" end elsif (list_type = type_spec[:list]) raise ArgumentError, "#{name} expects an Array, got #{value.class}" unless value.is_a?(Array) value.each_with_index do |elem, i| validate_prop_type("#{name}[#{i}]", elem, list_type) end elsif (map_types = type_spec[:map]) raise ArgumentError, "#{name} expects a Hash, got #{value.class}" unless value.is_a?(Hash) map_types.each do |key, val_type| validate_prop_type("#{name}[#{key.inspect}]", value[key], val_type) if value.key?(key) end end end |
#validate_prop_type(name, value, type) ⇒ Object
Validate a prop value against its declared type. Supports Class/module types, :numeric, :boolean, and composite types ([T1, T2], [:a, :b], T).
568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 |
# File 'lib/plushie/widget.rb', line 568 def validate_prop_type(name, value, type) case type when Class, Module unless value.is_a?(type) raise ArgumentError, "#{name} expects #{type}, got #{value.class}: #{value.inspect}" end when :numeric unless value.is_a?(Numeric) raise ArgumentError, "#{name} expects a Numeric, got #{value.class}: #{value.inspect}" end when :boolean unless [true, false].include?(value) raise ArgumentError, "#{name} expects true or false, got #{value.inspect}" end when :symbol unless value.is_a?(Symbol) raise ArgumentError, "#{name} expects a Symbol, got #{value.class}: #{value.inspect}" end when Hash validate_composite_type(name, value, type) end end |
#widget(type_name, **opts)
This method returns an undefined value.
Declares the widget type name.
115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 |
# File 'lib/plushie/widget.rb', line 115 def (type_name, **opts) kind = opts.fetch(:kind, :widget) unless VALID_KINDS.include?(kind) raise ArgumentError, "unsupported widget kind #{kind.inspect}. Supported: #{VALID_KINDS.inspect}" end @_widget_type = type_name @_widget_kind = kind return unless opts.key?(:container) mode = (opts[:container] == true) ? :many : opts[:container] children(mode) end |
#widget_event_specs ⇒ Array<Hash{Symbol => Object}>
Returns the declared event specs with field definitions.
361 |
# File 'lib/plushie/widget.rb', line 361 def = @_widget_events |
#widget_events ⇒ Array<Symbol>
Returns the declared event names.
357 |
# File 'lib/plushie/widget.rb', line 357 def = @_widget_events.map { |e| e[:name] } |
#widget_positionals ⇒ Array<Hash>
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Returns positional argument declarations.
385 |
# File 'lib/plushie/widget.rb', line 385 def = @_widget_positionals |
#widget_props ⇒ Array<Hash{Symbol => Object}>
Returns the declared props metadata.
349 |
# File 'lib/plushie/widget.rb', line 349 def = @_widget_props |
#widget_state_fields ⇒ Array<Hash{Symbol => Object}>
Returns the declared state fields.
353 |
# File 'lib/plushie/widget.rb', line 353 def = @_widget_state_fields |