Class: Sexp::Matcher
Overview
Defines a family of objects that can be used to match sexps to certain types of patterns, much like regexps can be used on strings. Generally you won’t use this class directly.
You would normally create a matcher using the top-level #s method, but with a block, calling into the Sexp factory methods. For example:
s{ s(:class, m(/^Test/), _, ___) }
This creates a matcher for classes whose names start with “Test”. It uses Sexp.m to create a Sexp::Matcher::Pattern matcher, Sexp._ to create a Sexp::Matcher::Wild matcher, and Sexp._ to create a Sexp::Matcher::Remaining matcher. It works like this:
s{ # start to create a pattern
s( # create a sexp matcher
:class. # for class nodes
m(/^Test/), # matching name slots that start with "Test"
_, # any superclass value
___ # and whatever is in the class
)
}
Then you can use that with #=~, #/, Sexp#replace_sexp, and others.
For more examples, see the various Sexp class methods, the examples, and the tests supplied with Sexp.
-
For pattern creation, see factory methods: Sexp::_, Sexp::_, etc.
-
For matching returning truthy/falsey results, see Sexp#=~.
-
For case expressions, see Matcher#===.
-
For getting all subtree matches, see Sexp#/.
If rdoc didn’t suck, these would all be links.
Direct Known Subclasses
All, Any, Atom, Child, Include, Not, Pattern, Remaining, Sibling, Type, Wild
Defined Under Namespace
Classes: Parser
Constant Summary
Constants inherited from Sexp
Instance Attribute Summary
Attributes inherited from Sexp
#comments, #file, #line, #line_max
Class Method Summary collapse
-
.match_subs=(o) ⇒ Object
Setter for
match_subs?
. -
.match_subs? ⇒ Boolean
Should #=~ match sub-trees?.
-
.parse(s) ⇒ Object
Parse a lispy string representation of a matcher into a Matcher.
Instance Method Summary collapse
-
#&(other) ⇒ Object
Combines the Matcher with another Matcher, the resulting one will be satisfied only if both Matchers would be satisfied.
-
#-@ ⇒ Object
Returns a Matcher that matches whenever this Matcher would not have matched.
-
#/(sexp) ⇒ Object
Searches through
sexp
for all sub-trees that match this matcher and returns a MatchCollection for each match. -
#=~(sexp) ⇒ Object
(also: #===)
Tree equivalent to String#=~, returns true if
self
matchessexp
as a whole or in a sub-tree (ifmatch_subs?
). -
#>>(other) ⇒ Object
Returns a Matcher that matches if this has a sibling
o
. -
#greedy? ⇒ Boolean
Is this matcher greedy? Defaults to false.
-
#inspect ⇒ Object
:nodoc:.
-
#pretty_print(q) ⇒ Object
:nodoc:.
-
#satisfy?(o) ⇒ Boolean
Does this matcher actually match
o
? Returns falsey ifo
is not a Sexp or if any sub-tree ofo
is not satisfied by or equal to its corresponding sub-matcher. -
#|(other) ⇒ Object
Combines the Matcher with another Matcher, the resulting one will be satisfied if either Matcher would be satisfied.
Methods inherited from Sexp
#==, _, ___, all, any, #array_type?, atom, child, #compact, #deep_each, #depth, #each_of_type, #each_sexp, #eql?, #find_and_replace_all, #find_node, #find_nodes, from_array, #gsub, #hash, include, #initialize, k, m, #map, #mass, #method_missing, #new, not?, q, #replace_sexp, #respond_to?, s, #search_each, #sexp_body, #sexp_body=, #sexp_type, #sexp_type=, #shift, #structure, #sub, t, #to_a, #value
Constructor Details
This class inherits a constructor from Sexp
Dynamic Method Handling
This class handles dynamic methods through the method_missing method in the class Sexp
Class Method Details
.match_subs=(o) ⇒ Object
Setter for match_subs?
.
259 260 261 |
# File 'lib/sexp_matcher.rb', line 259 def self.match_subs= o @@match_subs = o end |
.match_subs? ⇒ Boolean
Should #=~ match sub-trees?
252 253 254 |
# File 'lib/sexp_matcher.rb', line 252 def self.match_subs? @@match_subs end |
Instance Method Details
#&(other) ⇒ Object
Combines the Matcher with another Matcher, the resulting one will be satisfied only if both Matchers would be satisfied.
TODO: redirect Example:
t(:a) & include(:b)
341 342 343 |
# File 'lib/sexp_matcher.rb', line 341 def & other All.new self, other end |
#/(sexp) ⇒ Object
Searches through sexp
for all sub-trees that match this matcher and returns a MatchCollection for each match.
TODO: redirect? Example:
Q{ s(:b) } / s(:a, s(:b)) => [s(:b)]
314 315 316 317 318 319 |
# File 'lib/sexp_matcher.rb', line 314 def / sexp raise ArgumentError, "can't both be matchers" if Matcher === sexp # TODO: move search_each into matcher? MatchCollection.new sexp.search_each(self).to_a end |
#=~(sexp) ⇒ Object Also known as: ===
Tree equivalent to String#=~, returns true if self
matches sexp
as a whole or in a sub-tree (if match_subs?
).
TODO: maybe this should NOT be aliased to === ?
TODO: example
297 298 299 300 301 302 |
# File 'lib/sexp_matcher.rb', line 297 def =~ sexp raise ArgumentError, "Can't both be matchers: %p" % [sexp] if Matcher === sexp self.satisfy?(sexp) || (self.class.match_subs? && sexp.each_sexp.any? { |sub| self =~ sub }) end |
#>>(other) ⇒ Object
361 362 363 |
# File 'lib/sexp_matcher.rb', line 361 def >> other Sibling.new self, other end |
#greedy? ⇒ Boolean
Is this matcher greedy? Defaults to false.
368 369 370 |
# File 'lib/sexp_matcher.rb', line 368 def greedy? false end |
#inspect ⇒ Object
:nodoc:
372 373 374 375 376 |
# File 'lib/sexp_matcher.rb', line 372 def inspect # :nodoc: s = super.dup s[0] = "q" s end |
#pretty_print(q) ⇒ Object
:nodoc:
378 379 380 381 382 383 384 |
# File 'lib/sexp_matcher.rb', line 378 def pretty_print q # :nodoc: q.group 1, "q(", ")" do q.seplist self do |v| q.pp v end end end |
#satisfy?(o) ⇒ Boolean
Does this matcher actually match o
? Returns falsey if o
is not a Sexp or if any sub-tree of o
is not satisfied by or equal to its corresponding sub-matcher.
– TODO: push this up to Sexp and make this the workhorse TODO: do the same with ===/satisfy?
274 275 276 277 278 279 280 281 282 283 284 285 286 287 |
# File 'lib/sexp_matcher.rb', line 274 def satisfy? o return unless o.kind_of?(Sexp) && (length == o.length || Matcher === last && last.greedy?) each_with_index.all? { |child, i| sexp = o.at i if Sexp === child then # TODO: when will this NOT be a matcher? sexp = o.sexp_body i if child.respond_to?(:greedy?) && child.greedy? child.satisfy? sexp else child == sexp end } end |