Class: Amp::Match

Inherits:
Object show all
Extended by:
Ignore
Defined in:
lib/amp/support/match.rb

Overview

Match

In this project, we came to a fork in the road: port the match class, 200+ lines of strange and convoluted Python, or write our own matcher. We chose to write our own matcher, and it was originally just a proc that would be passed around. After a few days of working with that, we then decided that it would be best to do our own implementation of their Match class, because we needed access to three things from this one object: the explicit files passed, the includes, and the excludes.

Constant Summary

Constants included from Ignore

Ignore::COMMENT, Ignore::SYNTAXES

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Ignore

matcher_for_string, matcher_for_text, parse_ignore, parse_line, parse_lines, regexps_to_proc

Constructor Details

#initialize(*args, &block) ⇒ Match

args can either be a hash (with a block supplied separately) or a list of arguments in the form of:

files, includes, excludes, &block

The block should be used for things that can’t be represented as regular expressions. Thus, everything taken from the command line is presented as either an include or an exclude, because blocks are impossible from the console.

Examples:

Match.new :files => [] do |file|
  file =~ /test_(.+).rb$/
end

Match.new :include => /.rbc$/

Match.new([]) {|file| file =~ /test_(.+).rb$/ }

Parameters:

  • Hash, (Hash, [#include?, Regexp, Regexp] either a hash or arrays in the order of: files, include, exclude)
    #include?, Regexp, Regexp

    either a hash or

    arrays in the order of: files, include, exclude



76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
# File 'lib/amp/support/match.rb', line 76

def initialize(*args, &block)
  if (hash = args.first).is_a? Hash
    @files   = hash[:files]   || []
    @include = hash[:include]
    @exclude = hash[:exclude]
    
  else
    files, include_, exclude, block = *args
    
    @files   = files    || []
    @include = include_
    @exclude = exclude
  end
  
  @block = block || proc { false }
end

Instance Attribute Details

#blockObject (readonly)

Returns the value of attribute block.



15
16
17
# File 'lib/amp/support/match.rb', line 15

def block
  @block
end

#excludeObject (readonly)

Returns the value of attribute exclude.



18
19
20
# File 'lib/amp/support/match.rb', line 18

def exclude
  @exclude
end

#filesObject (readonly)

Returns the value of attribute files.



16
17
18
# File 'lib/amp/support/match.rb', line 16

def files
  @files
end

#includeObject (readonly)

Returns the value of attribute include.



17
18
19
# File 'lib/amp/support/match.rb', line 17

def include
  @include
end

Class Method Details

.create(*args, &block) ⇒ Object

Very similar to #new – the only difference is that instead of having to pass Regexps as :include or :exclude, you pass in strings, and the strings are parsed and converted into regexps. This is really the same as #initialize.

Parameters:

See Also:

  • new


29
30
31
32
33
34
35
36
# File 'lib/amp/support/match.rb', line 29

def self.create(*args, &block)
  args  = args.first
  includer, excluder = regexp_for(args[:includer]), regexp_for(args[:excluder])

  new :files   => args[:files],
      :include => includer,
      :exclude => excluder, &block
end

.regexp_for(arg) ⇒ Regexp

To remove code duplication. This will return a regexp given arg If arg is a string, it will turn it into a Regexp. If it’s a Regexp, it returns arg.

This is called from Match::create, so it needs to be a class method (duh)

Parameters:

Returns:

  • (Regexp)


47
48
49
50
51
52
53
54
55
56
# File 'lib/amp/support/match.rb', line 47

def self.regexp_for(arg)
  case arg
  when Regexp
    [arg]
  when Array
    matcher_for_text arg.join("\n") if arg.any?
  when String
    [matcher_for_string(arg)]  if arg.any?
  end
end

Instance Method Details

#approximate?(file) ⇒ Boolean

Is it an approximate match?

Parameters:

  • file (String)

    the file to test

Returns:

  • (Boolean)

    is it an approximate match?



144
145
146
147
148
# File 'lib/amp/support/match.rb', line 144

def approximate?(file)
  return false if exact? file
  return false if (@include.nil? && @block.nil?)
  included?(file) || (@block && @block.call(file))
end

#call(file) ⇒ Boolean Also known as: []

Is it an exact match or an approximate match and not a file to be excluded?

If a file is to be both included and excluded, all hell is let loose. You have been warned.

Parameters:

  • file (String)

    the file to test

Returns:



121
122
123
124
125
126
127
# File 'lib/amp/support/match.rb', line 121

def call(file)
  if exact? file and failure? file
    raise StandardError.new("File #{file.inspect} is to be both included and excluded")
  end
  # `and` because it's loosely binding
  exact?(file) || included?(file) || approximate?(file) and !failure?(file)
end

#exact?(file) ⇒ Boolean

Is file an exact match?

Parameters:

  • file (String)

    the file to test

Returns:

  • (Boolean)

    is it an exact match?



98
99
100
# File 'lib/amp/support/match.rb', line 98

def exact?(file)
  @files.include?(file)
end

#failure?(file) ⇒ Boolean

Is this file being excluded? Does it automatically fail?

Parameters:

  • file (String)

    the file to test

Returns:

  • (Boolean)

    is it a failure match?



108
109
110
# File 'lib/amp/support/match.rb', line 108

def failure?(file)
  @exclude && @exclude.any? {|r| file =~ r}
end

#included?(file) ⇒ Boolean

Is it to be included?

Parameters:

  • file (String)

    the file to test

Returns:

  • (Boolean)

    is it to be included?



135
136
137
# File 'lib/amp/support/match.rb', line 135

def included?(file)
  @include && @include.any? {|r| file =~ r}
end