Using classes in a module from the lib directory - Rails 3
I have a setup in the lib directory like so:
lib/
copy_process.rb
copy_process/
processor.rb
The copy_process.rb and processor.rb contain the module definition CopyProcess. The copy_process.rb defines the CopyFile class as well:
module CopyProcess
class CopyFile
end
end
The processor.rb is structured like so:
module CopyProcess
class Processer
end
end
In one of its methods, it creates a new copy file object:
def append_file_if_valid(file_contents, headers, files, file_name)
unless headers
raise "Headers not found"
else
files << CopyProcess::CopyFile.new()
end
end
When I used these files as part of a command line ruby program, it worked fine. However, i started putting it into a rails app, and I have written cucumber/capybara tests to hit the buttons and so forth where this is used. I initialize a Processor object from one of my AR models, and call the above method a few times. It cannot seem to find the CopyFile class, even though I have the following code in my application.rb
config.autoload_paths += %W(#{config.root}/lib)
config.autoload_paths += Dir["#{config.root}/lib/**/"]
Any ideas?
===============================================================
Edit Above was solved by extracting the copy file class into it's own file under lib. I now have another issue:
The CopyFile class refers to module-level helper methods that sit in lib/copy_process.rb, like so:
module CopyProcess
# Gets the index of a value inside an array of the given array
def get_inner_index(value, arr)
idx = nil
arr.each_with_index do |e, i|
if e[0] == value
idx = i
end
end
return idx
end
def includes_inner?(value, arr)
bool = false
arr.each { |e| bool = true if e[0] == value }
return bool
end
# Encloses the string in double quotes, in case it contains a comma
# @param [String] - the string to enclose
# @return [String]
def enclose(string)
string = string.gsub(/\u2019/, '’')
if string.index(',')
return "\"#{string}\""
else
return string
end
end
end
When I run my cucumber tests, i get the following error:
undefined method `includes_inner?' for CopyProcess:Module (NoMethodError)
./lib/copy_process/copy_file.rb:64:in `set_element_name_and_counter'
Which refers to this method here:
def set_element_name_and_counter(element_names, name)
if !CopyProcess::includes_inner?(name, element_names)
element_names << [name, 1]
else
# if it's in the array already, find it and increment the counter
current_element = element_names[CopyProcess::get_inner_index(name, element_names)]
element_names[CopyProcess::get_inner_index(name, element_names)] = [current_element[0], current_element[1]+1]
end
element_names
end
I also tried moving the copy_file.rb and other files in the lib/copy_process/ directory up a level into the lib directory. I then received the following error:
Expected /Users/aaronmcleod/Documents/work/copy_process/lib/copy_file.rb to define CopyFile (LoadError)
./lib/processor.rb:48:in `append_file_if_valid'
The line that the error states creates an instance of CopyFile. I guess rails doesn't li开发者_JS百科ke loading the files in that fashion, and for the former setup, I think the copy_file.rb is having issues loading the rest of the module. I tried requiring it and so forth, but no luck. You can also find my most recent code here: https://github.com/agmcleod/Copy-Process/tree/rails
First config.autoload_paths += %W(#{config.root}/lib)
should be sufficient. This tells rails to start looking for properly structured files at /lib.
Second, I think that you're running into issues because CopyFile
isn't where rails expects it to be. As far as I know your setup 'should' work but have you tried seperating CopyFile
out into its own file under the copy_process folder? My guess is that since the copy_process folder exists, it is expecting all CopyProcess::*
classes to be defined there instead of the copy_process.rb.
EDIT: You may consider opening another question, but the second half of your question is a different problem entirely.
You define methods in your module like so,
module X
def method_one
puts "hi"
end
end
Methods of this form are instance methods on the module, and they have very special restrictions. For instance, you can not access them from outside the module definition (I'm skeptical how these worked previously). Executing the above gives
> X::method_one
NoMethodError: undefined method `method_one' for X:Module
If you want to access these methods from other scopes you have a few options.
Use Class Methods
module X
def self.method_one
puts "hi"
end
end
X::hi #=> "hi"
Use Mixins
module X
module Helpers
def method_one
puts "hi"
end
end
end
class CopyFile
include X::Helpers
def some_method
method_one #=> "hi"
self.method_one #=> "hi"
end
end
精彩评论