rake-pipeline 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|