I would have never thought of just extending the actual top level "main" object.
Ha, you didn't have to divulge that. I assumed you thought of it but
that your focus was on 'import'.
My suggestion was a bit more drastic, though: it implicitly called for
the annihilation of environment.rb. There have been times when I, too,
have not realized that a change suddenly obsoletes a hunk of code :)
All of the following are now equivalent,
Rake::Environment.run do
task :a do
p 'task a'
end
end
Rake::DSL.environment do
task :b do
p 'task b'
end
end
module Rake::Environment
task :c do
p 'task c'
end
end
Rake::Environment.module_eval do
task :d do
p 'task d'
end
end
task :default => [:a, :b, :c, :d]
Option c is clearly the winner, with d being needed for access to
top-level locals (probably uncommon). Aren't a and b vestigial
structures from the old 'import' workaround device?
But what is Rake::Environment doing now?
module MyStuff
extend Rake::DSL
task :default do
# ...
end
end
In my first email, I asked if an example like that in the readme could
replace the need for environment.rb. Meaning, rather than give users
an empty bucket (Rake::Environment), teach them how to make their own
bucket (MyStuff). At least _I_ would prefer a fresh module over
Rake::Environment.
load_string also looks like a vestigial artifact. It's the same as
module_eval now.
Rake::Environment.load_string %{
task :x do
p 'task x'
end
}
Rake::Environment.module_eval %{
task :y do
p 'task y'
end
}
task :default => [:x, :y]
(They are not quite the same; load_string uses eval() which treats
constants differently.)
Lastly there is load_rakefile, which is effectively
Rake::Environment.module_eval(File.read("extra.rake"))
But this has the same problem shown in my first email on beta.1
(http://rubyforge.org/pipermail/rake-devel/2011-March/000832.html).
Indeed running the examples from that email,
% rake --version
rake, version 0.9.0.beta.2
% rake
33
rake aborted!
uninitialized constant #<Class:0x489f7c>::MyStuff::CONST_B
Ah, but what is that anonymous class? It's the load_string/module_eval
difference mentioned above. Rake::Environment is simultaneously a
named module and an anonymous module because eval() doesn't understand
that the module is really Rake::Environment. (In C terms,
rb_mod_module_eval calls eval_under while rb_f_eval does not.) But
this is moot because replacing load_string with module_eval gives the
equally undesirable
uninitialized constant Rake::Environment::MyStuff::CONST_B
The constants in a Rakefile are placed inside Rake::Environment, but
since the Rakefile may require files, and since require starts a new
scope, it all goes to pot. The lesson from beta.1 is that Rakefiles
can't be sandboxed into Rake::Environment.
I don't like the explicit test for JRuby (that means some Rakefile
wouldn't run in JRuby, yuck). Instead I'm going to deprecate
'import' and promote the use of Rake.import.
'import' is not a built-in jruby method; it's only defined with
'require "jruby"', and that is only needed for jruby-specific things
like enabling/disabling ObjectSpace.
Additionally, jruby + Rake seems an unlikely choice for a build tool.
The launch time for jruby is excruciating in this context. JRuby is
aimed at the opposite use case where startup time is not important.
Does *anyone* regularly use jruby with Rake?
I would be interested to see a real-life example where jruby + Rake +
'require "jruby"' is needed. There are viable workarounds even if that
did happen. It's not immediately obvious to me that Rake should change
its API to accommodate that case. If Rake weren't the most popular gem
of all time with 15K downloads per day, the issue might be different.