Class: RSMP::StateCollector

Inherits:
Collector show all
Defined in:
lib/rsmp/collect/state_collector.rb

Overview

Base class for waiting for specific status or command responses, specified by a list of matchers. Matchers are defined as an array of hashes, e.g [

 {"cCI"=>"M0104", "cO"=>"setDate", "n"=>"securityCode", "v"=>"1111"},
 {"cCI"=>"M0104", "cO"=>"setDate", "n"=>"year", "v"=>"2020"},
 {"cCI"=>"M0104", "cO"=>"setDate", "n"=>"month", "v"=>/\d+/}
]

Note that matchers can contain regex patterns for values, like /d+/ in the example above.

When an input messages is received it typically contains several items, eg: [

{"cCI"=>"M0104", "n"=>"month", "v"=>"9", "age"=>"recent"},
{"cCI"=>"M0104", "n"=>"day", "v"=>"29", "age"=>"recent"},
{"cCI"=>"M0104", "n"=>"hour", "v"=>"17", "age"=>"recent"}

]

Each input item is matched against each of the matchers. If a match is found, it’s stored in the @results hash, with the matcher as the key, and a mesage and status as the key. In the example above, this matcher:

“cO”=>“setDate”, “n”=>“month”, “v”=>/d+/

matches this input:

“n”=>“month”, “v”=>“9”, “age”=>“recent”

And the result is stored as:

{"cCI"=>"M0104", "cO"=>"setDate", "n"=>"month", "v"=>/\d+/ =>
  { <StatusResponse message>, "cO"=>"setDate", "n"=>"month", "v"=>"9" }

}

Direct Known Subclasses

CommandResponseCollector, StatusCollector

Instance Attribute Summary collapse

Attributes inherited from Collector

#condition, #error, #m_id, #status, #task

Instance Method Summary collapse

Methods inherited from Collector

#acceptable?, #cancel, #cancelled?, #collect, #collect!, #collecting?, #complete, #describe_num_and_type, #describe_types, #do_stop, #identifier, #incomplete, #ingoing?, #inspect, #log_incomplete, #log_start, #make_title, #ok!, #ok?, #outgoing?, #ready?, #receive, #receive_disconnect, #receive_error, #receive_schema_error, #reject_not_ack, #reset, #start, #timeout?, #use_task, #wait, #wait!

Methods included from Receiver

#accept_message?, #handle_message, #initialize_receiver, #receive, #receive_error, #reject_message?, #start_receiving, #stop_receiving

Methods included from Inspect

#inspect, #inspector

Constructor Details

#initialize(proxy, want, options = {}) ⇒ StateCollector

Initialize with a list of wanted statuses

Raises:

  • (ArgumentError)


38
39
40
41
42
# File 'lib/rsmp/collect/state_collector.rb', line 38

def initialize proxy, want, options={}
  raise ArgumentError.new("num option cannot be used") if options[:num]
  super proxy, options
  @matchers = want.map { |item| build_matcher item }
end

Instance Attribute Details

#matchersObject (readonly)

Returns the value of attribute matchers.



35
36
37
# File 'lib/rsmp/collect/state_collector.rb', line 35

def matchers
  @matchers
end

Instance Method Details

#build_matcher(want) ⇒ Object

Build a matcher object. Sub-classes should override to use their own matcher classes.



46
47
48
# File 'lib/rsmp/collect/state_collector.rb', line 46

def build_matcher want
  Matcher.new want
end

#describeObject



116
117
118
# File 'lib/rsmp/collect/state_collector.rb', line 116

def describe
  @matchers.map {|q| q.want.to_s }
end

#describe_matcherObject

return a string that describes the attributes that we’re looking for



121
122
123
# File 'lib/rsmp/collect/state_collector.rb', line 121

def describe_matcher
  "#{super} matching #{matcher_want_hash.to_s}"
end

#describe_progressObject

return a string that describe how many many messages have been collected



154
155
156
157
158
# File 'lib/rsmp/collect/state_collector.rb', line 154

def describe_progress
  num_matchers = @matchers.size
  num_matched =  @matchers.count { |matcher| matcher.done? }
  ".. Matched #{num_matched}/#{num_matchers} with #{progress_hash.to_s}"
end

#done?Boolean

Are there matchers left to type_match?

Returns:

  • (Boolean)


75
76
77
# File 'lib/rsmp/collect/state_collector.rb', line 75

def done?
  @matchers.all? { |matcher| matcher.done? }
end

#keep(message) ⇒ Object

don’t collect anything. Matcher will collect them instead



113
114
# File 'lib/rsmp/collect/state_collector.rb', line 113

def keep message
end

#log_completeObject

