Ruby是Script Language,所有lib都是有載入順序的,最方便改寫一個特定code的方式就是用mask
例如這段code:
def x(a)
puts a
end
> x(1)
#=> 1
def x(a)
puts a + 1
end
> x(1)
#=> 2
okay,這就是mask的真義,之後load的code會蓋掉之前的code,而真實世界怎樣辦到?
Rails下會先require gem後,才會執行config/initializers,所以其實在裡面新增.rb檔,裡面寫gem的對象,其實就可以把該gem的該methods mask掉...類似這個我自己重寫過的will_paginate.rb
看之前請對照原source,其實你會發覺我只是想把該code增加一行指令而已(下面的add this line),然後也請不要整個檔案都copy過去,而是把該method的所有上層宣告含入,其他的則全部刪除即可(就只會蓋到它)
# encoding:utf-8
module WillPaginate
module ViewHelpers
def will_paginate(collection, options = {})
# early exit if there is nothing to render
return nil unless collection.total_pages > 1
options = WillPaginate::ViewHelpers.pagination_options.merge(options)
options[:previous_label] ||= will_paginate_translate(:previous_label) { '← Previous' }
options[:next_label] ||= will_paginate_translate(:next_label) { 'Next →' }
#########add this line
options[:next_label] += "(#{collection.total_entries}#{will_paginate_translate(:unit_record)}/#{will_paginate_translate(:unit_page)}#{collection.per_page})" if options[:show_total]
#########add this line
# get the renderer instance
renderer = case options[:renderer]
when nil
raise ArgumentError, ":renderer not specified"
when String
klass = if options[:renderer].respond_to? :constantize then options[:renderer].constantize
else Object.const_get(options[:renderer]) # poor man's constantize
end
klass.new
when Class then options[:renderer].new
else options[:renderer]
end
# render HTML for pagination
renderer.prepare collection, options, self
renderer.to_html
end
end
end
這行的作用其實是在『下一頁』這按鈕上面,改成『下一頁(12307筆/每頁30)』,也就是增加total和per page的文字說明(當然這邊有另外作i18n就是了)
so...沒有fork,只有mask,當然方便的風險也還是有的,如果未來這個gem大量改寫了,那該code可能會掛掉,以前就曾經幫paperclip寫video process lib(video => flv)就曾出現這類的事情X"D...不過你會發覺,其實只要再去查source,然後一樣mask過去即可,比起完整的fork去處理...應該簡潔省事得多唄...:)
沒有留言:
張貼留言