Class: Roby::Interface

Inherits:
Object show all
Defined in:
lib/roby/interface.rb

Overview

This class is used to interface with the Roby event loop and plan. It is the main front object when accessing a Roby core remotely

Defined Under Namespace

Modules: GatherExceptions

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(control) ⇒ Interface

Creates a local server for a remote interface, acting on control



198
199
200
201
202
203
204
# File 'lib/roby/interface.rb', line 198

def initialize(control)
    @control        = control
    @pending_messages = Queue.new

    Roby::Control.extend GatherExceptions
    Roby::Control.register_interface self
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(name, *args) ⇒ Object

Tries to find a planner method which matches name with args. If it finds one, creates a task planned by a planning task and yields both



358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
# File 'lib/roby/interface.rb', line 358

def method_missing(name, *args)
    if name.to_s =~ /!$/
  name = $`.to_sym
    else
  super
    end

    if args.size > 1
  raise ArgumentError, "wrong number of arguments (#{args.size} for 1) in #{name}!"
    end

    options = args.first || {}
    task, planner = Robot.prepare_action(name, options)
    begin
  Roby.wait_until(planner.event(:success)) do
      control.plan.insert(task)
      yield(task, planner) if block_given?
  end
    rescue Roby::UnreachableEvent
  raise RuntimeError, "cannot start #{name}: #{planner.terminal_event.context.first}"
    end

           Roby.execute do
               result = planner.result
               result.on(:failed) { |ev| pending_messages << "task #{ev.task} failed" }
               result.on(:success) { |ev| pending_messages << "task #{ev.task} finished successfully" }
               RemoteObjectProxy.new(result)
           end
end

Instance Attribute Details

#controlObject (readonly)

The Roby::Control object this interface is working on



194
195
196
# File 'lib/roby/interface.rb', line 194

def control
  @control
end

#pending_messagesObject (readonly)

The set of pending messages that are to be displayed on the remote interface



196
197
198
# File 'lib/roby/interface.rb', line 196

def pending_messages
  @pending_messages
end

Instance Method Details

#actionsObject

Displays the set of actions which are available through the planners registered on #control. See Control#planners



289
290
291
292
293
294
# File 'lib/roby/interface.rb', line 289

def actions
    control.planners.
  map { |p| p.planning_methods_names.to_a }.
  flatten.
  sort
end

#call(task, m, *args) ⇒ Object

Synchronously call m on tasks with the given arguments. This, along with the implementation of RemoteInterface#method_missing, ensures that no interactive operations are performed outside the control thread.



223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
# File 'lib/roby/interface.rb', line 223

def call(task, m, *args)
    Roby.execute do
               if m.to_s =~ /!$/
                   event_name = $`
                   # Check if the called event is terminal. If it is the case,
                   # discard the task before calling it, and make sure the user
                   # will get a message
                   #
                   if task.event(event_name).terminal?
                       plan.discard(task)
                       task.on(:stop) { |ev| pending_messages << "task #{ev.task} stopped by user request" }
                   else
                       task.on(event_name) { |ev| pending_messages << "done emitting #{ev.generator}" }
                   end
               end

  task.send(m, *args)
    end
end

#clearObject

Clear the current plan: remove all running and permanent tasks.



207
208
209
210
211
212
# File 'lib/roby/interface.rb', line 207

def clear
    Roby.execute do
  plan.missions.dup.each  { |t| plan.discard(t) }
  plan.keepalive.dup.each { |t| plan.auto(t) }
    end
end

#find_tasks(model = nil, args = nil) ⇒ Object



243
244
245
# File 'lib/roby/interface.rb', line 243

def find_tasks(model = nil, args = nil)
    plan.find_tasks(model, args)
end

#methodsObject



340
341
342
343
# File 'lib/roby/interface.rb', line 340

def methods
    result = super
    result + actions.map { |n| "#{n}!" }
end

#missionsObject

Returns a string representing the set of missions



327
328
329
330
331
# File 'lib/roby/interface.rb', line 327

def missions
    Roby.execute do
  task_set_to_s(control.plan.missions)
    end
end

#modelsObject

Displays the set of models as well as their superclasses



274
275
276
277
278
279
280
281
282
283
284
285
# File 'lib/roby/interface.rb', line 274

def models
    task_models = []
    Roby.execute do
  ObjectSpace.each_object(Class) do |obj|
      task_models << obj if obj <= Roby::Task && obj.name !~ /^Roby::/
  end
    end

    task_models.map do |model|
  "#{model} #{model.superclass}"
    end
end

#planObject

The Roby plan



217
# File 'lib/roby/interface.rb', line 217

def plan; Roby.plan end

#poll_messagesObject

Called every once in a while by RemoteInterface to read and clear the set of pending messages.



347
348
349
350
351
352
353
354
# File 'lib/roby/interface.rb', line 347

def poll_messages
    result = []
    while !pending_messages.empty?
  msg = pending_messages.pop
  result << msg
    end
    result
end

#reloadObject

WARNING: does not work for now



268
269
270
271
# File 'lib/roby/interface.rb', line 268

def reload
    Roby.app.reload
    nil
end

#remote_constant(name) ⇒ Object

Returns a DRbObject on the given named constant. Use this to get a remote interface to a given object, not taking into account its ‘marshallability’



261
262
263
# File 'lib/roby/interface.rb', line 261

def remote_constant(name)
    DRbObject.new(name.to_s.constantize)
end

#remote_query_result_set(m_query) ⇒ Object

For using Query on Interface objects



248
249
250
251
# File 'lib/roby/interface.rb', line 248

def remote_query_result_set(m_query) # :nodoc:
    plan.query_result_set(m_query.to_query(plan)).
  map { |t| RemoteObjectProxy.new(t) }
end

#remote_query_roots(result_set, m_relation) ⇒ Object

For using Query on Interface objects



253
254
255
256
# File 'lib/roby/interface.rb', line 253

def remote_query_roots(result_set, m_relation) # :nodoc:
    plan.query_roots(result_set, m_relation.proxy(nil)).
  map { |t| RemoteObjectProxy.new(t) }
end

#running_tasksObject

Returns a string representing the set of running tasks



320
321
322
323
324
# File 'lib/roby/interface.rb', line 320

def running_tasks
    Roby.execute do
  task_set_to_s(Roby.plan.find_tasks.running.to_a)
    end
end

#stopObject

Make the Roby event loop quit



215
# File 'lib/roby/interface.rb', line 215

def stop; control.quit; nil end

#task_set_to_s(task_set) ⇒ Object

Pretty-prints a set of tasks



297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
# File 'lib/roby/interface.rb', line 297

def task_set_to_s(task_set) # :nodoc:
    if task_set.empty?
  return "no tasks"
    end

    task = task_set.map do |task|
  state_name = %w{pending starting running finishing finished}.find do |state_name|
      task.send("#{state_name}?")
  end

  start_event = task.history.find { |ev| ev.symbol == :start }
               since = if start_event then start_event.time
                       else 'N/A'
                       end
  { 'Task' => task.to_s, 'Since' => since, 'State' => state_name }
    end

    io = StringIO.new
    ColumnFormatter.from_hashes(task, io) { %w{Task Since State} }
    "\n#{io.string}"
end

#tasksObject

Returns a string representing the set of tasks present in the plan



334
335
336
337
338
# File 'lib/roby/interface.rb', line 334

def tasks
    Roby.execute do 
  task_set_to_s(Roby.plan.known_tasks)
    end
end