Module: Plushie

Defined in:
lib/plushie.rb,
lib/plushie/ui.rb,
lib/plushie/app.rb,
lib/plushie/data.rb,
lib/plushie/node.rb,
lib/plushie/test.rb,
lib/plushie/tree.rb,
lib/plushie/undo.rb,
lib/plushie/event.rb,
lib/plushie/model.rb,
lib/plushie/route.rb,
lib/plushie/state.rb,
lib/plushie/binary.rb,
lib/plushie/bridge.rb,
lib/plushie/effect.rb,
lib/plushie/encode.rb,
lib/plushie/widget.rb,
lib/plushie/command.rb,
lib/plushie/runtime.rb,
lib/plushie/version.rb,
lib/plushie/protocol.rb,
lib/plushie/animation.rb,
lib/plushie/selection.rb,
lib/plushie/test/case.rb,
lib/plushie/tree/diff.rb,
lib/plushie/type/a11y.rb,
lib/plushie/type/font.rb,
lib/plushie/connection.rb,
lib/plushie/dev_server.rb,
lib/plushie/test/rspec.rb,
lib/plushie/type/color.rb,
lib/plushie/type/theme.rb,
lib/plushie/widget/pin.rb,
lib/plushie/widget/row.rb,
lib/plushie/widget/svg.rb,
lib/plushie/widget_set.rb,
lib/plushie/event/specs.rb,
lib/plushie/test/script.rb,
lib/plushie/thread_pool.rb,
lib/plushie/tree/search.rb,
lib/plushie/type/anchor.rb,
lib/plushie/type/border.rb,
lib/plushie/type/length.rb,
lib/plushie/type/shadow.rb,
lib/plushie/widget/grid.rb,
lib/plushie/widget/rule.rb,
lib/plushie/widget/text.rb,
lib/plushie/canvas/shape.rb,
lib/plushie/command/text.rb,
lib/plushie/renderer_env.rb,
lib/plushie/subscription.rb,
lib/plushie/test/helpers.rb,
lib/plushie/test/session.rb,
lib/plushie/type/padding.rb,
lib/plushie/type/shaping.rb,
lib/plushie/widget/build.rb,
lib/plushie/widget/image.rb,
lib/plushie/widget/radio.rb,
lib/plushie/widget/space.rb,
lib/plushie/widget/stack.rb,
lib/plushie/widget/table.rb,
lib/plushie/bounded_queue.rb,
lib/plushie/canvas_widget.rb,
lib/plushie/cargo_plushie.rb,
lib/plushie/command/image.rb,
lib/plushie/dsl/buildable.rb,
lib/plushie/key_modifiers.rb,
lib/plushie/protocol/keys.rb,
lib/plushie/renderer_exit.rb,
lib/plushie/test/snapshot.rb,
lib/plushie/type/gradient.rb,
lib/plushie/type/position.rb,
lib/plushie/type/wrapping.rb,
lib/plushie/widget/button.rb,
lib/plushie/widget/canvas.rb,
lib/plushie/widget/column.rb,
lib/plushie/widget/sensor.rb,
lib/plushie/widget/slider.rb,
lib/plushie/widget/themer.rb,
lib/plushie/widget/window.rb,
lib/plushie/command/scroll.rb,
lib/plushie/command/window.rb,
lib/plushie/type/alignment.rb,
lib/plushie/type/direction.rb,
lib/plushie/type/style_map.rb,
lib/plushie/widget/overlay.rb,
lib/plushie/widget/qr_code.rb,
lib/plushie/widget/toggler.rb,
lib/plushie/widget/tooltip.rb,
lib/plushie/animation/tween.rb,
lib/plushie/protocol/decode.rb,
lib/plushie/protocol/encode.rb,
lib/plushie/runtime/windows.rb,
lib/plushie/timer_scheduler.rb,
lib/plushie/widget/checkbox.rb,
lib/plushie/widget/floating.rb,
lib/plushie/widget/markdown.rb,
lib/plushie/animation/spring.rb,
lib/plushie/event/diagnostic.rb,
lib/plushie/protocol/parsers.rb,
lib/plushie/runtime/commands.rb,
lib/plushie/type/content_fit.rb,
lib/plushie/type/line_height.rb,
lib/plushie/widget/combo_box.rb,
lib/plushie/widget/container.rb,
lib/plushie/widget/pane_grid.rb,
lib/plushie/widget/pick_list.rb,
lib/plushie/widget/rich_text.rb,
lib/plushie/canvas/shape/clip.rb,
lib/plushie/canvas/shape/dash.rb,
lib/plushie/canvas/shape/line.rb,
lib/plushie/canvas/shape/path.rb,
lib/plushie/canvas/shape/rect.rb,
lib/plushie/test/session_pool.rb,
lib/plushie/transport/framing.rb,
lib/plushie/widget/responsive.rb,
lib/plushie/widget/scrollable.rb,
lib/plushie/widget/text_input.rb,
lib/plushie/animation/sequence.rb,
lib/plushie/canvas/shape/group.rb,
lib/plushie/test/script/runner.rb,
lib/plushie/type/filter_method.rb,
lib/plushie/widget/text_editor.rb,
lib/plushie/canvas/shape/circle.rb,
lib/plushie/canvas/shape/stroke.rb,
lib/plushie/widget/keyed_column.rb,
lib/plushie/widget/native_build.rb,
lib/plushie/widget/pointer_area.rb,
lib/plushie/widget/progress_bar.rb,
lib/plushie/animation/transition.rb,
lib/plushie/command/window_query.rb,
lib/plushie/canvas/shape/hit_rect.rb,
lib/plushie/runtime/subscriptions.rb,
lib/plushie/transport/tcp_adapter.rb,
lib/plushie/canvas/shape/transform.rb,
lib/plushie/widget/vertical_slider.rb,
lib/plushie/canvas/shape/canvas_svg.rb,
lib/plushie/canvas/shape/canvas_text.rb,
lib/plushie/canvas/shape/drag_bounds.rb,
lib/plushie/canvas/shape/shape_style.rb,
lib/plushie/canvas/shape/canvas_image.rb,
lib/plushie/canvas/shape/linear_gradient.rb

