Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
357 views
in Technique[技术] by (71.8m points)

require - Circular Dependencies in Ruby

Let's say we have two classes, Foo and Foo Sub, each in a different file, foo.rb and foo_sub.rb respectively.

foo.rb:

require "foo_sub"
class Foo
    def foo
        FooSub.SOME_CONSTANT
    end
end

foo_sub.rb:

require "foo"
class FooSub < Foo
    SOME_CONSTANT = 1
end

This isn't going to work due to the circular dependency - we can't define either class without the other. There are various solutions that I've seen. Two of them I want to avoid - namely, putting them in the same file and removing the circular dependency. So, the only other solution I've found is a forward declaration:

foo.rb:

class Foo
end
require "foo_sub"
class Foo
    def foo
        FooSub.SOME_CONSTANT
    end
end

foo_sub.rb

require "foo"
class FooSub < Foo
    SOME_CONSTANT = 1
end

Unfortunately, I can't get the same thing to work if I have three files:

foo.rb:

class Foo
end
require "foo_sub_sub"
class Foo
    def foo
        FooSubSub.SOME_CONSTANT
    end
end

foo_sub.rb:

require "foo"
class FooSub < Foo
end

foo_sub_sub.rb:

require "foo_sub"
class FooSubSub < FooSub
    SOME_CONSTANT = 1
end

If I require foo_sub.rb, then FooSub is an uninitialized constant in foo_sub_sub.rb. Any ideas how to get around this without putting them in the same file nor removing the circular dependency?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

If you need to access a subclass from a superclass then there's a good chance that your model is broken (i.e. it should be one class).

That said, there are a couple of obvious solutions:

1) just create a file that requires the foo files:

all_foos.rb:

require "foo.rb"
require "foo_sub.rb"

and remove the requires from foo.rb and foo_sub.rb.

2) remove the require from foo.rb

3) remove the require from foo_sub.rb and put the require in foo.rb after the class definition.

Ruby isn't C++, it won't complain about FooSub.SOME_CONSTANT until you call Foo#foo() ;)


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...