1
\$\begingroup\$

I have a module (in file dialect.rb) defined as such:

require 'dialect/generators/elements'
module Dialect
 def self.included(caller)
 caller.extend Dialect::Generator::Element
 end
 def self.version
 "Dialect v#{Dialect::VERSION}"
 end
end

Then I have the file dialect/generators/elements.rb, which looks like this:

module Dialect
 module Generator
 module Element
 puts Dialect.version
 end
 end
end

If I run my app, I get:

/lib/dialect/generators/elements.rb:7:in `<module:Element>':
undefined method `version' for Dialect:Module (NoMethodError)

My question/problem is: I didn't understand why the Element module could not find the version method here.

How I call Dialect is like this:

require 'dialect'
class PageTest
 include Dialect
end

So you can see Dialect is mixed-in to an existing class. It's when this class is instantiated that I get the error above.

When I try a simple IRB session doing what appears to be this same logic, this all seems to work:

irb(main):001:0> module Dialect
irb(main):002:1> def self.version
irb(main):003:2> puts "Version number"
irb(main):004:2> end
irb(main):005:1> end
=> nil
irb(main):006:0> module Dialect
irb(main):007:1> module Generator
irb(main):008:2> module Element
irb(main):009:3> puts Dialect.version
irb(main):010:3> end
irb(main):011:2> end
irb(main):012:1> end
Version number

Here I get the "Version number" text back, which tells me (I think?) that Dialect::Generator::Element can call the method version on Dialect.

The issue ended up being corrected by simply moving my require statement to the end, like this:

module Dialect
 def self.included(caller)
 caller.extend Dialect::Generator::Element
 end
 def self.version
 "Dialect v#{Dialect::VERSION}"
 end
end
require 'dialect/generators/elements'

Having the require statement at the end solves the problem I was having.

The question then becomes: is this a good way to do this? I feel like making my logic depend on where the require statement goes seems like a bad idea.

asked Mar 3, 2014 at 12:53
\$\endgroup\$
0

1 Answer 1

2
\$\begingroup\$

The require line in the first file means that ruby runs the second file before the first file, which is before the version method is declared...

Doing it the other way around will work, since only when included is called is the module Element is required.

dialect/dialect.rb:

module Dialect
 def self.included(caller)
 caller.extend Dialect::Generator::Element
 end
 def self.version
 "Dialect v#{Dialect::VERSION}"
 end
end

dialect/generators/elements.rb:

require 'dialect/dialect'
module Dialect
 module Generator
 module Element
 puts Dialect.version
 end
 end
end

Alternatively, you could also write a file declaring only the version:

dialect/version.rb:

module Dialect 
 def self.version
 "Dialect v#{Dialect::VERSION}"
 end
end

Edit

To answer your question - this is not a good way to do this. The problem you encountered with the require hints to circular dependency - Dialect calls Element, which uses Dialect on its creation.

The correct resolution is to break this dependency by using my version.rb suggestion above, so the code will look like this:

dialect/version.rb:

module Dialect 
 def self.version
 "Dialect v#{Dialect::VERSION}"
 end
end

dialect/generators/elements.rb:

require 'dialect/version'
module Dialect
 module Generator
 module Element
 puts Dialect.version
 end
 end
end

dialect/dialect.rb:

require 'dialect/version'
require 'dialect/generators/elements'
module Dialect
 def self.included(caller)
 caller.extend Dialect::Generator::Element
 end
end
answered Mar 3, 2014 at 13:18
\$\endgroup\$

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.