开发者

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/, '&rsquo;')
    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
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