Overview

Native desktop GUI framework for Ruby, powered by iced.

Plushie implements the Elm architecture (init/update/view) for building desktop applications. The rendering is handled by a precompiled binary that communicates with Ruby over stdin/stdout using MessagePack.

Examples:

Run an app

Plushie.run(Counter)

Start in background

handle = Plushie.start(Counter)
handle.stop

See Also:

Defined Under Namespace

Modules: Animation, App, Binary, BoundedQueue, Canvas, CanvasWidget, CargoPlushie, DSL, DataQuery, Effect, Encode, Event, Model, Protocol, RendererEnv, Test, Transport, Tree, Type, UI, Widget, WidgetSet Classes: Bridge, Command, Configuration, Connection, DevServer, Error, KeyModifiers, Node, ProtocolVersionMismatchError, RendererExit, Route, Runtime, Selection, State, Subscription, ThreadPool, TimerScheduler, Undo

Constant Summary collapse

VERSION =

Current version of the plushie gem.

"0.6.0"
PLUSHIE_RUST_VERSION =

The plushie-rust release this SDK targets. Host SDKs pin to this exact version to download the matching renderer binary, install the matching cargo-plushie, and emit matching dep versions into generated Cargo.toml. See plushie-rust docs/versioning.md.

"0.7.1"
RENDERER_EXIT_TYPES =

Structured renderer exit reason passed to +handle_renderer_exit+.

The runtime converts raw internal exit reasons (connection errors, exit statuses, heartbeat timeouts) into a typed object before calling the app callback. This normalizes implementation details into a stable public API.

Pattern matching works automatically via Data.define:

Examples:

Pattern matching in handle_renderer_exit

def handle_renderer_exit(model, exit)
  case exit
  in Plushie::RendererExit[type: :heartbeat_timeout]
    model.with(status: :unresponsive)
  in Plushie::RendererExit[type: :crash]
    model.with(status: :crashed)
  else
    model
  end
end
%i[crash connection_lost shutdown heartbeat_timeout].freeze

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Attribute Details

