Class: Buildr::Filter

Inherits:
Object show all
Defined in:
lib/buildr/core/filter.rb

Overview

A filter knows how to copy files from one directory to another, applying mappings to the contents of these files.

You can specify the mapping using a Hash, and it will map $key fields found in each source file into the appropriate value in the target file. For example:

filter.using 'version'=>'1.2', 'build'=>Time.now

will replace all occurrences of ${version} with 1.2, and ${build} with the current date/time.

You can also specify the mapping by passing a proc or a method, that will be called for each source file, with the file name and content, returning the modified content.

Without any mapping, the filter simply copies files from the source directory into the target directory.

A filter has one target directory, but you can specify any number of source directories, either when creating the filter or calling #from. Include/exclude patterns are specified relative to the source directories, so:

filter.include '*.png'

will only include PNG files from any of the source directories.

See Buildr#filter.

Defined Under Namespace

Classes: Mapper

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeFilter

:nodoc:



48
49
50
# File 'lib/buildr/core/filter.rb', line 48

def initialize #:nodoc:
  clear
end

Instance Attribute Details

#sourcesObject (readonly)

Returns the list of source directories (each being a file task).



53
54
55
# File 'lib/buildr/core/filter.rb', line 53

def sources
  @sources
end

#targetObject (readonly)

The target directory as a file task.



80
81
82
# File 'lib/buildr/core/filter.rb', line 80

def target
  @target
end

Instance Method Details

#clearObject

:call-seq:

clear => self

Clear filter sources and include/exclude patterns



59
60
61
62
63
64
65
# File 'lib/buildr/core/filter.rb', line 59

def clear
  @include = []
  @exclude = []
  @sources = FileList[]
  @mapper = Mapper.new
  self
end

#exclude(*files) ⇒ Object

:call-seq:

exclude(*files) => self

Specifies files to exclude and returns self. See FileList#exclude.



111
112
113
114
# File 'lib/buildr/core/filter.rb', line 111

def exclude(*files)
  @exclude += files
  self
end

#from(*sources) ⇒ Object

:call-seq:

from(*sources) => self

Adds additional directories from which to copy resources.

For example:

filter.from('src').into('target').using('build'=>Time.now)


74
75
76
77
# File 'lib/buildr/core/filter.rb', line 74

def from(*sources)
  @sources |= sources.flatten.map { |dir| file(File.expand_path(dir.to_s)) }
  self
end

#include(*files) ⇒ Object Also known as: add

:call-seq:

include(*files) => self

Specifies files to include and returns self. See FileList#include.

By default all files are included. You can use this method to only include specific files from the source directory.



101
102
103
104
# File 'lib/buildr/core/filter.rb', line 101

def include(*files)
  @include += files
  self
end

#into(dir) ⇒ Object

:call-seq:

into(dir) => self

Sets the target directory into which files are copied and returns self.

For example:

filter.from('src').into('target').using('build'=>Time.now)


89
90
91
92
# File 'lib/buildr/core/filter.rb', line 89

def into(dir)
  @target = file(File.expand_path(dir.to_s)) { |task| run if target == task }
  self
end

#mapperObject

The mapper to use. See #using.



122
123
124
# File 'lib/buildr/core/filter.rb', line 122

def mapper #:nodoc:
  @mapper.mapper_type
end

#mappingObject

The mapping. See #using.



117
118
119
# File 'lib/buildr/core/filter.rb', line 117

def mapping #:nodoc:
  @mapper.config
end

#runObject

:call-seq:

run => boolean

Runs the filter.



161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
# File 'lib/buildr/core/filter.rb', line 161

def run
  sources.each { |source| raise "Source directory #{source} doesn't exist" unless File.exist?(source.to_s) }
  raise 'No target directory specified, where am I going to copy the files to?' if target.nil?

  copy_map = sources.flatten.map(&:to_s).inject({}) do |map, source|
    files = Util.recursive_with_dot_files(source).
      map { |file| Util.relative_path(file, source) }.
      select { |file| @include.empty? || @include.any? { |pattern| File.fnmatch(pattern, file, File::FNM_PATHNAME) } }.
      reject { |file| @exclude.any? { |pattern| File.fnmatch(pattern, file, File::FNM_PATHNAME) } }
    files.each do |file|
      src, dest = File.expand_path(file, source), File.expand_path(file, target.to_s)
      map[file] = src if !File.exist?(dest) || File.stat(src).mtime >= File.stat(dest).mtime
    end
    map
  end
    
  mkpath target.to_s, :verbose=>Buildr.application.options.trace
  return false if copy_map.empty?

  verbose(Buildr.application.options.trace || false) do
    copy_map.each do |path, source|
      dest = File.expand_path(path, target.to_s)
      if File.directory?(source)
        mkpath dest, :verbose=>false
      else
        mkpath File.dirname(dest)
        if @mapper.mapper_type
          mapped = @mapper.transform(File.open(source, 'rb') { |file| file.read }, path)
          File.open(dest, 'wb') { |file| file.write mapped }
        else # no mapping
          cp source, dest
          File.chmod(0664, dest)
        end
      end
    end
    touch target.to_s
  end
  true
end

#to_sObject

Returns the target directory.



202
203
204
# File 'lib/buildr/core/filter.rb', line 202

def to_s
  @target.to_s
end

#using(*args, &block) ⇒ Object

:call-seq:

using(mapping) => self
using { |file_name, contents| ... } => self

Specifies the mapping to use and returns self.

The most typical mapping uses a Hash, and the default mapping uses the Maven style, so ${key} are mapped to the values. You can change that by passing a different format as the first argument. Currently supports:

  • :ant – Map @key@.

  • :maven – Map ${key} (default).

  • :ruby – Map #{key}.

  • :erb – Map <%= key %>.

  • Regexp – Maps the matched data (e.g. /=(.*?)=/

For example:

filter.using 'version'=>'1.2'

Is the same as:

filter.using :maven, 'version'=>'1.2'

You can also pass a proc or method. It will be called with the file name and content, to return the mapped content.

Without any mapping, all files are copied as is.

To register new mapping type see the Mapper class.



152
153
154
155
# File 'lib/buildr/core/filter.rb', line 152

def using(*args, &block)
  @mapper.using(*args, &block)
  self
end