log when we end collecting



209
210
211
# File 'lib/rsmp/collect/state_collector.rb', line 209

def log_complete
  @distributor.log "#{identifier}: Completed with #{matcher_got_hash.to_s}", level: :collect
end

#matcher_got_hashObject

return a hash that describe the end result



184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
# File 'lib/rsmp/collect/state_collector.rb', line 184

def matcher_got_hash
  h = {}
  @matchers.each do |matcher|
    want = matcher.want
    got = matcher.got
    if want['cCI']
      cCI = want['cCI']
      h[cCI] ||= {}
      cO = want['cO']
      h[cCI][cO] ||= {}
      n = want['n']
      v = got ? got['v'] : nil
      h[cCI][cO][n] = v
    elsif want['sCI']
      sCI = want['sCI']
      h[sCI] ||= {}
      n = want['n']
      s = got ? got['s'] : nil
      h[sCI][n] = s
    end
  end
  h
end

#matcher_result(want) ⇒ Object

Get a results



51
52
53
54
55
# File 'lib/rsmp/collect/state_collector.rb', line 51

def matcher_result want
  matcher = @matchers.find { |q| q.want == want}
  raise unless matcher
  matcher.got
end

#matcher_statusObject

Get a simplified hash of matchers, with values set to either true or false, indicating which matchers have been matched.



81
82
83
# File 'lib/rsmp/collect/state_collector.rb', line 81

def matcher_status
  @matchers.map { |matcher| [matcher.want, matcher.done?] }.to_h
end

#matcher_want_hashObject



160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
# File 'lib/rsmp/collect/state_collector.rb', line 160

def matcher_want_hash
  h = {}
  @matchers.each do |matcher|
    item = matcher.want
    if item['cCI']
      cCI = item['cCI']
      h[cCI] ||= {}
      cO = item['cO']
      h[cCI][cO] ||= {}
      n = item['n']
      v = item['v']
      h[cCI][cO][n] = v || :any
    elsif item['sCI']
      sCI = item['sCI']
      h[sCI] ||= {}
      n = item['n']
      s = item['s']
      h[sCI][n] = s || :any
    end
  end
  h
end

#messagesObject

Get messages from results



63
64
65
# File 'lib/rsmp/collect/state_collector.rb', line 63

def messages
  @matchers.map { |matcher| matcher.message }.uniq.compact
end

#perform_match(message) ⇒ Object

Check if a messages matches our criteria. Match each matcher against each item in the message



92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
# File 'lib/rsmp/collect/state_collector.rb', line 92

def perform_match message
  return false if super(message) == false
  return unless collecting?
  @matchers.each do |matcher|       # look through matchers
    get_items(message).each do |item|  # look through items in message
      matched = matcher.perform_match(item,message,@block)
      return unless collecting?
      if matched != nil
        type = {true=>'match',false=>'mismatch'}[matched]
        @distributor.log "#{@title.capitalize} #{message.m_id_short} collect #{type} #{matcher.want}, item #{item}", level: :debug
        if matched == true
          matcher.keep message, item
        elsif matched == false
          matcher.forget
        end
      end
    end
  end
end

#progressObject

Return progress as completes matchers vs. total number of matchers



68
69
70
71
72
# File 'lib/rsmp/collect/state_collector.rb', line 68

def progress
  need = @matchers.size
  reached =  @matchers.count { |matcher| matcher.done? }
  { need: need, reached: reached }
end

#progress_hashObject

return a hash that describe the status of all matchers



126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
# File 'lib/rsmp/collect/state_collector.rb', line 126

def progress_hash
  h = {}
  @matchers.each do |matcher|
    want = matcher.want
    if want['cCI']
      cCI = want['cCI']
      h[cCI] ||= {}
      cO = h['cO']
      n = h['n']
      v = h['v']
      h[cCI][cO] ||= {}
      h[cCI][cO][n] = v
    elsif want['sCI']
      sCI = want['sCI']
      h[sCI] ||= {}
      n = want['n']
      s = want['s']
      if matcher.got && matcher.got['s']
        h[sCI][n] = { {s=>matcher.got['s']} => matcher.done? }
      else
        h[sCI][n] = { s=>nil }
      end
    end
  end
  h
end

#reachedObject

Get an array of the last item received for each matcher



58
59
60
# File 'lib/rsmp/collect/state_collector.rb', line 58

def reached
  @matchers.map { |matcher| matcher.got }.compact
end

#summaryObject

Get a simply array of bools, showing which matchers have been matched.



86
87
88
# File 'lib/rsmp/collect/state_collector.rb', line 86

def summary
  @matchers.map { |matcher| matcher.done? }
end