refactoring - How to refactor singleton methods in Ruby? -
currently have code following (simplified somewhat). eventually, i've added more , more new classes d1/d2, , think it's time refactoring make more elegant. goal of course make adding new class dx use little duplicate code possible. @ least, duplicate parts of calling fileimporter.import
inside singleton method dx.import
should factored out.
module fileimporter def self.import(main_window, viewers) ... importer = yield file # delegate d1/d2 preparing importer object ... end end class d1 def self.import(main_window) viewers = [:v11, ] # d1 specific viewers fileimporter.import(main_window, viewers) |file| importer = self.new(file) ... # d1 specific handling of importer return importer end end end class d2 def self.import(main_window) viewers = [:v21,:v22, ] # d2 specific viewers fileimporter.import(main_window, viewers) |file| importer = self.new(file) ... # d2 specific handling of importer return importer end end end # client code calls d1.import(...) or d2.import(...)
essentially fileimporter.import
common part, dx.import
being variation. i'm not sure how refactor these singleton methods. common ruby way of doing this?
update: (some comments added code above, make intension clearer ...)
originally, i've left out code thought not significant avoid confusion. should have mentioned code above result of refactoring class d1 , d2 (by moving common part out , module fileimporter
). purpose of d1.import
, d2.import
create objects of proper class (and possibly followed class-specific handling before returning block). fileimporter.import
common logic, within @ point yield specific class generating importer object.
i feel class d1 , d2 , looks similar , should possible further refactor them. example, both call fileimporter.import
supply block, within both create object of itself.
solution: didn't realize call base class's singleton methods calling super
within derived class's corresponding singleton methods. main problem had , not able go route. i've accepted @makevoid answer indeed makes creating new derived classes more easily.
using common base class elegant refactoring solution, 1 problem new derived classes use 1 base class quota. i've came class macro method provides more concise results derived class perspective.
module fileimporter def self.included(mod) mod.extend classmethods end module classmethods def importer_viewer(*viewers, &blk) @viewers = viewers @blk = blk class << self def import(main_window) if @blk.nil? fileimporter.import(main_window, @viewers) |file| self.new(file) end else fileimporter.import(main_window, @viewers, &@blk) end end end end end def self.import(main_window, viewers, multi=true) ... importer = yield file # delegate d1/d2 preparing importer object ... end end class d1 include fileimporter importer_viewer [:v11, ] ... # d1 specific handling of importer end end class d2 include fileimporter importer_viewer [:v21,:v22, ] ... # d2 specific handling of importer end end
maybe it's not best solution @ first seems dx classes share same behaviour, sublassing them c class has self.import method uses block accept other code work. or done including module too.
anyway, should work (sorry shorter names prototyping). notice changed fileimporter.import method name avoid misunderstandings , note haven't tested code :)
module f def self.fimport(something) yield "file" end end class c include f def initialize(f) end def self.import(something, &block) f.fimport(something) { |f| d = self.new(f) block.call d } end end class d1 < c def self.import(something) super(something){ puts } end end class d2 < c def self.import(something) super(something){ puts } end end p d1.import("a") p d2.import("b") #=> #=> #<d1:0x100163068> #=> b #=> #<d2:0x100162e88>
Comments
Post a Comment