rake-pipeline 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +18 -0
- data/.rspec +1 -0
- data/.yardopts +2 -0
- data/Gemfile +10 -0
- data/LICENSE +20 -0
- data/README.markdown +4 -0
- data/README.yard +149 -0
- data/Rakefile +12 -0
- data/bin/rakep +27 -0
- data/lib/rake-pipeline.rb +365 -0
- data/lib/rake-pipeline/dsl.rb +146 -0
- data/lib/rake-pipeline/error.rb +17 -0
- data/lib/rake-pipeline/file_wrapper.rb +173 -0
- data/lib/rake-pipeline/filter.rb +209 -0
- data/lib/rake-pipeline/filters.rb +1 -0
- data/lib/rake-pipeline/filters/concat.rb +63 -0
- data/lib/rake-pipeline/matcher.rb +106 -0
- data/lib/rake-pipeline/middleware.rb +70 -0
- data/lib/rake-pipeline/rails_plugin.rb +8 -0
- data/lib/rake-pipeline/railtie.rb +17 -0
- data/lib/rake-pipeline/version.rb +6 -0
- data/rails/init.rb +2 -0
- data/rake-pipeline.gemspec +22 -0
- data/spec/concat_filter_spec.rb +60 -0
- data/spec/dsl_spec.rb +86 -0
- data/spec/encoding_spec.rb +106 -0
- data/spec/file_wrapper_spec.rb +105 -0
- data/spec/filter_spec.rb +216 -0
- data/spec/matcher_spec.rb +105 -0
- data/spec/middleware_spec.rb +149 -0
- data/spec/pipeline_spec.rb +160 -0
- data/spec/rake_acceptance_spec.rb +240 -0
- data/spec/spec_helper.rb +74 -0
- metadata +123 -0
@@ -0,0 +1,146 @@
|
|
1
|
+
module Rake
|
2
|
+
class Pipeline
|
3
|
+
# This class exists purely to provide a convenient DSL for
|
4
|
+
# configuring a pipeline.
|
5
|
+
#
|
6
|
+
# All instance methods of {DSL} are available in the context
|
7
|
+
# the block passed to +Rake::Pipeline.+{Pipeline.build}.
|
8
|
+
#
|
9
|
+
# When configuring a pipeline, you *must* provide both a
|
10
|
+
# root, and a series of files using {#input}.
|
11
|
+
class DSL
|
12
|
+
# @return [Pipeline] the pipeline the DSL should configure
|
13
|
+
attr_reader :pipeline
|
14
|
+
|
15
|
+
# Configure a pipeline with a passed in block.
|
16
|
+
#
|
17
|
+
# @param [Pipeline] pipeline the pipeline that the DSL
|
18
|
+
# should configure.
|
19
|
+
# @param [Proc] block the block describing the
|
20
|
+
# configuration. This block will be evaluated in
|
21
|
+
# the context of a new instance of {DSL}
|
22
|
+
# @return [void]
|
23
|
+
def self.evaluate(pipeline, &block)
|
24
|
+
new(pipeline).instance_eval(&block)
|
25
|
+
copy_filter = Rake::Pipeline::ConcatFilter.new
|
26
|
+
copy_filter.output_name_generator = proc { |input| input }
|
27
|
+
pipeline.add_filter(copy_filter)
|
28
|
+
end
|
29
|
+
|
30
|
+
# Create a new {DSL} to configure a pipeline.
|
31
|
+
#
|
32
|
+
# @param [Pipeline] pipeline the pipeline that the DSL
|
33
|
+
# should configure.
|
34
|
+
# @return [void]
|
35
|
+
def initialize(pipeline)
|
36
|
+
@pipeline = pipeline
|
37
|
+
end
|
38
|
+
|
39
|
+
# Define the input location and files for the pipeline.
|
40
|
+
#
|
41
|
+
# @example
|
42
|
+
# !!!ruby
|
43
|
+
# Rake::Pipeline.build do
|
44
|
+
# input "app/assets", "**/*.js"
|
45
|
+
# # ...
|
46
|
+
# end
|
47
|
+
#
|
48
|
+
# @param [String] root the root path where the pipeline
|
49
|
+
# should find its input files.
|
50
|
+
# @param [String] glob a file pattern that represents
|
51
|
+
# the list of all files that the pipeline should
|
52
|
+
# process. The default is +"**/*"+.
|
53
|
+
# @return [void]
|
54
|
+
def input(root, glob="**/*")
|
55
|
+
pipeline.input_root = root
|
56
|
+
pipeline.input_glob = glob
|
57
|
+
end
|
58
|
+
|
59
|
+
# Add a filter to the pipeline.
|
60
|
+
#
|
61
|
+
# In addition to a filter class, {#filter} takes a
|
62
|
+
# block that describes how the filter should map
|
63
|
+
# input files to output files.
|
64
|
+
#
|
65
|
+
# By default, the block maps an input file into
|
66
|
+
# an output file with the same name.
|
67
|
+
#
|
68
|
+
# Any additional arguments passed to {#filter} will
|
69
|
+
# be passed on to the filter class's constructor.
|
70
|
+
#
|
71
|
+
# @see Filter#outputs Filter#output (for an example
|
72
|
+
# of how a list of input files gets mapped to
|
73
|
+
# its outputs)
|
74
|
+
#
|
75
|
+
# @param [Class] filter_class the class of the filter.
|
76
|
+
# @param [Array] ctor_args a list of arguments to pass
|
77
|
+
# to the filter's constructor.
|
78
|
+
# @param [Proc] block an output file name generator.
|
79
|
+
# @return [void]
|
80
|
+
def filter(filter_class, *ctor_args, &block)
|
81
|
+
filter = filter_class.new(*ctor_args, &block)
|
82
|
+
pipeline.add_filter(filter)
|
83
|
+
end
|
84
|
+
|
85
|
+
# Apply a number of filters, but only to files matching
|
86
|
+
# a particular pattern.
|
87
|
+
#
|
88
|
+
# Inside the block passed to {#match match}, you may
|
89
|
+
# specify any number of filters that should be applied
|
90
|
+
# to files matching the pattern.
|
91
|
+
#
|
92
|
+
# @param [String] pattern a glob pattern to match
|
93
|
+
# @param [Proc] block a block that supplies filters
|
94
|
+
# @return [Matcher]
|
95
|
+
#
|
96
|
+
# @example
|
97
|
+
# !!!ruby
|
98
|
+
# Pipeline.build do
|
99
|
+
# input "app/assets"
|
100
|
+
# output "public"
|
101
|
+
#
|
102
|
+
# # compile coffee files into JS files
|
103
|
+
# match "*.coffee" do
|
104
|
+
# filter CompileCoffee do |input|
|
105
|
+
# input.sub(/coffee$/, "js")
|
106
|
+
# end
|
107
|
+
# end
|
108
|
+
#
|
109
|
+
# # because the previous step converted coffeee
|
110
|
+
# # into JS, the coffee files will be included here
|
111
|
+
# match "*.js" do
|
112
|
+
# filter MinifyFilter
|
113
|
+
# filter Rake::Pipeline::ConcatFilter, "application.js"
|
114
|
+
# end
|
115
|
+
# end
|
116
|
+
def match(pattern, &block)
|
117
|
+
matcher = pipeline.copy(Matcher, &block)
|
118
|
+
matcher.glob = pattern
|
119
|
+
pipeline.add_filter matcher
|
120
|
+
matcher
|
121
|
+
end
|
122
|
+
|
123
|
+
# Specify the output directory for the pipeline.
|
124
|
+
#
|
125
|
+
# @param [String] root the output directory.
|
126
|
+
# @return [void]
|
127
|
+
def output(root)
|
128
|
+
pipeline.output_root = root
|
129
|
+
end
|
130
|
+
|
131
|
+
# Specify the location of the temporary directory.
|
132
|
+
# Filters will store intermediate build artifacts
|
133
|
+
# here.
|
134
|
+
#
|
135
|
+
# This defaults "tmp" in the current working directory.
|
136
|
+
#
|
137
|
+
# @param [String] root the temporary directory
|
138
|
+
# @return [void]
|
139
|
+
def tmpdir(root)
|
140
|
+
pipeline.tmpdir = root
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Rake
|
2
|
+
class Pipeline
|
3
|
+
# The general Rake::Pipeline error class
|
4
|
+
class Error < ::StandardError
|
5
|
+
end
|
6
|
+
|
7
|
+
# The error that Rake::Pipeline uses when it detects
|
8
|
+
# that a file uses an improper encoding.
|
9
|
+
class EncodingError < Error
|
10
|
+
end
|
11
|
+
|
12
|
+
# The error that Rake::Pipeline uses if you try to
|
13
|
+
# write to a FileWrapper before creating it.
|
14
|
+
class UnopenedFile < Error
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,173 @@
|
|
1
|
+
module Rake
|
2
|
+
class Pipeline
|
3
|
+
# This class wraps a file for consumption inside of filters. It is
|
4
|
+
# initialized with a root and path, and filters usually use the
|
5
|
+
# {#read} and {#write} methods to work with these files.
|
6
|
+
#
|
7
|
+
# The {#root} and +path+ parameters are provided by the {Filter}
|
8
|
+
# class' internal implementation. Individual filters do not need
|
9
|
+
# to worry about them.
|
10
|
+
#
|
11
|
+
# The root of a {FileWrapper} is always an absolute path.
|
12
|
+
class FileWrapper
|
13
|
+
# @return [String] an absolute path representing this {FileWrapper}'s
|
14
|
+
# root directory.
|
15
|
+
attr_accessor :root
|
16
|
+
|
17
|
+
# @return [String] the path to the file represented by the {FileWrapper},
|
18
|
+
# relative to its {#root}.
|
19
|
+
attr_accessor :path
|
20
|
+
|
21
|
+
# @return [String] the encoding that the file represented by this
|
22
|
+
# {FileWrapper} is encoded in. Filters set the {#encoding} to
|
23
|
+
# +BINARY+ if they are declared as processing binary data.
|
24
|
+
attr_accessor :encoding
|
25
|
+
|
26
|
+
# Create a new {FileWrapper}, passing in optional root, path, and
|
27
|
+
# encoding. Any of the parameters can be ommitted and supplied later.
|
28
|
+
#
|
29
|
+
# @return [void]
|
30
|
+
def initialize(root=nil, path=nil, encoding="UTF-8")
|
31
|
+
@root, @path, @encoding = root, path, encoding
|
32
|
+
@created_file = nil
|
33
|
+
end
|
34
|
+
|
35
|
+
# Create a new {FileWrapper FileWrapper} with the same root and
|
36
|
+
# path as this {FileWrapper FileWrapper}, but with a specified
|
37
|
+
# encoding.
|
38
|
+
#
|
39
|
+
# @param [String] encoding the encoding for the new object
|
40
|
+
# @return [FileWrapper]
|
41
|
+
def with_encoding(encoding)
|
42
|
+
self.class.new(@root, @path, encoding)
|
43
|
+
end
|
44
|
+
|
45
|
+
# A {FileWrapper} is equal to another {FileWrapper} for hashing purposes
|
46
|
+
# if they have the same {#root} and {#path}
|
47
|
+
#
|
48
|
+
# @param [FileWrapper] other another {FileWrapper} to compare.
|
49
|
+
# @return [true,false]
|
50
|
+
def eql?(other)
|
51
|
+
return false unless other.is_a?(self.class)
|
52
|
+
root == other.root && path == other.path
|
53
|
+
end
|
54
|
+
alias == eql?
|
55
|
+
|
56
|
+
# Similar to {#eql?}, generate a {FileWrapper}'s {#hash} from its {#root}
|
57
|
+
# and {#path}
|
58
|
+
#
|
59
|
+
# @see #eql?
|
60
|
+
# @return [Fixnum] a hash code
|
61
|
+
def hash
|
62
|
+
[root, path].hash
|
63
|
+
end
|
64
|
+
|
65
|
+
# The full path of a FileWrapper is its root joined with its path
|
66
|
+
#
|
67
|
+
# @return [String] the {FileWrapper}'s full path
|
68
|
+
def fullpath
|
69
|
+
raise "#{root}, #{path}" unless root =~ /^\//
|
70
|
+
File.join(root, path)
|
71
|
+
end
|
72
|
+
|
73
|
+
# Make FileWrappers sortable
|
74
|
+
#
|
75
|
+
# @param [FileWrapper] other {FileWrapper FileWrapper}
|
76
|
+
# @return [Fixnum] -1, 0, or 1
|
77
|
+
def <=>(other)
|
78
|
+
[root, path, encoding] <=> [other.root, other.path, other.encoding]
|
79
|
+
end
|
80
|
+
|
81
|
+
# Does the file represented by the {FileWrapper} exist in the file system?
|
82
|
+
#
|
83
|
+
# @return [true,false]
|
84
|
+
def exists?
|
85
|
+
File.exists?(fullpath)
|
86
|
+
end
|
87
|
+
|
88
|
+
# Read the contents of the file represented by the {FileWrapper}.
|
89
|
+
#
|
90
|
+
# Read the file using the {FileWrapper}'s encoding, which will result in
|
91
|
+
# this method returning a +String+ tagged with the {FileWrapper}'s encoding.
|
92
|
+
#
|
93
|
+
# @return [String] the contents of the file
|
94
|
+
# @raise [EncodingError] when the contents of the file are not valid in the
|
95
|
+
# expected encoding specified in {#encoding}.
|
96
|
+
def read
|
97
|
+
contents = if "".respond_to?(:encode)
|
98
|
+
File.read(fullpath, :encoding => encoding)
|
99
|
+
else
|
100
|
+
File.read(fullpath)
|
101
|
+
end
|
102
|
+
|
103
|
+
if "".respond_to?(:encode) && !contents.valid_encoding?
|
104
|
+
raise EncodingError, "The file at the path #{fullpath} is not valid UTF-8. Please save it again as UTF-8."
|
105
|
+
end
|
106
|
+
|
107
|
+
contents
|
108
|
+
end
|
109
|
+
|
110
|
+
# Create a new file at the {FileWrapper}'s {#fullpath}. If the file already
|
111
|
+
# exists, it will be overwritten.
|
112
|
+
#
|
113
|
+
# @api private
|
114
|
+
# @yieldparam [File] file the newly created file
|
115
|
+
# @return [File] if a block was not given
|
116
|
+
def create
|
117
|
+
FileUtils.mkdir_p(File.dirname(fullpath))
|
118
|
+
|
119
|
+
@created_file = if "".respond_to?(:encode)
|
120
|
+
File.open(fullpath, "w:#{encoding}")
|
121
|
+
else
|
122
|
+
File.open(fullpath, "w")
|
123
|
+
end
|
124
|
+
|
125
|
+
if block_given?
|
126
|
+
yield @created_file
|
127
|
+
end
|
128
|
+
|
129
|
+
@created_file
|
130
|
+
ensure
|
131
|
+
if block_given?
|
132
|
+
@created_file.close
|
133
|
+
@created_file = nil
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
# Close the file represented by the {FileWrapper} if it was previously opened.
|
138
|
+
#
|
139
|
+
# @api private
|
140
|
+
# @return [void]
|
141
|
+
def close
|
142
|
+
raise IOError, "closed stream" unless @created_file
|
143
|
+
@created_file.close
|
144
|
+
@created_file = nil
|
145
|
+
end
|
146
|
+
|
147
|
+
# Check to see whether the file represented by the {FileWrapper} is open.
|
148
|
+
#
|
149
|
+
# @api private
|
150
|
+
# @return [true,false]
|
151
|
+
def closed?
|
152
|
+
@created_file.nil?
|
153
|
+
end
|
154
|
+
|
155
|
+
# Write a String to a previously opened file. This method is called repeatedly
|
156
|
+
# by a {Filter}'s +#generate_output+ method and does not create a brand new
|
157
|
+
# file for each invocation.
|
158
|
+
#
|
159
|
+
# @raise [UnopenedFile] if the file is not already opened.
|
160
|
+
def write(string)
|
161
|
+
raise UnopenedFile unless @created_file
|
162
|
+
@created_file.write(string)
|
163
|
+
end
|
164
|
+
|
165
|
+
# @return [String] A pretty representation of the {FileWrapper}.
|
166
|
+
def inspect
|
167
|
+
"#<FileWrapper root=#{root.inspect} path=#{path.inspect} encoding=#{encoding.inspect}>"
|
168
|
+
end
|
169
|
+
|
170
|
+
alias to_s inspect
|
171
|
+
end
|
172
|
+
end
|
173
|
+
end
|
@@ -0,0 +1,209 @@
|
|
1
|
+
require "rake"
|
2
|
+
|
3
|
+
module Rake
|
4
|
+
class Pipeline
|
5
|
+
|
6
|
+
# A Filter is added to a pipeline and converts input files
|
7
|
+
# into output files.
|
8
|
+
#
|
9
|
+
# Filters operate on FileWrappers, which abstract away the
|
10
|
+
# root directory of a file, providing a relative path and
|
11
|
+
# a mechanism for reading and writing.
|
12
|
+
#
|
13
|
+
#
|
14
|
+
# For instance, a filter to wrap the contents of each file
|
15
|
+
# in a JavaScript closure would look like:
|
16
|
+
#
|
17
|
+
# !!!ruby
|
18
|
+
# require "json"
|
19
|
+
#
|
20
|
+
# class ClosureFilter < Rake::Pipeline::Filter
|
21
|
+
# def generate_output(inputs, output)
|
22
|
+
# inputs.each do |input|
|
23
|
+
# output.write "(function() { #{input.read.to_json} })()"
|
24
|
+
# end
|
25
|
+
# end
|
26
|
+
# end
|
27
|
+
#
|
28
|
+
# A filter's files come from the input directory or the directory
|
29
|
+
# owned by the previous filter, but filters are insulated from
|
30
|
+
# this concern.
|
31
|
+
#
|
32
|
+
# You can call +path+ on a FileWrapper to get the file's relative
|
33
|
+
# path, or `fullpath` to get its absolute path, but you should,
|
34
|
+
# in general, not use `fullpath` but instead use methods of
|
35
|
+
# FileWrapper like `read` and `write` that abstract the details
|
36
|
+
# from you.
|
37
|
+
#
|
38
|
+
# @see ConcatFilter Rake::Pipeline::ConcatFilter for another
|
39
|
+
# example filter implementation.
|
40
|
+
#
|
41
|
+
# @abstract
|
42
|
+
class Filter
|
43
|
+
# @return [Array<FileWrapper>] an Array of FileWrappers that
|
44
|
+
# represent the inputs of this filter. The Pipeline will
|
45
|
+
# usually set this up.
|
46
|
+
attr_accessor :input_files
|
47
|
+
|
48
|
+
# @return [Proc] a block that returns the relative output
|
49
|
+
# filename for a particular input file.
|
50
|
+
attr_accessor :output_name_generator
|
51
|
+
|
52
|
+
# @return [String] the root directory to write output files
|
53
|
+
# to. For the last filter in a pipeline, the pipeline will
|
54
|
+
# set this to the pipeline's output. For all other filters,
|
55
|
+
# the pipeline will create a temporary directory that it
|
56
|
+
# also uses when creating FileWrappers for the next filter's
|
57
|
+
# inputs.
|
58
|
+
attr_accessor :output_root
|
59
|
+
|
60
|
+
# @return [Array<Rake::Task>] an Array of Rake tasks created
|
61
|
+
# for this filter. Each unique output file will get a
|
62
|
+
# single task.
|
63
|
+
attr_reader :rake_tasks
|
64
|
+
|
65
|
+
# @return [Rake::Application] the Rake::Application that the
|
66
|
+
# filter should define new rake tasks on.
|
67
|
+
attr_writer :rake_application
|
68
|
+
|
69
|
+
attr_writer :file_wrapper_class
|
70
|
+
|
71
|
+
# @param [Proc] block a block to use as the Filter's
|
72
|
+
# {#output_name_generator}.
|
73
|
+
def initialize(&block)
|
74
|
+
block ||= proc { |input| input }
|
75
|
+
@output_name_generator = block
|
76
|
+
end
|
77
|
+
|
78
|
+
# Invoke this method in a subclass of Filter to declare that
|
79
|
+
# it expects to work with BINARY data, and that data that is
|
80
|
+
# not valid UTF-8 should be allowed.
|
81
|
+
#
|
82
|
+
# @return [void]
|
83
|
+
def self.processes_binary_files
|
84
|
+
define_method(:encoding) { "BINARY" }
|
85
|
+
end
|
86
|
+
|
87
|
+
# @return [Class] the class to use as the wrapper for output
|
88
|
+
# files.
|
89
|
+
def file_wrapper_class
|
90
|
+
@file_wrapper_class ||= FileWrapper
|
91
|
+
end
|
92
|
+
|
93
|
+
# Set the input files to a list of FileWrappers. The filter
|
94
|
+
# will map these into equivalent FileWrappers with the
|
95
|
+
# filter's encoding applied.
|
96
|
+
#
|
97
|
+
# By default, a filter's encoding is +UTF-8+, unless
|
98
|
+
# it calls #processes_binary_files, which changes it to
|
99
|
+
# +BINARY+.
|
100
|
+
#
|
101
|
+
# @param [Array<FileWrapper>] a list of FileWrapper objects
|
102
|
+
def input_files=(files)
|
103
|
+
@input_files = files.map do |file|
|
104
|
+
file.with_encoding(encoding)
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
# A hash of output files pointing at their associated input
|
109
|
+
# files. The output names are created by applying the
|
110
|
+
# {#output_name_generator} to each input file.
|
111
|
+
#
|
112
|
+
# For exmaple, if you had the following input files:
|
113
|
+
#
|
114
|
+
# javascripts/jquery.js
|
115
|
+
# javascripts/sproutcore.js
|
116
|
+
# stylesheets/sproutcore.css
|
117
|
+
#
|
118
|
+
# And you had the following {#output_name_generator}:
|
119
|
+
#
|
120
|
+
# !!!ruby
|
121
|
+
# filter.output_name_generator = proc do |filename|
|
122
|
+
# # javascripts/jquery.js becomes:
|
123
|
+
# # ["javascripts", "jquery", "js"]
|
124
|
+
# directory, file, ext = file.split(/[\.\/]/)
|
125
|
+
#
|
126
|
+
# "#{directory}.#{ext}"
|
127
|
+
# end
|
128
|
+
#
|
129
|
+
# You would end up with the following hash:
|
130
|
+
#
|
131
|
+
# !!!ruby
|
132
|
+
# {
|
133
|
+
# #<FileWrapper path="javascripts.js" root="#{output_root}> => [
|
134
|
+
# #<FileWrapper path="javascripts/jquery.js" root="#{previous_filter.output_root}">,
|
135
|
+
# #<FileWrapper path="javascripts/sproutcore.js" root="#{previous_filter.output_root}">
|
136
|
+
# ],
|
137
|
+
# #<FileWrapper path="stylesheets.css" root="#{output_root}"> => [
|
138
|
+
# #<FileWrapper path="stylesheets/sproutcore.css" root=#{previous_filter.output_root}">
|
139
|
+
# ]
|
140
|
+
# }
|
141
|
+
#
|
142
|
+
# Each output file becomes a Rake task, which invokes the +#generate_output+
|
143
|
+
# method defined by the subclass of {Filter} with the Array of inputs and
|
144
|
+
# the output (all as {FileWrapper}s).
|
145
|
+
#
|
146
|
+
# @return [Hash{FileWrapper => Array<FileWrapper>}]
|
147
|
+
def outputs
|
148
|
+
hash = {}
|
149
|
+
|
150
|
+
input_files.each do |file|
|
151
|
+
output = output_wrapper(output_name_generator.call(file.path))
|
152
|
+
|
153
|
+
hash[output] ||= []
|
154
|
+
hash[output] << file
|
155
|
+
end
|
156
|
+
|
157
|
+
hash
|
158
|
+
end
|
159
|
+
|
160
|
+
# An Array of the {FileWrapper} objects that rerepresent this filter's
|
161
|
+
# output files. It is the same as +outputs.keys+.
|
162
|
+
#
|
163
|
+
# @see #outputs
|
164
|
+
# @return [Array<FileWrapper>]
|
165
|
+
def output_files
|
166
|
+
input_files.inject([]) do |array, file|
|
167
|
+
array |= [output_wrapper(output_name_generator.call(file.path))]
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
# The Rake::Application that the filter should define new tasks on.
|
172
|
+
#
|
173
|
+
# @return [Rake::Application]
|
174
|
+
def rake_application
|
175
|
+
@rake_application || Rake.application
|
176
|
+
end
|
177
|
+
|
178
|
+
# Generate the Rake tasks for the output files of this filter.
|
179
|
+
#
|
180
|
+
# @see #outputs #outputs (for information on how the output files are determined)
|
181
|
+
# @return [void]
|
182
|
+
def generate_rake_tasks
|
183
|
+
@rake_tasks = outputs.map do |output, inputs|
|
184
|
+
dependencies = inputs.map(&:fullpath)
|
185
|
+
|
186
|
+
dependencies.each { |path| create_file_task(path) }
|
187
|
+
|
188
|
+
create_file_task(output.fullpath, dependencies) do
|
189
|
+
output.create { generate_output(inputs, output) }
|
190
|
+
end
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
194
|
+
private
|
195
|
+
# @attr_reader
|
196
|
+
def encoding
|
197
|
+
"UTF-8"
|
198
|
+
end
|
199
|
+
|
200
|
+
def create_file_task(output, deps=[], &block)
|
201
|
+
rake_application.define_task(Rake::FileTask, output => deps, &block)
|
202
|
+
end
|
203
|
+
|
204
|
+
def output_wrapper(file)
|
205
|
+
file_wrapper_class.new(output_root, file, encoding)
|
206
|
+
end
|
207
|
+
end
|
208
|
+
end
|
209
|
+
end
|