Module: Rooibos::Message::Predicates

Included in:
All, Batch, Bubbled, Canceled, Clock, Error, HttpResponse, Open, Random, Routed, System::Batch, System::Stream, Timer
Defined in:
lib/rooibos/message.rb

Overview

Fallback predicate mixin.

Update functions receive many message types. Checking unknown predicates crashes with NoMethodError. Verifying every predicate clutters the code.

This mixin returns false for unknown predicates. It also adds symbol comparison via to_sym and ==.

Include in custom message types for safe predicate calls and symbol matching.

Instance Method Summary collapse

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(name, *args, **kwargs, &block) ⇒ Object

Returns true if predicate matches :type or :envelope from deconstruct_keys. Returns false for unknown predicate methods.



74
75
76
77
78
79
80
81
82
# File 'lib/rooibos/message.rb', line 74

def method_missing(name, *args, **kwargs, &block)
  if name.to_s.end_with?("?") && args.empty? && kwargs.empty?
    predicate = name.to_s.chomp("?").to_sym
    keys = deconstruct_keys(nil)
    keys[:type] == predicate || keys[:envelope] == predicate
  else
    super
  end
end

Instance Method Details

#==(other) ⇒ Object

Compares the message with another object.

Symbols compare against to_sym. Other objects use default equality.

Example

if message == :message_timer
  handle_tick(message)
end


64
65
66
67
68
69
# File 'lib/rooibos/message.rb', line 64

def ==(other)
  case other
  when Symbol then to_sym == other
  else super
  end
end

#deconstruct_keys(keys) ⇒ Object

Fallback pattern matching for classes without explicit deconstruct_keys.

Derives :type from the class name in snake_case. Anonymous classes default to :custom.

Example

class MyCustomMessage
  include Rooibos::Message::Predicates
end

msg = MyCustomMessage.new
msg.deconstruct_keys(nil) # => { type: :my_custom_message }
msg.to_sym                # => :message_my_custom_message


98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
# File 'lib/rooibos/message.rb', line 98

def deconstruct_keys(keys)
  class_name = self.class.name&.split("::")&.last
  type_name = if class_name
    class_name.gsub(/([a-z])([A-Z])/, '\1_\2').downcase.to_sym
  else
    :custom
  end

  # Filter out :type before calling super — Data returns {} if any
  # requested key is unknown, which breaks pattern matching
  filtered_keys = keys&.reject { |k| k == :type }

  # Preserve parent's fields (e.g., Data.define members) and add :type
  parent_keys = begin
    super(filtered_keys)
  rescue NoMethodError
    {} #: Hash[Symbol, untyped]
  end
  parent_keys.merge(type: type_name)
end

#respond_to_missing?(name) ⇒ Boolean

Responds to all predicate methods.

Returns:

  • (Boolean)


120
121
122
# File 'lib/rooibos/message.rb', line 120

def respond_to_missing?(name, *)
  name.to_s.end_with?("?")
end

#to_symObject

Converts the message to a Symbol.

Returns the :type value from deconstruct_keys prefixed with message_. The prefix avoids collision with RatatuiRuby event symbols like :resize or :mouse.

Example

timer = Message::Timer.new(envelope: :tick, elapsed: 0.016)
timer.to_sym # => :message_timer


51
52
53
# File 'lib/rooibos/message.rb', line 51

def to_sym
  :"message_#{deconstruct_keys(nil)[:type]}"
end