5 # Copyright (c) 2003, 2004, 2005, 2006, 2007 Jim Weirich
7 # Permission is hereby granted, free of charge, to any person obtaining a copy
8 # of this software and associated documentation files (the "Software"), to
9 # deal in the Software without restriction, including without limitation the
10 # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
11 # sell copies of the Software, and to permit persons to whom the Software is
12 # furnished to do so, subject to the following conditions:
14 # The above copyright notice and this permission notice shall be included in
15 # all copies or substantial portions of the Software.
17 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22 # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
28 # This is the main file for the Rake application. Normally it is referenced
29 # as a library via a require statement, but it can be distributed
30 # independently as an application.
41 ######################################################################
42 # Rake extensions to Module.
45 # Check for an existing method in the current class before extending. IF
46 # the method already exists, then a warning is printed and the extension is
47 # not added. Otherwise the block is yielded and any definitions in the
48 # block will take effect.
53 # rake_extension("xyz") do
60 def rake_extension(method)
61 if instance_methods.include?(method.to_s) || instance_methods.include?(method.to_sym)
62 $stderr.puts "WARNING: Possible conflict with Rake extension: #{self}##{method} already exists"
70 ######################################################################
71 # User defined methods to be added to String.
74 rake_extension("ext") do
75 # Replace the file extension with +newext+. If there is no extension on
76 # the string, append the new extension to the end. If the new extension
77 # is not given, or is the empty string, remove any existing extension.
79 # +ext+ is a user added method for the String class.
81 return self.dup if ['.', '..'].include? self
83 newext = (newext =~ /^\./) ? newext : ("." + newext)
85 dup.sub!(%r(([^/\\])\.[^./\\]*$)) { $1 + newext } || self + newext
89 rake_extension("pathmap") do
90 # Explode a path into individual components. Used by +pathmap+.
92 head, tail = File.split(self)
93 return [self] if head == self
94 return [tail] if head == '.' || tail == '/'
95 return [head, tail] if head == '/'
96 return head.pathmap_explode + [tail]
98 protected :pathmap_explode
100 # Extract a partial path from the path. Include +n+ directories from the
101 # front end (left hand side) if +n+ is positive. Include |+n+|
102 # directories from the back end (right hand side) if +n+ is negative.
103 def pathmap_partial(n)
104 dirs = File.dirname(self).pathmap_explode
109 dirs.reverse[0...-n].reverse
113 File.join(partial_dirs)
115 protected :pathmap_partial
117 # Preform the pathmap replacement operations on the given path. The
118 # patterns take the form 'pat1,rep1;pat2,rep2...'.
119 def pathmap_replace(patterns, &block)
121 patterns.split(';').each do |pair|
122 pattern, replacement = pair.split(',')
123 pattern = Regexp.new(pattern)
124 if replacement == '*' && block_given?
125 result = result.sub(pattern, &block)
127 result = result.sub(pattern, replacement)
129 result = result.sub(pattern, '')
134 protected :pathmap_replace
136 # Map the path according to the given specification. The specification
137 # controls the details of the mapping. The following special patterns are
140 # * <b>%p</b> -- The complete path.
141 # * <b>%f</b> -- The base file name of the path, with its file extension,
142 # but without any directories.
143 # * <b>%n</b> -- The file name of the path without its file extension.
144 # * <b>%d</b> -- The directory list of the path.
145 # * <b>%x</b> -- The file extension of the path. An empty string if there
147 # * <b>%X</b> -- Everything *but* the file extension.
148 # * <b>%s</b> -- The alternate file separator if defined, otherwise use
149 # the standard file separator.
150 # * <b>%%</b> -- A percent sign.
152 # The %d specifier can also have a numeric prefix (e.g. '%2d'). If the
153 # number is positive, only return (up to) +n+ directories in the path,
154 # starting from the left hand side. If +n+ is negative, return (up to)
155 # |+n+| directories from the right hand side of the path.
159 # 'a/b/c/d/file.txt'.pathmap("%2d") => 'a/b'
160 # 'a/b/c/d/file.txt'.pathmap("%-2d") => 'c/d'
162 # Also the %d, %p, $f, $n, %x, and %X operators can take a
163 # pattern/replacement argument to perform simple string substitutions on a
164 # particular part of the path. The pattern and replacement are separated
165 # by a comma and are enclosed by curly braces. The replacement spec comes
166 # after the % character but before the operator letter. (e.g.
167 # "%{old,new}d"). Muliple replacement specs should be separated by
168 # semi-colons (e.g. "%{old,new;src,bin}d").
170 # Regular expressions may be used for the pattern, and back refs may be
171 # used in the replacement text. Curly braces, commas and semi-colons are
172 # excluded from both the pattern and replacement text (let's keep parsing
177 # "src/org/onestepback/proj/A.java".pathmap("%{^src,bin}X.class")
181 # "bin/org/onestepback/proj/A.class"
183 # If the replacement text is '*', then a block may be provided to perform
184 # some arbitrary calculation for the replacement.
188 # "/path/to/file.TXT".pathmap("%X%{.*,*}x") { |ext|
194 # "/path/to/file.txt"
196 def pathmap(spec=nil, &block)
197 return self if spec.nil?
199 spec.scan(/%\{[^}]*\}-?\d*[sdpfnxX%]|%-?\d+d|%.|[^%]+/) do |frag|
202 result << File.basename(self)
204 result << File.basename(self).ext
206 result << File.dirname(self)
208 result << $1 if self =~ /[^\/](\.[^.]+)$/
210 if self =~ /^(.*[^\/])(\.[^.]+)$/
218 result << (File::ALT_SEPARATOR || File::SEPARATOR)
224 result << pathmap_partial($1.to_i)
225 when /^%\{([^}]*)\}(\d*[dpfnxX])/
226 patterns, operator = $1, $2
227 result << pathmap('%' + operator).pathmap_replace(patterns, &block)
229 fail ArgumentError, "Unknown pathmap specifier #{frag} in '#{spec}'"
239 ##############################################################################
242 # --------------------------------------------------------------------------
243 # Rake module singleton methods.
246 # Current Rake Application
248 @application ||= Rake::Application.new
251 # Set the current Rake application object.
252 def application=(app)
256 # Return the original directory where the Rake application was started.
258 application.original_dir
263 # ##########################################################################
264 # Mixin for creating easily cloned objects.
267 # Clone an object by making a new object and setting all the instance
268 # variables to the same values.
270 sibling = self.class.new
271 instance_variables.each do |ivar|
272 value = self.instance_variable_get(ivar)
273 new_value = value.clone rescue value
274 sibling.instance_variable_set(ivar, new_value)
281 ####################################################################
282 # TaskAguments manage the arguments passed to a task.
289 def initialize(names, values, parent=nil)
293 names.each_with_index { |name, i|
294 @hash[name.to_sym] = values[i]
298 # Create a new argument scope using the prerequisite argument
301 values = names.collect { |n| self[n] }
302 self.class.new(names, values, self)
305 # Find an argument value by name or index.
314 def method_missing(sym, *args, &block)
333 if @hash.has_key?(name)
335 elsif ENV.has_key?(name.to_s)
337 elsif ENV.has_key?(name.to_s.upcase)
338 ENV[name.to_s.upcase]
345 ####################################################################
346 # InvocationChain tracks the chain of task invocations to detect
347 # circular dependencies.
348 class InvocationChain
349 def initialize(value, tail)
355 @value == obj || @tail.member?(obj)
360 fail RuntimeError, "Circular dependency detected: #{to_s} => #{value}"
362 self.class.new(value, self)
369 def self.append(value, chain)
379 class EmptyInvocationChain
384 InvocationChain.new(value, self)
391 EMPTY = EmptyInvocationChain.new
393 end # class InvocationChain
399 # #########################################################################
400 # A Task is the basic unit of work in a Rakefile. Tasks have associated
401 # actions (possibly more than one) and a list of prerequisites. When
402 # invoked, a task will first ensure that all of its prerequisites have an
403 # opportunity to run and then it will execute its own actions.
405 # Tasks are not usually created directly using the new method, but rather
406 # use the +file+ and +task+ convenience methods.
409 # List of prerequisites for a task.
410 attr_reader :prerequisites
412 # Application owning this task.
413 attr_accessor :application
415 # Comment for this task. Restricted to a single line of no more than 50
419 # Full text of the (possibly multi-line) comment.
420 attr_reader :full_comment
422 # Array of nested namespaces names used for task lookup by this task.
431 "<#{self.class} #{name} => [#{prerequisites.join(', ')}]>"
434 # List of sources for task.
440 # First source from a rule (nil if no sources)
442 @sources.first if defined?(@sources)
445 # Create a task named +task_name+ with no actions or prerequisites. Use
446 # +enhance+ to add actions and prerequisites.
447 def initialize(task_name, app)
448 @name = task_name.to_s
449 @prerequisites = FileList[]
451 @already_invoked = false
456 @scope = app.current_scope
460 # Enhance a task with prerequisites or actions. Returns self.
461 def enhance(deps=nil, &block)
462 @prerequisites |= deps if deps
463 @actions << block if block_given?
467 # Name of the task, including any namespace qualifiers.
472 # Name of task with argument list description.
473 def name_with_args # :nodoc:
475 "#{name}#{arg_description}"
481 # Argument description (nil if none).
482 def arg_description # :nodoc:
483 @arg_names ? "[#{(arg_names || []).join(',')}]" : nil
486 # Name of arguments for this task.
491 # Invoke the task if it is needed. Prerequites are invoked first.
493 task_args = TaskArguments.new(arg_names, args)
494 invoke_with_call_chain(task_args, InvocationChain::EMPTY)
497 # Same as invoke, but explicitly pass a call chain to detect
498 # circular dependencies.
499 def invoke_with_call_chain(task_args, invocation_chain)
500 new_chain = InvocationChain.append(self, invocation_chain)
502 if application.options.trace
503 puts "** Invoke #{name} #{format_trace_flags}"
505 return if @already_invoked
506 @already_invoked = true
507 invoke_prerequisites(task_args, new_chain)
508 execute(task_args) if needed?
511 protected :invoke_with_call_chain
513 # Invoke all the prerequisites of a task.
514 def invoke_prerequisites(task_args, invocation_chain)
515 @prerequisites.each { |n|
516 prereq = application[n, @scope]
517 prereq_args = task_args.new_scope(prereq.arg_names)
518 prereq.invoke_with_call_chain(prereq_args, invocation_chain)
522 # Format the trace flags for display.
523 def format_trace_flags
525 flags << "first_time" unless @already_invoked
526 flags << "not_needed" unless needed?
527 flags.empty? ? "" : "(" + flags.join(", ") + ")"
529 private :format_trace_flags
531 # Execute the actions associated with this task.
533 if application.options.dryrun
534 puts "** Execute (dry run) #{name}"
537 if application.options.trace
538 puts "** Execute #{name}"
540 application.enhance_with_matching_rule(name) if @actions.empty?
541 @actions.each do |act|
551 # Is this task needed?
556 # Timestamp for this task. Basic tasks return the current time for their
557 # time stamp. Other tasks can be more sophisticated.
559 @prerequisites.collect { |p| application[p].timestamp }.max || Time.now
562 # Add a description to the task. The description can consist of an option
563 # argument list (enclosed brackets) and an optional comment.
564 def add_description(description)
565 return if ! description
566 comment = description.strip
567 add_comment(comment) if comment && ! comment.empty?
570 # Writing to the comment attribute is the same as adding a description.
571 def comment=(description)
572 add_description(description)
575 # Add a comment to the task. If a comment alread exists, separate
576 # the new comment with " / ".
577 def add_comment(comment)
579 @full_comment << " / "
583 @full_comment << comment
584 if @full_comment =~ /\A([^.]+?\.)( |$)/
587 @comment = @full_comment
592 # Set the names of the arguments for this task. +args+ should be
593 # an array of symbols, one for each argument name.
594 def set_arg_names(args)
595 @arg_names = args.map { |a| a.to_sym }
598 # Return a string describing the internal state of a task. Useful for
601 result = "------------------------------\n"
602 result << "Investigating #{name}\n"
603 result << "class: #{self.class}\n"
604 result << "task needed: #{needed?}\n"
605 result << "timestamp: #{timestamp}\n"
606 result << "pre-requisites: \n"
607 prereqs = @prerequisites.collect {|name| application[name]}
608 prereqs.sort! {|a,b| a.timestamp <=> b.timestamp}
610 result << "--#{p.name} (#{p.timestamp})\n"
612 latest_prereq = @prerequisites.collect{|n| application[n].timestamp}.max
613 result << "latest-prerequisite time: #{latest_prereq}\n"
614 result << "................................\n\n"
618 # ----------------------------------------------------------------
619 # Rake Module Methods
623 # Clear the task list. This cause rake to immediately forget all the
624 # tasks that have been assigned. (Normally used in the unit tests.)
626 Rake.application.clear
629 # List of all defined tasks.
631 Rake.application.tasks
634 # Return a task with the given name. If the task is not currently
635 # known, try to synthesize one from the defined rules. If no rules are
636 # found, but an existing file matches the task name, assume it is a file
637 # task with no dependencies or actions.
639 Rake.application[task_name]
642 # TRUE if the task name is already defined.
643 def task_defined?(task_name)
644 Rake.application.lookup(task_name) != nil
647 # Define a task given +args+ and an option block. If a rule with the
648 # given name already exists, the prerequisites and actions are added to
649 # the existing task. Returns the defined task.
650 def define_task(*args, &block)
651 Rake.application.define_task(self, *args, &block)
654 # Define a rule for synthesizing tasks.
655 def create_rule(*args, &block)
656 Rake.application.create_rule(*args, &block)
659 # Apply the scope to the task name according to the rules for
660 # this kind of task. Generic tasks will accept the scope as
662 def scope_name(scope, task_name)
663 (scope + [task_name]).join(':')
666 end # class << Rake::Task
667 end # class Rake::Task
670 # #########################################################################
671 # A FileTask is a task that includes time based dependencies. If any of a
672 # FileTask's prerequisites have a timestamp that is later than the file
673 # represented by this task, then the file must be rebuilt (using the
676 class FileTask < Task
678 # Is this file task needed? Yes if it doesn't exist, or if its time stamp
681 return true unless File.exist?(name)
682 return true if out_of_date?(timestamp)
686 # Time stamp for file task.
689 File.mtime(name.to_s)
697 # Are there any prerequisites with a later time than the given time stamp?
698 def out_of_date?(stamp)
699 @prerequisites.any? { |n| application[n].timestamp > stamp}
702 # ----------------------------------------------------------------
703 # Task class methods.
706 # Apply the scope to the task name according to the rules for this kind
707 # of task. File based tasks ignore the scope when creating the name.
708 def scope_name(scope, task_name)
712 end # class Rake::FileTask
714 # #########################################################################
715 # A FileCreationTask is a file task that when used as a dependency will be
716 # needed if and only if the file has not been created. Once created, it is
717 # not re-triggered if any of its dependencies are newer, nor does trigger
718 # any rebuilds of tasks that depend on it whenever it is updated.
720 class FileCreationTask < FileTask
721 # Is this file task needed? Yes if it doesn't exist.
726 # Time stamp for file creation task. This time stamp is earlier
727 # than any other time stamp.
733 # #########################################################################
734 # Same as a regular task, but the immediate prerequisites are done in
735 # parallel using Ruby threads.
737 class MultiTask < Task
738 def invoke_prerequisites(args, invocation_chain)
739 threads = @prerequisites.collect { |p|
740 Thread.new(p) { |r| application[r].invoke_with_call_chain(args, invocation_chain) }
742 threads.each { |t| t.join }
747 # ###########################################################################
748 # Task Definition Functions ...
750 # Declare a basic task.
753 # task :clobber => [:clean] do
757 def task(*args, &block)
758 Rake::Task.define_task(*args, &block)
762 # Declare a file task.
765 # file "config.cfg" => ["config.template"] do
766 # open("config.cfg", "w") do |outfile|
767 # open("config.template") do |infile|
768 # while line = infile.gets
775 def file(args, &block)
776 Rake::FileTask.define_task(args, &block)
779 # Declare a file creation task.
780 # (Mainly used for the directory command).
781 def file_create(args, &block)
782 Rake::FileCreationTask.define_task(args, &block)
785 # Declare a set of files tasks to create the given directories on demand.
788 # directory "testdata/doc"
791 Rake.each_dir_parent(dir) do |d|
793 mkdir_p t.name if ! File.exist?(t.name)
798 # Declare a task that performs its prerequisites in parallel. Multitasks does
799 # *not* guarantee that its prerequisites will execute in any given order
800 # (which is obvious when you think about it)
803 # multitask :deploy => [:deploy_gem, :deploy_rdoc]
805 def multitask(args, &block)
806 Rake::MultiTask.define_task(args, &block)
809 # Create a new rake namespace and use it for evaluating the given block.
810 # Returns a NameSpace object that can be used to lookup tasks defined in the
815 # ns = namespace "nested" do
818 # task_run = ns[:run] # find :run in the given namespace.
820 def namespace(name=nil, &block)
821 Rake.application.in_namespace(name, &block)
824 # Declare a rule for auto-tasks.
827 # rule '.o' => '.c' do |t|
828 # sh %{cc -o #{t.name} #{t.source}}
831 def rule(*args, &block)
832 Rake::Task.create_rule(*args, &block)
835 # Describe the next rake task.
838 # desc "Run the Unit Tests"
839 # task :test => [:build]
843 def desc(description)
844 Rake.application.last_description = description
847 # Import the partial Rakefiles +fn+. Imported files are loaded _after_ the
848 # current file is completely loaded. This allows the import statement to
849 # appear anywhere in the importing file, and yet allowing the imported files
850 # to depend on objects defined in the importing file.
852 # A common use of the import statement is to include files containing
853 # dependency declarations.
855 # See also the --rakelibdir command line option.
858 # import ".depend", "my_rules"
862 Rake.application.add_import(fn)
866 # ###########################################################################
867 # This a FileUtils extension that defines several additional commands to be
868 # added to the FileUtils utility functions.
871 RUBY = File.join(Config::CONFIG['bindir'], Config::CONFIG['ruby_install_name'])
873 OPT_TABLE['sh'] = %w(noop verbose)
874 OPT_TABLE['ruby'] = %w(noop verbose)
876 # Run the system command +cmd+. If multiple arguments are given the command
877 # is not run with the shell (same semantics as Kernel::exec and
883 # sh 'ls', 'file with spaces'
885 # # check exit status after command runs
886 # sh %{grep pattern file} do |ok, res|
888 # puts "pattern not found (status = #{res.exitstatus})"
893 options = (Hash === cmd.last) ? cmd.pop : {}
895 show_command = cmd.join(" ")
896 show_command = show_command[0,42] + "..."
897 # TODO code application logic heref show_command.length > 45
898 block = lambda { |ok, status|
899 ok or fail "Command failed with status (#{status.exitstatus}): [#{show_command}]"
902 rake_check_options options, :noop, :verbose
903 rake_output_message cmd.join(" ") if options[:verbose]
904 unless options[:noop]
910 # Run a Ruby interpreter with the given arguments.
913 # ruby %{-pe '$_.upcase!' <README}
915 def ruby(*args,&block)
916 options = (Hash === args.last) ? args.pop : {}
917 if args.length > 1 then
918 sh(*([RUBY] + args + [options]), &block)
920 sh("#{RUBY} #{args.first}", options, &block)
924 LN_SUPPORTED = [true]
926 # Attempt to do a normal file link, but fall back to a copy if the link
929 unless LN_SUPPORTED[0]
934 rescue StandardError, NotImplementedError => ex
935 LN_SUPPORTED[0] = false
941 # Split a file path into individual directory names.
944 # split_all("a/b/c") => ['a', 'b', 'c']
947 head, tail = File.split(path)
948 return [tail] if head == '.' || tail == '/'
949 return [head, tail] if head == '/'
950 return split_all(head) + [tail]
954 # ###########################################################################
955 # RakeFileUtils provides a custom version of the FileUtils methods that
956 # respond to the <tt>verbose</tt> and <tt>nowrite</tt> commands.
962 attr_accessor :verbose_flag, :nowrite_flag
964 RakeFileUtils.verbose_flag = true
965 RakeFileUtils.nowrite_flag = false
967 $fileutils_verbose = true
968 $fileutils_nowrite = false
970 FileUtils::OPT_TABLE.each do |name, opts|
972 if opts.include?('verbose')
973 default_options << ':verbose => RakeFileUtils.verbose_flag'
975 if opts.include?('noop')
976 default_options << ':noop => RakeFileUtils.nowrite_flag'
979 next if default_options.empty?
980 module_eval(<<-EOS, __FILE__, __LINE__ + 1)
981 def #{name}( *args, &block )
983 *rake_merge_option(args,
984 #{default_options.join(', ')}
990 # Get/set the verbose flag controlling output from the FileUtils utilities.
991 # If verbose is true, then the utility method is echoed to standard output.
994 # verbose # return the current value of the verbose flag
995 # verbose(v) # set the verbose flag to _v_.
996 # verbose(v) { code } # Execute code with the verbose flag set temporarily to _v_.
997 # # Return to the original value when code is done.
998 def verbose(value=nil)
999 oldvalue = RakeFileUtils.verbose_flag
1000 RakeFileUtils.verbose_flag = value unless value.nil?
1005 RakeFileUtils.verbose_flag = oldvalue
1008 RakeFileUtils.verbose_flag
1011 # Get/set the nowrite flag controlling output from the FileUtils utilities.
1012 # If verbose is true, then the utility method is echoed to standard output.
1015 # nowrite # return the current value of the nowrite flag
1016 # nowrite(v) # set the nowrite flag to _v_.
1017 # nowrite(v) { code } # Execute code with the nowrite flag set temporarily to _v_.
1018 # # Return to the original value when code is done.
1019 def nowrite(value=nil)
1020 oldvalue = RakeFileUtils.nowrite_flag
1021 RakeFileUtils.nowrite_flag = value unless value.nil?
1026 RakeFileUtils.nowrite_flag = oldvalue
1032 # Use this function to prevent potentially destructive ruby code from
1033 # running when the :nowrite flag is set.
1037 # when_writing("Building Project") do
1041 # The following code will build the project under normal conditions. If the
1042 # nowrite(true) flag is set, then the example will print:
1043 # DRYRUN: Building Project
1044 # instead of actually building the project.
1046 def when_writing(msg=nil)
1047 if RakeFileUtils.nowrite_flag
1048 puts "DRYRUN: #{msg}" if msg
1054 # Merge the given options with the default values.
1055 def rake_merge_option(args, defaults)
1056 if Hash === args.last
1057 defaults.update(args.last)
1063 private :rake_merge_option
1065 # Send the message to the default rake output (which is $stderr).
1066 def rake_output_message(message)
1067 $stderr.puts(message)
1069 private :rake_output_message
1071 # Check that the options do not contain options not listed in +optdecl+. An
1072 # ArgumentError exception is thrown if non-declared options are found.
1073 def rake_check_options(options, *optdecl)
1075 optdecl.each do |name|
1078 raise ArgumentError, "no such option: #{h.keys.join(' ')}" unless h.empty?
1080 private :rake_check_options
1085 # ###########################################################################
1086 # Include the FileUtils file manipulation functions in the top level module,
1087 # but mark them private so that they don't unintentionally define methods on
1090 include RakeFileUtils
1091 private(*FileUtils.instance_methods(false))
1092 private(*RakeFileUtils.instance_methods(false))
1094 ######################################################################
1097 class RuleRecursionOverflowError < StandardError
1098 def initialize(*args)
1103 def add_target(target)
1108 super + ": [" + @targets.reverse.join(' => ') + "]"
1112 # #########################################################################
1113 # A FileList is essentially an array with a few helper methods defined to
1114 # make file manipulation a bit easier.
1116 # FileLists are lazy. When given a list of glob patterns for possible files
1117 # to be included in the file list, instead of searching the file structures
1118 # to find the files, a FileList holds the pattern for latter use.
1120 # This allows us to define a number of FileList to match any number of
1121 # files, but only search out the actual files when then FileList itself is
1122 # actually used. The key is that the first time an element of the
1123 # FileList/Array is requested, the pending patterns are resolved into a real
1124 # list of file names.
1130 # == Method Delegation
1132 # The lazy evaluation magic of FileLists happens by implementing all the
1133 # array specific methods to call +resolve+ before delegating the heavy
1134 # lifting to an embedded array object (@items).
1136 # In addition, there are two kinds of delegation calls. The regular kind
1137 # delegates to the @items array and returns the result directly. Well,
1138 # almost directly. It checks if the returned value is the @items object
1139 # itself, and if so will return the FileList object instead.
1141 # The second kind of delegation call is used in methods that normally
1142 # return a new Array object. We want to capture the return value of these
1143 # methods and wrap them in a new FileList object. We enumerate these
1144 # methods in the +SPECIAL_RETURN+ list below.
1146 # List of array methods (that are not in +Object+) that need to be
1148 ARRAY_METHODS = (Array.instance_methods - Object.instance_methods).map { |n| n.to_s }
1150 # List of additional methods that must be delegated.
1151 MUST_DEFINE = %w[to_a inspect]
1153 # List of methods that should not be delegated here (we define special
1154 # versions of them explicitly below).
1155 MUST_NOT_DEFINE = %w[to_a to_ary partition *]
1157 # List of delegated methods that return new array values which need
1159 SPECIAL_RETURN = %w[
1160 map collect sort sort_by select find_all reject grep
1161 compact flatten uniq values_at
1165 DELEGATING_METHODS = (ARRAY_METHODS + MUST_DEFINE - MUST_NOT_DEFINE).collect{ |s| s.to_s }.sort.uniq
1167 # Now do the delegation.
1168 DELEGATING_METHODS.each_with_index do |sym, i|
1169 if SPECIAL_RETURN.include?(sym)
1172 def #{sym}(*args, &block)
1174 result = @items.send(:#{sym}, *args, &block)
1175 FileList.new.import(result)
1181 def #{sym}(*args, &block)
1183 result = @items.send(:#{sym}, *args, &block)
1184 result.object_id == @items.object_id ? self : result
1190 # Create a file list from the globbable patterns given. If you wish to
1191 # perform multiple includes or excludes at object build time, use the
1192 # "yield self" pattern.
1195 # file_list = FileList.new('lib/**/*.rb', 'test/test*.rb')
1197 # pkg_files = FileList.new('lib/**/*') do |fl|
1198 # fl.exclude(/\bCVS\b/)
1201 def initialize(*patterns)
1204 @exclude_patterns = DEFAULT_IGNORE_PATTERNS.dup
1205 @exclude_procs = DEFAULT_IGNORE_PROCS.dup
1208 patterns.each { |pattern| include(pattern) }
1209 yield self if block_given?
1212 # Add file names defined by glob patterns to the file list. If an array
1213 # is given, add each element of the array.
1216 # file_list.include("*.java", "*.cfg")
1217 # file_list.include %w( math.c lib.h *.o )
1219 def include(*filenames)
1220 # TODO: check for pending
1221 filenames.each do |fn|
1222 if fn.respond_to? :to_ary
1233 # Register a list of file name patterns that should be excluded from the
1234 # list. Patterns may be regular expressions, glob patterns or regular
1235 # strings. In addition, a block given to exclude will remove entries that
1236 # return true when given to the block.
1238 # Note that glob patterns are expanded against the file system. If a file
1239 # is explicitly added to a file list, but does not exist in the file
1240 # system, then an glob pattern in the exclude list will not exclude the
1244 # FileList['a.c', 'b.c'].exclude("a.c") => ['b.c']
1245 # FileList['a.c', 'b.c'].exclude(/^a/) => ['b.c']
1247 # If "a.c" is a file, then ...
1248 # FileList['a.c', 'b.c'].exclude("a.*") => ['b.c']
1250 # If "a.c" is not a file, then ...
1251 # FileList['a.c', 'b.c'].exclude("a.*") => ['a.c', 'b.c']
1253 def exclude(*patterns, &block)
1254 patterns.each do |pat|
1255 @exclude_patterns << pat
1258 @exclude_procs << block
1260 resolve_exclude if ! @pending
1265 # Clear all the exclude patterns so that we exclude nothing.
1267 @exclude_patterns = []
1269 calculate_exclude_regexp if ! @pending
1278 # Return the internal array object.
1284 # Return the internal array object.
1289 # Lie about our class.
1291 klass == Array || super(klass)
1293 alias kind_of? is_a?
1295 # Redefine * to return either a string or a new file list.
1297 result = @items * other
1300 FileList.new.import(result)
1306 # Resolve all the pending adds now.
1310 @pending_add.each do |fn| resolve_add(fn) end
1317 def calculate_exclude_regexp
1319 @exclude_patterns.each do |pat|
1324 Dir[pat].each do |p| ignores << p end
1326 ignores << Regexp.quote(pat)
1332 re_str = ignores.collect { |p| "(" + p.to_s + ")" }.join("|")
1333 @exclude_re = Regexp.new(re_str)
1345 private :resolve_add
1348 calculate_exclude_regexp
1349 reject! { |fn| exclude?(fn) }
1352 private :resolve_exclude
1354 # Return a new FileList with the results of running +sub+ against each
1355 # element of the original list.
1358 # FileList['a.c', 'b.c'].sub(/\.c$/, '.o') => ['a.o', 'b.o']
1361 inject(FileList.new) { |res, fn| res << fn.sub(pat,rep) }
1364 # Return a new FileList with the results of running +gsub+ against each
1365 # element of the original list.
1368 # FileList['lib/test/file', 'x/y'].gsub(/\//, "\\")
1369 # => ['lib\\test\\file', 'x\\y']
1372 inject(FileList.new) { |res, fn| res << fn.gsub(pat,rep) }
1375 # Same as +sub+ except that the oringal file list is modified.
1377 each_with_index { |fn, i| self[i] = fn.sub(pat,rep) }
1381 # Same as +gsub+ except that the original file list is modified.
1383 each_with_index { |fn, i| self[i] = fn.gsub(pat,rep) }
1387 # Apply the pathmap spec to each of the included file names, returning a
1388 # new file list with the modified paths. (See String#pathmap for
1390 def pathmap(spec=nil)
1391 collect { |fn| fn.pathmap(spec) }
1394 # Return a new array with <tt>String#ext</tt> method applied to each
1395 # member of the array.
1397 # This method is a shortcut for:
1399 # array.collect { |item| item.ext(newext) }
1401 # +ext+ is a user added method for the Array class.
1403 collect { |fn| fn.ext(newext) }
1407 # Grep each of the files in the filelist using the given pattern. If a
1408 # block is given, call the block on each matching line, passing the file
1409 # name, line number, and the matching line of text. If no block is given,
1410 # a standard emac style file:linenumber:line message will be printed to
1418 if pattern.match(line)
1420 yield fn, count, line
1422 puts "#{fn}:#{count}:#{line}"
1430 # Return a new file list that only contains file names from the current
1431 # file list that exist on the file system.
1433 select { |fn| File.exist?(fn) }
1436 # Modify the current file list so that it contains only file name that
1437 # exist on the file system.
1440 @items = @items.select { |fn| File.exist?(fn) }
1444 # FileList version of partition. Needed because the nested arrays should
1445 # be FileLists in this version.
1446 def partition(&block) # :nodoc:
1448 result = @items.partition(&block)
1450 FileList.new.import(result[0]),
1451 FileList.new.import(result[1]),
1455 # Convert a FileList to a string by joining all elements with a space.
1461 # Add matching glob patterns.
1462 def add_matching(pattern)
1463 Dir[pattern].each do |fn|
1464 self << fn unless exclude?(fn)
1467 private :add_matching
1469 # Should the given file name be excluded?
1471 calculate_exclude_regexp unless @exclude_re
1472 fn =~ @exclude_re || @exclude_procs.any? { |p| p.call(fn) }
1475 DEFAULT_IGNORE_PATTERNS = [
1476 /(^|[\/\\])CVS([\/\\]|$)/,
1477 /(^|[\/\\])\.svn([\/\\]|$)/,
1481 DEFAULT_IGNORE_PROCS = [
1482 proc { |fn| fn =~ /(^|[\/\\])core$/ && ! File.directory?(fn) }
1484 # @exclude_patterns = DEFAULT_IGNORE_PATTERNS.dup
1492 # Create a new file list including the files listed. Similar to:
1494 # FileList.new(*args)
1505 # Yield each file or directory component.
1506 def each_dir_parent(dir)
1508 while dir != '.' && dir.length != old_length
1510 old_length = dir.length
1511 dir = File.dirname(dir)
1517 # Alias FileList to be available at the top level.
1518 FileList = Rake::FileList
1520 # ###########################################################################
1523 # Default Rakefile loader used by +import+.
1526 Kernel.load(File.expand_path(fn))
1530 # EarlyTime is a fake timestamp that occurs _before_ any other time value.
1544 EARLY = EarlyTime.instance
1547 # ###########################################################################
1548 # Extensions to time to allow comparisons with an early time class.
1551 alias rake_original_time_compare :<=>
1553 if Rake::EarlyTime === other
1556 rake_original_time_compare(other)
1563 ####################################################################
1564 # The NameSpace class will lookup task names in the the scope
1565 # defined by a +namespace+ command.
1569 # Create a namespace lookup object using the given task manager
1570 # and the list of scopes.
1571 def initialize(task_manager, scope_list)
1572 @task_manager = task_manager
1573 @scope = scope_list.dup
1576 # Lookup a task named +name+ in the namespace.
1578 @task_manager.lookup(name, @scope)
1581 # Return the list of tasks defined in this namespace.
1588 ####################################################################
1589 # The TaskManager module is a mixin for managing tasks.
1591 # Track the last comment made in the Rakefile.
1592 attr_accessor :last_description
1593 alias :last_comment :last_description # Backwards compatibility
1600 @last_description = nil
1603 def create_rule(*args, &block)
1604 pattern, arg_names, deps = resolve_args(args)
1605 pattern = Regexp.new(Regexp.quote(pattern) + '$') if String === pattern
1606 @rules << [pattern, deps, block]
1609 def define_task(task_class, *args, &block)
1610 task_name, arg_names, deps = resolve_args(args)
1611 task_name = task_class.scope_name(@scope, task_name)
1612 deps = [deps] unless deps.respond_to?(:to_ary)
1613 deps = deps.collect {|d| d.to_s }
1614 task = intern(task_class, task_name)
1615 task.set_arg_names(arg_names) unless arg_names.empty?
1616 task.add_description(@last_description)
1617 @last_description = nil
1618 task.enhance(deps, &block)
1622 # Lookup a task. Return an existing task if found, otherwise
1623 # create a task of the current type.
1624 def intern(task_class, task_name)
1625 @tasks[task_name.to_s] ||= task_class.new(task_name, self)
1628 # Find a matching task for +task_name+.
1629 def [](task_name, scopes=nil)
1630 task_name = task_name.to_s
1631 self.lookup(task_name, scopes) or
1632 enhance_with_matching_rule(task_name) or
1633 synthesize_file_task(task_name) or
1634 fail "Don't know how to build task '#{task_name}'"
1637 def synthesize_file_task(task_name)
1638 return nil unless File.exist?(task_name)
1639 define_task(Rake::FileTask, task_name)
1642 # Resolve the arguments for a task/rule. Returns a triplet of
1643 # [task_name, arg_name_list, prerequisites].
1644 def resolve_args(args)
1645 task_name = args.shift
1646 arg_names = args #.map { |a| a.to_sym }
1648 if task_name.is_a?(Hash)
1650 task_name = hash.keys[0]
1651 needs = hash[task_name]
1653 if arg_names.last.is_a?(Hash)
1654 hash = arg_names.pop
1655 needs = hash[:needs]
1656 fail "Unrecognized keys in task hash: #{hash.keys.inspect}" if hash.size > 1
1658 needs = [needs] unless needs.respond_to?(:to_ary)
1659 [task_name, arg_names, needs]
1662 # If a rule can be found that matches the task name, enhance the
1663 # task with the prerequisites and actions from the rule. Set the
1664 # source attribute of the task appropriately for the rule. Return
1665 # the enhanced task or nil of no rule was found.
1666 def enhance_with_matching_rule(task_name, level=0)
1667 fail Rake::RuleRecursionOverflowError,
1668 "Rule Recursion Too Deep" if level >= 16
1669 @rules.each do |pattern, extensions, block|
1670 if md = pattern.match(task_name)
1671 task = attempt_rule(task_name, extensions, block, level)
1676 rescue Rake::RuleRecursionOverflowError => ex
1677 ex.add_target(task_name)
1681 # List of all defined tasks in this application.
1683 @tasks.values.sort_by { |t| t.name }
1686 # Clear all tasks in this application.
1692 # Lookup a task, using scope and the scope hints in the task name.
1693 # This method performs straight lookups without trying to
1694 # synthesize file tasks or rules. Special scope names (e.g. '^')
1695 # are recognized. If no scope argument is supplied, use the
1696 # current scope. Return nil if the task cannot be found.
1697 def lookup(task_name, initial_scope=nil)
1698 initial_scope ||= @scope
1699 task_name = task_name.to_s
1700 if task_name =~ /^rake:/
1702 task_name = task_name.sub(/^rake:/, '')
1703 elsif task_name =~ /^(\^+)/
1704 scopes = initial_scope[0, initial_scope.size - $1.size]
1705 task_name = task_name.sub(/^(\^+)/, '')
1707 scopes = initial_scope
1709 lookup_in_scope(task_name, scopes)
1712 # Lookup the task name
1713 def lookup_in_scope(name, scope)
1716 tn = (scope[0,n] + [name]).join(':')
1723 private :lookup_in_scope
1725 # Return the list of scope names currently active in the task
1731 # Evaluate the block in a nested namespace named +name+. Create
1732 # an anonymous namespace if +name+ is nil.
1733 def in_namespace(name)
1734 name ||= generate_name
1736 ns = NameSpace.new(self, @scope)
1745 # Generate an anonymous namespace name.
1752 # Attempt to create a rule given the list of prerequisites.
1753 def attempt_rule(task_name, extensions, block, level)
1754 sources = make_sources(task_name, extensions)
1755 prereqs = sources.collect { |source|
1756 if File.exist?(source) || Rake::Task.task_defined?(source)
1758 elsif parent = enhance_with_matching_rule(sources.first, level+1)
1764 task = FileTask.define_task({task_name => prereqs}, &block)
1765 task.sources = prereqs
1769 # Make a list of sources from the list of file name extensions /
1770 # translation procs.
1771 def make_sources(task_name, extensions)
1772 extensions.collect { |ext|
1775 task_name.pathmap(ext)
1789 fail "Don't know how to handle rule dependent: #{ext.inspect}"
1796 ######################################################################
1797 # Rake main application object. When invoking +rake+ from the
1798 # command line, a Rake::Application object is created and run.
1803 # The name of the application (typically 'rake')
1806 # The original directory where rake was invoked.
1807 attr_reader :original_dir
1809 # Name of the actual rakefile used.
1810 attr_reader :rakefile
1812 # List of the top level task names (task names from the command line).
1813 attr_reader :top_level_tasks
1815 DEFAULT_RAKEFILES = ['rakefile', 'Rakefile', 'rakefile.rb', 'Rakefile.rb'].freeze
1817 OPTIONS = [ # :nodoc:
1818 ['--classic-namespace', '-C', GetoptLong::NO_ARGUMENT,
1819 "Put Task and FileTask in the top level namespace"],
1820 ['--describe', '-D', GetoptLong::OPTIONAL_ARGUMENT,
1821 "Describe the tasks (matching optional PATTERN), then exit."],
1822 ['--rakefile', '-f', GetoptLong::OPTIONAL_ARGUMENT,
1823 "Use FILE as the rakefile."],
1824 ['--help', '-h', '-H', GetoptLong::NO_ARGUMENT,
1825 "Display this help message."],
1826 ['--libdir', '-I', GetoptLong::REQUIRED_ARGUMENT,
1827 "Include LIBDIR in the search path for required modules."],
1828 ['--dry-run', '-n', GetoptLong::NO_ARGUMENT,
1829 "Do a dry run without executing actions."],
1830 ['--nosearch', '-N', GetoptLong::NO_ARGUMENT,
1831 "Do not search parent directories for the Rakefile."],
1832 ['--prereqs', '-P', GetoptLong::NO_ARGUMENT,
1833 "Display the tasks and dependencies, then exit."],
1834 ['--quiet', '-q', GetoptLong::NO_ARGUMENT,
1835 "Do not log messages to standard output."],
1836 ['--require', '-r', GetoptLong::REQUIRED_ARGUMENT,
1837 "Require MODULE before executing rakefile."],
1838 ['--rakelibdir', '-R', GetoptLong::REQUIRED_ARGUMENT,
1839 "Auto-import any .rake files in RAKELIBDIR. (default is 'rakelib')"],
1840 ['--silent', '-s', GetoptLong::NO_ARGUMENT,
1841 "Like --quiet, but also suppresses the 'in directory' announcement."],
1842 ['--tasks', '-T', GetoptLong::OPTIONAL_ARGUMENT,
1843 "Display the tasks (matching optional PATTERN) with descriptions, then exit."],
1844 ['--trace', '-t', GetoptLong::NO_ARGUMENT,
1845 "Turn on invoke/execute tracing, enable full backtrace."],
1846 ['--verbose', '-v', GetoptLong::NO_ARGUMENT,
1847 "Log message to standard output (default)."],
1848 ['--version', '-V', GetoptLong::NO_ARGUMENT,
1849 "Display the program version."],
1852 # Initialize a Rake::Application object.
1856 @rakefiles = DEFAULT_RAKEFILES.dup
1858 @pending_imports = []
1861 @default_loader = Rake::DefaultLoader.new
1862 @original_dir = Dir.pwd
1863 @top_level_tasks = []
1864 add_loader('rf', DefaultLoader.new)
1865 add_loader('rake', DefaultLoader.new)
1868 # Run the Rake application. The run method performs the following three steps:
1870 # * Initialize the command line options (+init+).
1871 # * Define the tasks (+load_rakefile+).
1872 # * Run the top level tasks (+run_tasks+).
1874 # If you wish to build a custom rake command, you should call +init+ on your
1875 # application. The define any tasks. Finally, call +top_level+ to run your top
1878 standard_exception_handling do
1885 # Initialize the command line parameters and app name.
1886 def init(app_name='rake')
1887 standard_exception_handling do
1894 # Find the rakefile and then load it and any pending imports.
1896 standard_exception_handling do
1901 # Run the top level tasks of a Rake application.
1903 standard_exception_handling do
1904 if options.show_tasks
1905 display_tasks_and_comments
1906 elsif options.show_prereqs
1907 display_prerequisites
1909 top_level_tasks.each { |task_name| invoke_task(task_name) }
1914 # Add a loader to handle imported files ending in the extension
1916 def add_loader(ext, loader)
1917 ext = ".#{ext}" unless ext =~ /^\./
1918 @loaders[ext] = loader
1921 # Application options from the command line
1923 @options ||= OpenStruct.new
1926 # private ----------------------------------------------------------------
1928 def invoke_task(task_string)
1929 name, args = parse_task_string(task_string)
1934 def parse_task_string(string)
1935 if string =~ /^([^\[]+)(\[(.*)\])$/
1937 args = $3.split(/\s*,\s*/)
1945 # Provide standard exception handling for the given block.
1946 def standard_exception_handling
1949 rescue SystemExit => ex
1950 # Exit silently with current status
1952 rescue SystemExit, GetoptLong::InvalidOption => ex
1955 rescue Exception => ex
1956 # Exit with error message
1957 $stderr.puts "rake aborted!"
1958 $stderr.puts ex.message
1960 $stderr.puts ex.backtrace.join("\n")
1962 $stderr.puts ex.backtrace.find {|str| str =~ /#{@rakefile}/ } || ""
1963 $stderr.puts "(See full trace by running task with --trace)"
1969 # True if one of the files in RAKEFILES is in the current directory.
1970 # If a match is found, it is copied into @rakefile.
1972 @rakefiles.each do |fn|
1973 if File.exist?(fn) || fn == ''
1981 # Display the rake command line help.
1983 puts "rake [-f rakefile] {options} targets..."
1985 puts "Options are ..."
1987 OPTIONS.sort.each do |long, short, mode, desc|
1988 if mode == GetoptLong::REQUIRED_ARGUMENT
1989 if desc =~ /\b([A-Z]{2,})\b/
1990 long = long + "=#{$1}"
1993 printf " %-20s (%s)\n", long, short
1994 printf " %s\n", desc
1998 # Display the tasks and dependencies.
1999 def display_tasks_and_comments
2000 displayable_tasks = tasks.select { |t|
2001 t.comment && t.name =~ options.show_task_pattern
2003 if options.full_description
2004 displayable_tasks.each do |t|
2005 puts "rake #{t.name_with_args}"
2006 t.full_comment.split("\n").each do |line|
2012 width = displayable_tasks.collect { |t| t.name_with_args.length }.max || 10
2013 max_column = 80 - name.size - width - 7
2014 displayable_tasks.each do |t|
2015 printf "#{name} %-#{width}s # %s\n",
2016 t.name_with_args, truncate(t.comment, max_column)
2021 def truncate(string, width)
2022 if string.length <= width
2025 string[0, width-3] + "..."
2029 # Display the tasks and prerequisites
2030 def display_prerequisites
2032 puts "rake #{t.name}"
2033 t.prerequisites.each { |pre| puts " #{pre}" }
2037 # Return a list of the command line options supported by the
2039 def command_line_options
2040 OPTIONS.collect { |lst| lst[0..-2] }
2043 # Do the option defined by +opt+ and +value+.
2044 def do_option(opt, value)
2047 options.show_tasks = true
2048 options.show_task_pattern = Regexp.new(value || '.')
2049 options.full_description = true
2053 options.dryrun = true
2054 options.trace = true
2061 options.nosearch = true
2063 options.show_prereqs = true
2070 options.rakelib = value.split(':')
2074 rescue LoadError => ex
2077 rescue LoadError => ex2
2083 options.silent = true
2085 options.show_tasks = true
2086 options.show_task_pattern = Regexp.new(value || '.')
2087 options.full_description = false
2089 options.trace = true
2094 puts "rake, version #{RAKEVERSION}"
2096 when '--classic-namespace'
2097 require 'rake/classic_namespace'
2098 options.classic_namespace = true
2102 # Read and handle the command line options.
2104 options.rakelib = ['rakelib']
2106 opts = GetoptLong.new(*command_line_options)
2107 opts.each { |opt, value| do_option(opt, value) }
2109 # If class namespaces are requested, set the global options
2110 # according to the values in the options structure.
2111 if options.classic_namespace
2112 $show_tasks = options.show_tasks
2113 $show_prereqs = options.show_prereqs
2114 $trace = options.trace
2115 $dryrun = options.dryrun
2116 $silent = options.silent
2118 rescue NoMethodError => ex
2119 raise GetoptLong::InvalidOption, "While parsing options, error = #{ex.class}:#{ex.message}"
2122 # Similar to the regular Ruby +require+ command, but will check
2123 # for .rake files in addition to .rb files.
2124 def rake_require(file_name, paths=$LOAD_PATH, loaded=$")
2125 return false if loaded.include?(file_name)
2126 paths.each do |path|
2127 fn = file_name + ".rake"
2128 full_path = File.join(path, fn)
2129 if File.exist?(full_path)
2135 fail LoadError, "Can't find #{file_name}"
2138 def raw_load_rakefile # :nodoc:
2140 while ! have_rakefile
2142 if Dir.pwd == here || options.nosearch
2143 fail "No Rakefile found (looking for: #{@rakefiles.join(', ')})"
2147 puts "(in #{Dir.pwd})" unless options.silent
2148 $rakefile = @rakefile
2149 load File.expand_path(@rakefile) if @rakefile != ''
2150 options.rakelib.each do |rlib|
2151 Dir["#{rlib}/*.rake"].each do |name| add_import name end
2156 # Collect the list of tasks on the command line. If no tasks are
2157 # given, return a list containing only the default task.
2158 # Environmental assignments are processed at this time as well.
2160 @top_level_tasks = []
2162 if arg =~ /^(\w+)=(.*)$/
2165 @top_level_tasks << arg
2168 @top_level_tasks.push("default") if @top_level_tasks.size == 0
2171 # Add a file to the list of files to be imported.
2173 @pending_imports << fn
2176 # Load the pending list of imported files.
2178 while fn = @pending_imports.shift
2179 next if @imported.member?(fn)
2180 if fn_task = lookup(fn)
2183 ext = File.extname(fn)
2184 loader = @loaders[ext] || @default_loader
2190 # Warn about deprecated use of top level constant names.
2191 def const_warning(const_name)
2192 @const_warning ||= false
2194 $stderr.puts %{WARNING: Deprecated reference to top-level constant '#{const_name}' } +
2195 %{found at: #{rakefile_location}} # '
2196 $stderr.puts %{ Use --classic-namespace on rake command}
2197 $stderr.puts %{ or 'require "rake/classic_namespace"' in Rakefile}
2199 @const_warning = true
2202 def rakefile_location
2205 rescue RuntimeError => ex
2206 ex.backtrace.find {|str| str =~ /#{@rakefile}/ } || ""
2214 # Rename the original handler to make it available.
2215 alias :rake_original_const_missing :const_missing
2217 # Check for deprecated uses of top level (i.e. in Object) uses of
2218 # Rake class names. If someone tries to reference the constant
2219 # name, display a warning and return the proper object. Using the
2220 # --classic-namespace command line option will define these
2221 # constants in Object and avoid this handler.
2222 def const_missing(const_name)
2225 Rake.application.const_warning(const_name)
2228 Rake.application.const_warning(const_name)
2230 when :FileCreationTask
2231 Rake.application.const_warning(const_name)
2232 Rake::FileCreationTask
2234 Rake.application.const_warning(const_name)
2237 rake_original_const_missing(const_name)