#children [Array<Node>] frozen array of child nodes (empty for leaf widgets)([Array<Node>](empty) ⇒ Object (readonly)

A UI tree node. Produced by DSL methods and widget builders.

Nodes are immutable value objects representing a single widget in the view tree. The runtime diffs consecutive trees to produce patches sent to the renderer.

Examples:

Creating a node

Node.new(id: "greeting", type: "text", props: { content: "Hello" })

Pattern matching

case node
in Node[type: "button", id:]
  puts "Found button: #{id}"
end


24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
# File 'lib/plushie/node.rb', line 24

Node = Data.define(:id, :type, :props, :children, :meta) do
  # Create a new Node with string-coerced id and type, and frozen props/children/meta.
  #
  # @param id [#to_s] unique widget identifier
  # @param type [#to_s] widget type name
  # @param props [Hash] widget properties (will be frozen)
  # @param children [Array<Node>] child nodes (will be frozen)
  # @param meta [Hash] runtime-only metadata, never sent to the renderer (will be frozen)
  # @return [Node]
  def initialize(id:, type:, props: {}, children: [], meta: {})
    raise ArgumentError, "Node id cannot be nil" if id.nil?
    raise ArgumentError, "Node type cannot be nil" if type.nil?
    super(id: id.to_s, type: type.to_s, props: props.freeze, children: children.freeze, meta: meta.freeze)
  end

  # Return a new Node with the given fields replaced.
  # Unspecified fields retain their current values.
  #
  # @param changes [Hash] fields to replace (:id, :type, :props, :children, :meta)
  # @return [Node] new Node with the changes applied
  def with(**changes)
    self.class.new(**to_h.merge(changes))
  end
end

#details [Hash, nil] safe structured context([Hash, nil]) ⇒ Object (readonly)

Structured renderer exit reason passed to +handle_renderer_exit+.

The runtime converts raw internal exit reasons (connection errors, exit statuses, heartbeat timeouts) into a typed object before calling the app callback. This normalizes implementation details into a stable public API.

Pattern matching works automatically via Data.define:

Examples:

Pattern matching in handle_renderer_exit

def handle_renderer_exit(model, exit)
  case exit
  in Plushie::RendererExit[type: :heartbeat_timeout]
    model.with(status: :unresponsive)
  in Plushie::RendererExit[type: :crash]
    model.with(status: :crashed)
  else
    model
  end
end


28
# File 'lib/plushie/renderer_exit.rb', line 28

RENDERER_EXIT_TYPES = %i[crash connection_lost shutdown heartbeat_timeout].freeze

#id [String] unique widget identifier (scoped within parent containers)([String](scoped within parent containers)) ⇒ Object (readonly)

A UI tree node. Produced by DSL methods and widget builders.

Nodes are immutable value objects representing a single widget in the view tree. The runtime diffs consecutive trees to produce patches sent to the renderer.

Examples:

Creating a node

Node.new(id: "greeting", type: "text", props: { content: "Hello" })

Pattern matching

case node
in Node[type: "button", id:]
  puts "Found button: #{id}"
end


24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
# File 'lib/plushie/node.rb', line 24

Node = Data.define(:id, :type, :props, :children, :meta) do
  # Create a new Node with string-coerced id and type, and frozen props/children/meta.
  #
  # @param id [#to_s] unique widget identifier
  # @param type [#to_s] widget type name
  # @param props [Hash] widget properties (will be frozen)
  # @param children [Array<Node>] child nodes (will be frozen)
  # @param meta [Hash] runtime-only metadata, never sent to the renderer (will be frozen)
  # @return [Node]
  def initialize(id:, type:, props: {}, children: [], meta: {})
    raise ArgumentError, "Node id cannot be nil" if id.nil?
    raise ArgumentError, "Node type cannot be nil" if type.nil?
    super(id: id.to_s, type: type.to_s, props: props.freeze, children: children.freeze, meta: meta.freeze)
  end

  # Return a new Node with the given fields replaced.
  # Unspecified fields retain their current values.
  #
  # @param changes [Hash] fields to replace (:id, :type, :props, :children, :meta)
  # @return [Node] new Node with the changes applied
  def with(**changes)
    self.class.new(**to_h.merge(changes))
  end
