Class: Roby::Queries::PlanObjectMatcher
- Inherits:
-
MatcherBase
- Object
- MatcherBase
- Roby::Queries::PlanObjectMatcher
- Defined in:
- lib/roby/queries/plan_object_matcher.rb,
lib/roby/droby/enable.rb
Overview
Predicate that matches characteristics on a plan object
Direct Known Subclasses
EventGeneratorMatcher, TaskEventGeneratorMatcher, TaskMatcher
Instance Attribute Summary collapse
-
#children ⇒ Hash
readonly
private
Per relation list of out-edges that the matched object is expected to have.
-
#indexed_neg_predicates ⇒ Array<Symbol>
readonly
private
Set of predicates that should be false on the object, and for which the index maintains a set of objects for which it is true.
-
#indexed_predicates ⇒ Array<Symbol>
readonly
private
Set of predicates that should be true on the object, and for which the index maintains a set of objects for which it is true.
-
#instance ⇒ nil, Object
readonly
private
The actual instance that should match.
-
#model ⇒ Array<Class>
readonly
private
A set of models that should be provided by the object.
-
#owners ⇒ Array<DRobyID>
readonly
private
Set of owners that the object should have.
-
#parents ⇒ Hash
readonly
private
Per-relation list of in-edges that the matched object is expected to have.
Attributes inherited from MatcherBase
Class Method Summary collapse
Instance Method Summary collapse
-
#===(object) ⇒ Boolean
Tests whether the given object matches this predicate.
-
#executable? ⇒ Object
:method: not_executable.
-
#filter(initial_set, index, initial_is_complete: false) ⇒ Set
Filters the tasks in
initial_setby using the information inindex, and returns the result. -
#handle_parent_child_arguments(other_query, relation, relation_options) ⇒ Object
Helper method for #with_child and #with_parent.
-
#handle_parent_child_match(object, match_spec) ⇒ Object
Helper method for handling parent/child matches in #===.
-
#indexed_query? ⇒ Boolean
Returns true if filtering with this TaskMatcher using #=== is equivalent to calling #filter() using a Index.
-
#indexed_sets(index) ⇒ (Set,Set)
private
Resolve the indexed sets needed to filter an initial set in #filter.
-
#initialize(instance = nil) ⇒ PlanObjectMatcher
constructor
Initializes an empty TaskMatcher object.
-
#not_self_owned ⇒ Object
Filters out locally-owned tasks.
-
#owned_by(*ids) ⇒ Object
Filters on ownership.
-
#self_owned ⇒ Object
Filters locally-owned tasks.
- #to_s ⇒ Object
-
#with_child(other_query, relation = nil, relation_options = nil) ⇒ Object
Filters based on the object’s children.
-
#with_instance(instance) ⇒ Object
Match an instance explicitely.
-
#with_model(model) ⇒ Object
Filters on the task model.
-
#with_parent(other_query, relation = nil, relation_options = nil) ⇒ Object
Filters based on the object’s parents.
Methods included from DRoby::V5::Queries::PlanObjectMatcherDumper
Methods inherited from MatcherBase
#&, declare_class_methods, #describe_failed_match, #each, #match, match_predicates, #negate, #|
Constructor Details
#initialize(instance = nil) ⇒ PlanObjectMatcher
Initializes an empty TaskMatcher object
57 58 59 60 61 62 63 64 65 66 67 68 |
# File 'lib/roby/queries/plan_object_matcher.rb', line 57 def initialize(instance = nil) @instance = instance @indexed_query = !@instance @model = Array.new @predicates = Array.new @neg_predicates = Array.new @indexed_predicates = Array.new @indexed_neg_predicates = Array.new @owners = Array.new @parents = Hash.new @children = Hash.new end |
Instance Attribute Details
#children ⇒ Hash (readonly)
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.
Per relation list of out-edges that the matched object is expected to have
54 55 56 |
# File 'lib/roby/queries/plan_object_matcher.rb', line 54 def children @children end |
#indexed_neg_predicates ⇒ Array<Symbol> (readonly)
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.
Set of predicates that should be false on the object, and for which the index maintains a set of objects for which it is true
40 41 42 |
# File 'lib/roby/queries/plan_object_matcher.rb', line 40 def indexed_neg_predicates @indexed_neg_predicates end |
#indexed_predicates ⇒ Array<Symbol> (readonly)
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.
Set of predicates that should be true on the object, and for which the index maintains a set of objects for which it is true
32 33 34 |
# File 'lib/roby/queries/plan_object_matcher.rb', line 32 def indexed_predicates @indexed_predicates end |
#instance ⇒ nil, Object (readonly)
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.
The actual instance that should match
10 11 12 |
# File 'lib/roby/queries/plan_object_matcher.rb', line 10 def instance @instance end |
#model ⇒ Array<Class> (readonly)
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.
A set of models that should be provided by the object
17 18 19 |
# File 'lib/roby/queries/plan_object_matcher.rb', line 17 def model @model end |
#owners ⇒ Array<DRobyID> (readonly)
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.
Set of owners that the object should have
24 25 26 |
# File 'lib/roby/queries/plan_object_matcher.rb', line 24 def owners @owners end |
#parents ⇒ Hash (readonly)
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.
Per-relation list of in-edges that the matched object is expected to have
47 48 49 |
# File 'lib/roby/queries/plan_object_matcher.rb', line 47 def parents @parents end |
Class Method Details
.match_predicate(name, positive_index = nil, negative_index = nil) ⇒ Object
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.
114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 |
# File 'lib/roby/queries/plan_object_matcher.rb', line 114 def match_predicate(name, positive_index = nil, negative_index = nil) method_name = name.to_s.gsub(/\?$/, '') if Index::PREDICATES.include?(name) indexed_predicate = true positive_index ||= [["#{name}"], []] negative_index ||= [[], ["#{name}"]] end positive_index ||= [[], []] negative_index ||= [[], []] class_eval " def \#{method_name}\n if neg_predicates.include?(:\#{name})\n raise ArgumentError, \"trying to match (\#{name} & !\#{name})\"\n end\n \#{\"@indexed_query = false\" if !indexed_predicate}\n predicates << :\#{name}\n \#{if !positive_index[0].empty? then [\"indexed_predicates\", *positive_index[0]].join(\" << :\") end}\n \#{if !positive_index[1].empty? then [\"indexed_neg_predicates\", *positive_index[1]].join(\" << :\") end}\n self\n end\n def not_\#{method_name}\n if predicates.include?(:\#{name})\n raise ArgumentError, \"trying to match (\#{name} & !\#{name})\"\n end\n \#{\"@indexed_query = false\" if !indexed_predicate}\n neg_predicates << :\#{name}\n \#{if !negative_index[0].empty? then [\"indexed_predicates\", *negative_index[0]].join(\" << :\") end}\n \#{if !negative_index[1].empty? then [\"indexed_neg_predicates\", *negative_index[1]].join(\" << :\") end}\n self\n end\n EOD\n declare_class_methods(method_name, \"not_\#{method_name}\")\nend\n", __FILE__, __LINE__+1 |
Instance Method Details
#===(object) ⇒ Boolean
Tests whether the given object matches this predicate
267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 |
# File 'lib/roby/queries/plan_object_matcher.rb', line 267 def ===(object) if instance return false if object != instance end if !model.empty? return unless object.fullfills?(model) end for parent_spec in @parents result = handle_parent_child_match(object, parent_spec) do |relation, m, | object.each_parent_object(relation). any? { |parent| m === parent && (! || === parent[object, relation]) } end return false if !result end for child_spec in @children result = handle_parent_child_match(object, child_spec) do |relation, m, | object.each_child_object(relation). any? { |child| m === child && (! || === object[child, relation]) } end return false if !result end for pred in predicates return false if !object.send(pred) end for pred in neg_predicates return false if object.send(pred) end return false if !owners.empty? && !(object.owners - owners).empty? true end |
#executable? ⇒ Object
:method: not_executable
Matches if the object is not executable
See also #executable, PlanObject#executable?
163 |
# File 'lib/roby/queries/plan_object_matcher.rb', line 163 match_predicates :executable? |
#filter(initial_set, index, initial_is_complete: false) ⇒ Set
Filters the tasks in initial_set by using the information in index, and returns the result. The resulting set must include all tasks in initial_set which match with #===, but can include tasks which do not match #===
341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 |
# File 'lib/roby/queries/plan_object_matcher.rb', line 341 def filter(initial_set, index, initial_is_complete: false) positive_sets, negative_sets = indexed_sets(index) positive_sets << initial_set if !initial_is_complete || positive_sets.empty? negative = negative_sets.shift || Set.new if negative_sets.size > 1 negative = negative.dup negative_sets.each { |set| negative.merge(set) } end positive_sets = positive_sets.sort_by(&:size) result = Set.new result.compare_by_identity positive_sets.shift.each do |obj| result.add(obj) if !negative.include?(obj) && positive_sets.all? { |set| set.include?(obj) } end return result end |
#handle_parent_child_arguments(other_query, relation, relation_options) ⇒ Object
Helper method for #with_child and #with_parent
168 169 170 |
# File 'lib/roby/queries/plan_object_matcher.rb', line 168 def handle_parent_child_arguments(other_query, relation, ) # :nodoc: return relation, [other_query.match, ] end |
#handle_parent_child_match(object, match_spec) ⇒ Object
Helper method for handling parent/child matches in #===
224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 |
# File 'lib/roby/queries/plan_object_matcher.rb', line 224 def handle_parent_child_match(object, match_spec) # :nodoc: relation, matchers = *match_spec return false if !relation && object.relations.empty? for match_spec in matchers m, = *match_spec if relation if !yield(relation, m, ) return false end else result = object.relations.any? do |rel| yield(rel, m, ) end return false if !result end end true end |
#indexed_query? ⇒ Boolean
Returns true if filtering with this TaskMatcher using #=== is equivalent to calling #filter() using a Index. This is used to avoid an explicit O(N) filtering step after filter() has been called
246 247 248 |
# File 'lib/roby/queries/plan_object_matcher.rb', line 246 def indexed_query? @indexed_query end |
#indexed_sets(index) ⇒ (Set,Set)
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.
Resolve the indexed sets needed to filter an initial set in #filter
309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 |
# File 'lib/roby/queries/plan_object_matcher.rb', line 309 def indexed_sets(index) positive_sets = [] for m in @model positive_sets << index.by_model[m] end for o in @owners if candidates = index.by_owner[o] positive_sets << candidates else return [Set.new, Set.new] end end for pred in @indexed_predicates positive_sets << index.by_predicate[pred] end negative_sets = @indexed_neg_predicates. map { |pred| index.by_predicate[pred] } return positive_sets, negative_sets end |
#not_self_owned ⇒ Object
Filters out locally-owned tasks
Matches if the object is owned by the local plan manager.
98 99 100 101 |
# File 'lib/roby/queries/plan_object_matcher.rb', line 98 def not_self_owned neg_predicates << :self_owned? self end |
#owned_by(*ids) ⇒ Object
Filters on ownership
Matches if the object is owned by the listed peers.
Use #self_owned to match if it is owned by the local plan manager.
82 83 84 85 |
# File 'lib/roby/queries/plan_object_matcher.rb', line 82 def owned_by(*ids) @owners |= ids self end |
#self_owned ⇒ Object
Filters locally-owned tasks
Matches if the object is owned by the local plan manager.
90 91 92 93 |
# File 'lib/roby/queries/plan_object_matcher.rb', line 90 def self_owned predicates << :self_owned? self end |
#to_s ⇒ Object
250 251 252 253 254 255 256 257 258 259 260 |
# File 'lib/roby/queries/plan_object_matcher.rb', line 250 def to_s description = if instance instance.to_s elsif model.size == 1 model.first.to_s else "(#{model.map(&:to_s).join(",")})" end ([description] + predicates.map(&:to_s) + neg_predicates.map { |p| "not_#{p}" }).join(".") end |
#with_child(other_query, relation = nil, relation_options = nil) ⇒ Object
Filters based on the object’s children
Matches if this object has at least one child which matches query.
If relation is given, then only the children in this relation are considered. Moreover, relation options can be used to restrict the search even more.
Examples:
parent.depends_on(child)
TaskMatcher.new.
with_child(TaskMatcher.new.pending) === parent # => true
TaskMatcher.new.
with_child(TaskMatcher.new.pending, Roby::TaskStructure::Dependency) === parent # => true
TaskMatcher.new.
with_child(TaskMatcher.new.pending, Roby::TaskStructure::PlannedBy) === parent # => false
TaskMatcher.new.
with_child(TaskMatcher.new.pending,
Roby::TaskStructure::Dependency,
roles: ["trajectory_following"]) === parent # => false
parent.depends_on child, role: "trajectory_following"
TaskMatcher.new.
with_child(TaskMatcher.new.pending,
Roby::TaskStructure::Dependency,
roles: ["trajectory_following"]) === parent # => true
200 201 202 203 204 205 |
# File 'lib/roby/queries/plan_object_matcher.rb', line 200 def with_child(other_query, relation = nil, = nil) relation, spec = handle_parent_child_arguments(other_query, relation, ) (@children[relation] ||= Array.new) << spec @indexed_query = false self end |
#with_instance(instance) ⇒ Object
Match an instance explicitely
71 72 73 74 75 |
# File 'lib/roby/queries/plan_object_matcher.rb', line 71 def with_instance(instance) @instance = instance @indexed_query = false self end |
#with_model(model) ⇒ Object
Filters on the task model
Will match if the task is an instance of model or one of its subclasses.
107 108 109 110 |
# File 'lib/roby/queries/plan_object_matcher.rb', line 107 def with_model(model) @model = Array(model) self end |
#with_parent(other_query, relation = nil, relation_options = nil) ⇒ Object
Filters based on the object’s parents
Matches if this object has at least one parent which matches query.
If relation is given, then only the parents in this relation are considered. Moreover, relation options can be used to restrict the search even more.
See examples for #with_child
216 217 218 219 220 221 |
# File 'lib/roby/queries/plan_object_matcher.rb', line 216 def with_parent(other_query, relation = nil, = nil) relation, spec = handle_parent_child_arguments(other_query, relation, ) (@parents[relation] ||= Array.new) << spec @indexed_query = false self end |