::slaps heel of hand to forehead::
The END{ require } thing isn't needed. Setting $" solves the infinite
loop -- you can just call require.
···
On Thu, Jul 24, 2008 at 9:02 AM, Shadowfirebird <shadowfirebird@gmail.com> wrote:
I've had my think.
I think I have some conclusions which might be useful for other people
in the same boat, and since I've not seen them anywhere else, I hope
you'll allow me to bore you with them. No doubt cooler heads than
mine will see things differently, but there you go. And, maybe I'm
missing the obvious, anyway.1) require is mildly broken (a). It doesn't set $" until after the
given file is loaded. This can lead to errors when you have a
circular call of requires. If it set $" first, circular references
would just be ignored. Of course, you should never actually *need* to
have circular 'require' referefences, but: see my next point.2) Require is mildly broken (b). Secondly -- and I suppose that this
is less of a bug and more of a bugbear -- there is no way to
distinguish between require-because-it-wont-load-otherwise and
require-because-some-methods-wont-run-otherwise. This second sort
isn't entirely necessary, but it's aesthetically pleasing and useful
for unit testing.3) You can get around (1) by manually pushing the program name into $"
at the start of each file. This done, you can use a new idiom -- END
{ require } -- to specify
require-because-some-methods-wont-run-otherwise. Not the prettiest
thing, but neither the ugliest, I think: "in the end, this is
required."Now I suppose I'd better show my working if I'm going to say anything
as contentious as all that. Apologies for the length of this, but
then, you can stop reading now. OTOH, I'd really like to hear other
points of view.A new set of example programs:
# runner.rb
require 'root'
Root.create_data()
Root.customers.each{|c| puts c.oid, c.name}# root.rb
require 'customer'
class Root
@@list =def self.create_data()
Customer.new("Dolly")
Customer.new("Reymond")
enddef self.customers()
return @@list.find_all{|x| x.kind_of?(Customer)}
endattr_accessor :oid
def initialize()
@oid = @@list.size
@@list << self
end
end# customer.rb
require 'root'
class Customer < Root
attr_accessor :namedef initialize(name)
super()
@name = name
end
endBroadly speaking this follows the same approach as my actual code. As
listed, of course, it doesn't work: run runner.rb and it loads
root.rb, which starts by loading customer.rb, which starts by loading
root.rb, which...I needed to make a distinction (#2 above) between code that referred
to another object when it was loaded; and code that referred to
another object when it was run. root.rb doesn't need a 'require
'customer'; runner.rb does. But this is rather unhelpful when it
comes to unit testing: when writing the test class for Root I
shouldn't have to remember to require customer. Ideally I should be
able to put the require in root.rb somehow.For experimental purposes lets try putting the "require 'customer'" at
the *end* of root.rb. This has practical implications -- no
programmer is going to look for it there -- but it works; running
runner.rb produces no errors. Oddly enough, putting "END {require
'customer'}" at the start of the file does not work. But, wait.What is more interesting, is that if you run root.rb or customer.rb
you get warnings about redefined methods. You shouldn't see this if
require works as described -- a file should never be called twice.
What appears to be happening is that $" is set after the file is
loaded -- that is, it's not being set until the chain of requires has
finished. We can defeat that behaviour by adding $" << "<filename>"
to the start of root.rb and customer.rb. The warnings now disappear.
(And that seems like a bug to me, or at least an undocumented feature.)This is really odd: if we now try END{ require 'customer'} at the
start of root.rb -- well, after the $" thing -- it *works*. Really
odd, but nice.So, root.rb now looks like this:
# root.rb
$" << "root.rb"
END { require 'customer' }
class Root
@@list =def self.create_data()
Customer.new("Dolly")
Customer.new("Reymond")
enddef self.customers()
return @@list.find_all{|x| x.kind_of?(Customer)}
endattr_accessor :oid
def initialize()
@oid = @@list.size
@@list << self
end
endAnd I can live with that. But I'm open to suggestions -- any
suggestions, except rude ones...
--
Me, I imagine places that I have never seen / The colored lights in
fountains, blue and green / And I imagine places that I will never go
/ Behind these clouds that hang here dark and low
But it's there when I'm holding you / There when I'm sleeping too /
There when there's nothing left of me / Hanging out behind the
burned-out factories / Out of reach but leading me / Into the
beautiful sea