end

#message [String] human-readable description([String]) ⇒ Object (readonly)

Structured renderer exit reason passed to +handle_renderer_exit+.

The runtime converts raw internal exit reasons (connection errors, exit statuses, heartbeat timeouts) into a typed object before calling the app callback. This normalizes implementation details into a stable public API.

Pattern matching works automatically via Data.define:

Examples:

Pattern matching in handle_renderer_exit

def handle_renderer_exit(model, exit)
  case exit
  in Plushie::RendererExit[type: :heartbeat_timeout]
    model.with(status: :unresponsive)
  in Plushie::RendererExit[type: :crash]
    model.with(status: :crashed)
  else
    model
  end
end


28
# File 'lib/plushie/renderer_exit.rb', line 28

RENDERER_EXIT_TYPES = %i[crash connection_lost shutdown heartbeat_timeout].freeze

#meta [Hash] frozen runtime-only metadata, never sent to the renderer or included in diffs([Hash], neversenttotherenderer) ⇒ Object (readonly)

A UI tree node. Produced by DSL methods and widget builders.

Nodes are immutable value objects representing a single widget in the view tree. The runtime diffs consecutive trees to produce patches sent to the renderer.

Examples:

Creating a node

Node.new(id: "greeting", type: "text", props: { content: "Hello" })

Pattern matching

case node
in Node[type: "button", id:]
  puts "Found button: #{id}"
end


24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
# File 'lib/plushie/node.rb', line 24

Node = Data.define(:id, :type, :props, :children, :meta) do
  # Create a new Node with string-coerced id and type, and frozen props/children/meta.
  #
  # @param id [#to_s] unique widget identifier
  # @param type [#to_s] widget type name
  # @param props [Hash] widget properties (will be frozen)
  # @param children [Array<Node>] child nodes (will be frozen)
  # @param meta [Hash] runtime-only metadata, never sent to the renderer (will be frozen)
  # @return [Node]
  def initialize(id:, type:, props: {}, children: [], meta: {})
    raise ArgumentError, "Node id cannot be nil" if id.nil?
    raise ArgumentError, "Node type cannot be nil" if type.nil?
    super(id: id.to_s, type: type.to_s, props: props.freeze, children: children.freeze, meta: meta.freeze)
  end

  # Return a new Node with the given fields replaced.
  # Unspecified fields retain their current values.
  #
  # @param changes [Hash] fields to replace (:id, :type, :props, :children, :meta)
  # @return [Node] new Node with the changes applied
  def with(**changes)
    self.class.new(**to_h.merge(changes))
  end
end

#props [Hash] frozen hash of property values (symbol keys)([Hash](symbol keys)) ⇒ Object (readonly)

A UI tree node. Produced by DSL methods and widget builders.

Nodes are immutable value objects representing a single widget in the view tree. The runtime diffs consecutive trees to produce patches sent to the renderer.

Examples:

Creating a node

Node.new(id: "greeting", type: "text", props: { content: "Hello" })

Pattern matching

case node
in Node[type: "button", id:]
  puts "Found button: #{id}"
end


24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
# File 'lib/plushie/node.rb', line 24

Node = Data.define(:id, :type, :props, :children, :meta) do
  # Create a new Node with string-coerced id and type, and frozen props/children/meta.
  #
  # @param id [#to_s] unique widget identifier
  # @param type [#to_s] widget type name
  # @param props [Hash] widget properties (will be frozen)
  # @param children [Array<Node>] child nodes (will be frozen)
  # @param meta [Hash] runtime-only metadata, never sent to the renderer (will be frozen)
  # @return [Node]
  def initialize(id:, type:, props: {}, children: [], meta: {})
    raise ArgumentError, "Node id cannot be nil" if id.nil?
    raise ArgumentError, "Node type cannot be nil" if type.nil?
    super(id: id.to_s, type: type.to_s, props: props.freeze, children: children.freeze, meta: meta.freeze)
  end

  # Return a new Node with the given fields replaced.
  # Unspecified fields retain their current values.
  #
  # @param changes [Hash] fields to replace (:id, :type, :props, :children, :meta)
  # @return [Node] new Node with the changes applied
  def with(**changes)
    self.class.new(**to_h.merge(changes))
  end
