开发者

Extending Enumerable in Rails 3

UPDATE TO QUESTION

Here is what I have done based on some research and findings.

STEP 1 - I have this module in my Rails 3 project and place it in my lib folder

# lib/enumerable.rb
module Enumerable
   def sum
      return self.inject(0){|acc,i|acc +i}
   end

   def average
      return self.sum/self.length.to_f
   end

   def sample_variance 
       avg=self.average
       sum=self.inject(0){|acc,i|acc +(i-avg)**2}
       return(1/self.length.to_f*sum)
   end

   def standard_deviation
       return Math.sqrt(self.sample_variance)
   end

end

STEP 2 - According to this blog article, in Rails 3 your lib folder will not get loaded automatically. In order to load this module you need to go to your config / application.rb and type this in:

config.autoload_paths += %W(#{config.root}/lib)

STEP 3 - Then in your model my understanding is you type this in to get the开发者_如何转开发 module picked up.

class MyModel < ActiveRecord::Base
    include Enumerable
end

STEP 4 - I then try restart the rails server and try this out and I get false when I would expect it to be true.

MyModel.respond_to?('sample_variance')
# false, when it should be true

What am I doing wrong? Should I not be getting true?


Your inclusion of the main Enumerable module (not your extension) undoubtedly worked, and you can test it by simply checking for any of the methods that were mixed in. The problem is, your 'Include Enumerable' may not have included your file, but rather the main module.

One suggestion is to rename the file name for your extension, and have it loaded through an initializer with a

require 'my_enumerable.rb'

That way you for sure get both Enumerable and your extension to Enumerable loaded.


If I understand what you're driving at, you're trying to use Enumerable's sum method in ActiveRecord. You can do that by converting the current object to an array, then calling Enumerable's sum method on that array.

One more thing: you don't need to use return like you are using it. Ruby will return the last calculated thing from your method. You don't need to use self like that either -- in Ruby, self is the current object.

So if you have a method:

def charlie
  inject{|i, j| i + j + 1}
end

and you call it like this:

(1..2).charlie

self is the current object (1..2).

The output will be 4, with no self or return.

I highly recommend Dave Thomas' lecture on Ruby metaprogramming, I tried to find it, but I could not, it's out there on the web somewhere.


You might want to take a look at this:

http://www.ruby-doc.org/docs/ProgrammingRuby/html/tut_modules.html

You can include a module in a class, and thereby make that module's methods available to that class.

If you include Enumerable into a Rails model, then its methods would be available to that model. But since Enumerable's methods are already available to certain types of objects inside your Rails project, and those objects are available to be instantiated from inside your model, I don't see why you might do that, because Enumerable's methods are working just fine for the purposes they were designed.

Anyway, you might find that one of the following might work for you:

-- use Activerecord's sum method

-- convert your object to an array, and use Enumerable's sum method

-- write your own method, but don't call it sum, because you don't want to confuse yourself.

Try commenting out the second occurrence of module Neuone in the following snippet, and see what happens. Then try commenting out the Charlie.one method, and see what happens.

module Neuone
def one
  'neuone one'
end 

def two
  'neuone two'
end

end

module Neuone
def two
  'neuone two two'
end

end

class Charlie include Neuone

def one
    'charlie one'
end

end

c = Charlie.new p c.one p c.two

0

上一篇:

下一篇:

精彩评论

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

最新问答

问答排行榜