3

I'm trying to extend core classes and have no idea why the following fails when being called through the Rails 4 console:

# config/application.rb
config.autoload_paths += Dir["#{config.root}/lib/**/"]

# lib/core_ext/string.rb
class String
  def test
    self + " some test"
  end
end

# lib/core_ext/array.rb
class Array
  def mean
    sum / size if sum && size
  end
end

# lib/core_ext/test.rb
class Test
  def test
    "some test"
  end
end

Rails console output:

1] pry(main)> test = Test.new
#<Test:0x007ff63971b588>
[2] pry(main)> test.test
"some test"
[3] pry(main)> "string".test
NoMethodError: private method `test' called for "string":String
from (pry):3:in `__pry__'
[4] pry(main)> [1,2,3].mean
NoMethodError: undefined method `mean' for [1, 2, 3]:Array
from (pry):4:in `__pry__'
migu
  • 4,236
  • 5
  • 39
  • 60
  • I can work it in plain pry. – Karthik T Aug 13 '13 at 01:07
  • Take a look at http://guides.rubyonrails.org/plugins.html#extending-core-classes perhaps they are blocking the default way somehow – Karthik T Aug 13 '13 at 01:09
  • and http://stackoverflow.com/questions/5654517/in-ruby-on-rails-to-extend-the-string-class-where-should-the-code-be-put-in – Karthik T Aug 13 '13 at 01:11
  • and http://stackoverflow.com/questions/4425620/where-is-the-right-place-to-put-predefined-class-e-g-string-symbol-extension?rq=1 – Karthik T Aug 13 '13 at 01:12
  • Thanks for your reply. Tried `Array.class_eval do` and that didn't work either. Files are being loaded, otherwise I couldn't use the Test class. – migu Aug 13 '13 at 01:15
  • Sorry, you were right, this did the trick: `Dir[File.join(Rails.root, "lib", "core_ext", "*.rb")].each {|l| require l }`. I assumed `config.autoload_paths += Dir["#{config.root}/lib/**/"]` would suffice. – migu Aug 13 '13 at 01:17
  • If you put it in as an answer, then I'll mark as correct and upvote. Thx – migu Aug 13 '13 at 01:17

3 Answers3

4

You should add the following line to effectively require the files into your project

Dir[File.join(Rails.root, "lib", "core_ext", "*.rb")].each {|l| require l }

Taken from In Ruby on Rails, to extend the String class, where should the code be put in?

Community
  • 1
  • 1
Karthik T
  • 31,456
  • 5
  • 68
  • 87
  • 1
    This simply DOES NOT WORK for me. I don't know why. Where exactly should this line go? I have the exact same configuration. – Ariel Mar 03 '14 at 09:58
  • 2
    @Ariel I havent tried it personally, but I guess application.rb around(below) where Bundler#require is invoked would be a decent area. – Karthik T Mar 03 '14 at 15:18
4

I would add the following:

# In config/initializers/require.rb:
require "core_ext/string" 
require "core_ext/array" 
require "core_ext/test"

And not modify config/application.rb's autoload_paths, which do not eager load your extensions. If a module or class is already loaded somewhere else, it won't extend it. For references, check these SO question1 and question2

Community
  • 1
  • 1
konyak
  • 10,818
  • 4
  • 59
  • 65
1

Notice that if you are interested in static methods (e.g. String.test) you you declare it as def self.test.

guyaloni
  • 4,972
  • 5
  • 52
  • 92