end

#type [String] widget type name ("button", "column", "text_input", etc.)([String]("button", "column", "text_input", etc.)) ⇒ Object (readonly)

A UI tree node. Produced by DSL methods and widget builders.

Nodes are immutable value objects representing a single widget in the view tree. The runtime diffs consecutive trees to produce patches sent to the renderer.

Examples:

Creating a node

Node.new(id: "greeting", type: "text", props: { content: "Hello" })

Pattern matching

case node
in Node[type: "button", id:]
  puts "Found button: #{id}"
end


24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
# File 'lib/plushie/node.rb', line 24

Node = Data.define(:id, :type, :props, :children, :meta) do
  # Create a new Node with string-coerced id and type, and frozen props/children/meta.
  #
  # @param id [#to_s] unique widget identifier
  # @param type [#to_s] widget type name
  # @param props [Hash] widget properties (will be frozen)
  # @param children [Array<Node>] child nodes (will be frozen)
  # @param meta [Hash] runtime-only metadata, never sent to the renderer (will be frozen)
  # @return [Node]
  def initialize(id:, type:, props: {}, children: [], meta: {})
    raise ArgumentError, "Node id cannot be nil" if id.nil?
    raise ArgumentError, "Node type cannot be nil" if type.nil?
    super(id: id.to_s, type: type.to_s, props: props.freeze, children: children.freeze, meta: meta.freeze)
  end

  # Return a new Node with the given fields replaced.
  # Unspecified fields retain their current values.
  #
  # @param changes [Hash] fields to replace (:id, :type, :props, :children, :meta)
  # @return [Node] new Node with the changes applied
  def with(**changes)
    self.class.new(**to_h.merge(changes))
  end
end

#type [Symbol] exit category (:crash, :connection_lost, :shutdown, :heartbeat_timeout)([Symbol](: crash, :connection_lost, :shutdown, :heartbeat_timeout)) ⇒ Object (readonly)

Structured renderer exit reason passed to +handle_renderer_exit+.

The runtime converts raw internal exit reasons (connection errors, exit statuses, heartbeat timeouts) into a typed object before calling the app callback. This normalizes implementation details into a stable public API.

Pattern matching works automatically via Data.define:

Examples:

Pattern matching in handle_renderer_exit

def handle_renderer_exit(model, exit)
  case exit
  in Plushie::RendererExit[type: :heartbeat_timeout]
    model.with(status: :unresponsive)
  in Plushie::RendererExit[type: :crash]
    model.with(status: :crashed)
  else
    model
  end
end


28
# File 'lib/plushie/renderer_exit.rb', line 28

RENDERER_EXIT_TYPES = %i[crash connection_lost shutdown heartbeat_timeout].freeze

Class Method Details

.configurationConfiguration

Returns the global configuration.

Returns:



233
234
235
# File 'lib/plushie.rb', line 233

def self.configuration
  @configuration
end

.configure {|Configuration| ... } ⇒ Object

Configure the SDK via a block.

Yields:



240
241
242
# File 'lib/plushie.rb', line 240

def self.configure
  yield @configuration
end

.run(app_class, **opts) ⇒ Object

Start a Plushie app and block until it exits.

Plushie.run(Counter) Plushie.run(Counter, transport: :spawn, format: :msgpack)



249
250
251
252
253
# File 'lib/plushie.rb', line 249

def self.run(app_class, **opts)
  app = app_class.new
  runtime = Runtime.new(app:, **opts)
  runtime.run
end

.start(app_class, **opts) ⇒ Object

Start a Plushie app in the background. Returns a handle that can be stopped later.

handle = Plushie.start(Counter) handle.stop



261
262
263
264
265
266
# File 'lib/plushie.rb', line 261

def self.start(app_class, **opts)
  app = app_class.new
  runtime = Runtime.new(app:, **opts)
  runtime.start
  runtime
end