class Sexp::Matcher

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.

If rdoc didn’t suck, these would all be links.

Public Class Methods

match_subs=(o) click to toggle source

Setter for match_subs?.

# File lib/sexp_matcher.rb, line 259
def self.match_subs= o
  @@match_subs = o
end
match_subs?() click to toggle source

Should =~ match sub-trees?

# File lib/sexp_matcher.rb, line 252
def self.match_subs?
  @@match_subs
end
parse(s) click to toggle source

Parse a lispy string representation of a matcher into a Matcher. See Parser.

# File lib/sexp_matcher.rb, line 390
def self.parse s
  Parser.new(s).parse
end

Public Instance Methods

&(other) click to toggle source

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)
# File lib/sexp_matcher.rb, line 341
def & other
  All.new self, other
end
-@() click to toggle source

Returns a Matcher that matches whenever this Matcher would not have matched

Example:

-s(:a)
# File lib/sexp_matcher.rb, line 351
def -@
  Not.new self
end
/(sexp) click to toggle source

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)]
# 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)
Alias for: =~
=~(sexp) click to toggle source

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

# 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
Also aliased as: ===
>>(other) click to toggle source

Returns a Matcher that matches if this has a sibling o

Example:

s(:a) >> s(:b)
# File lib/sexp_matcher.rb, line 361
def >> other
  Sibling.new self, other
end
greedy?() click to toggle source

Is this matcher greedy? Defaults to false.

# File lib/sexp_matcher.rb, line 368
def greedy?
  false
end
satisfy?(o) click to toggle source

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.

# 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
|(other) click to toggle source

Combines the Matcher with another Matcher, the resulting one will be satisfied if either Matcher would be satisfied.

TODO: redirect Example:

s(:a) | s(:b)
# File lib/sexp_matcher.rb, line 329
def | other
  Any.new self, other
end