The Rails method Array#to_sentence
allows for the following:
['a', 'b', 'c'].to_sentence # gives: "a, b, and c"
I would like to extend this method to allow it to take a block, so that you can do something like the following (where people is an array of Person objects, which have the name attribute):
people.to_sentence { |person| person.name }
# => "Bill, John, and Mark"
I don't have a problem with writing the extension method. But I can't work out where to put it. The Rails core extensions get loaded somewhere down in the depths of ActiveSupport
.
My need is for a place where user-defined code is always loaded, and is pre-loaded (before any application code).
The redefined method accesses the private components of the redefined class and not any private components of the same name in the superclass. In the redefined method, the implementation of the direct superclass can be called using super->meth.
Static method of parent class can be re-declared by child class, which hides the parent class static method. This is known as Redefinition in Java.
define_method is a method defined in Module class which you can use to create methods dynamically. To use define_method , you call it with the name of the new method and a block where the parameters of the block become the parameters of the new method.
Create config/initializers/super_to_sentence.rb
. All files in this directory are loaded after Rails has been loaded, so you'll have a chance to override Rails' definition of Array#to_sentence
.
For code you want to load before Rails gets loaded, add it to config/environment.rb
.
I like to do this:
# config/initializers/app.rb
Dir[File.join(Rails.root, "lib", "core_ext", "*.rb")].each {|l| require l }
# lib/core_ext/array.rb
class Array
def to_sentence_with_block(*args, &block)
if block_given?
# do something...
# to_sentence_without_block(*args) perhaps?
else
to_sentence_without_block(*args)
end
end
alias_method_chain :to_sentence, :block
end
I think this is an ugly idea. Why dont you just write
people.collect { |person| person.name }.to_sentence
This looks almost the same and will not confuse other people reading your code (like yourself in 2 years)
just searching around the web, seems like good practice is to add it in lib/
so if you wanna extend some ruby class (in my case, DateTime), just put the code in .rb and then in config/environment.rb:
config.after_initialize do
require "lib/super_datetime.rb"
end
my super_datetime.rb looks like this (code from http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/140184):
class DateTime
def days_in_month
self::class.civil(year, month, -1).day
end
alias dim days_in_month
def weekdays
(1..dim).to_a
end
end
restart your server and you'll have access to the new method for all DateTime objects.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With