in Tokyo, Japan. • I’m a Canadian from Montréal. • I work at a company called Degica. • I’m the author of a gem called Mobility. • I blog at dejimata.com.
software is to write generic software. Instead of designing a single API that completely handles a specific case, you write multiple APIs that handle smaller, more generic parts of that use case and then handling the entire case is just gluing those parts together. When you approach code like that, designing APIs that solve generic problems, you can more easily reuse those APIs later, to solve other problems.” “ The Development of Sequel, May 2012 “
locale) return value if value.present? end nil end def column_value(attribute, locale) read_attribute("#{attribute}_#{locale}") end end column storage "title_en"
that the methods defined by the user to tailor the framework will often be called from within the framework itself, rather than from the user's application code. The framework often plays the role of the main program in coordinating and sequencing application activity. This inversion of control gives frameworks the power to serve as extensible skeletons. The methods supplied by the user tailor the generic algorithms defined in the framework for a particular application.” “ - Ralph E. Johnson & Brian Foote, Designing Reusable Classes (1988)
end def define_backend(attribute, backend_class) define_method "#{attribute}_backend" do @backends[attribute] ||= backend_class.new(self, attribute) end end
end def define_backend(attribute, backend_class) define_method "#{attribute}_backend" do @backends[attribute] ||= backend_class.new(self, attribute) end end ColumnBackend
end def read(locale) @model.read_attribute(column(locale)) end def write(locale, value) @model.write_attribute(column(locale), value) end end "#{@attribute}_#{locale}"
|plugin| backend_subclass.include plugin end attributes.each do |attribute| define_accessor(attribute) define_backend(attribute, backend_subclass) end backend_subclass.setup_model(self, attributes) end plugins
plugins.each { |plugin| backend_subclass.include plugin } attributes.each do |attribute| define_accessor(attribute) define_backend(attribute, backend_subclass) end backend_subclass.setup_model(self, attributes) end def define_backend(attribute, backend_class) define_method "#{attribute}_backend" do @backends ||= {} @backends[attribute] ||= backend_class.new(self, attribute) end end def define_accessor(attribute) define_method(attribute) do send("#{attribute}_backend").read(I18n.locale) end define_method("#{attribute}=") do |value| send("#{attribute}_backend").write(I18n.locale, value) end end end
plugins.each { |plugin| backend_subclass.include plugin } attributes.each do |attribute| define_accessor(attribute) define_backend(attribute, backend_subclass) end backend_subclass.setup_model(self, attributes) end def define_backend(attribute, backend_class) define_method "#{attribute}_backend" do @backends ||= {} @backends[attribute] ||= backend_class.new(self, attribute) end end def define_accessor(attribute) define_method(attribute) do send("#{attribute}_backend").read(I18n.locale) end define_method("#{attribute}=") do |value| send("#{attribute}_backend").write(I18n.locale, value) end end end No ActiveRecord
plugins.each { |plugin| backend_subclass.include plugin } attributes.each do |attribute| define_accessor(attribute) define_backend(attribute, backend_subclass) end backend_subclass.setup_model(self, attributes) end def define_backend(attribute, backend_class) define_method "#{attribute}_backend" do @backends ||= {} @backends[attribute] ||= backend_class.new(self, attribute) end end def define_accessor(attribute) define_method(attribute) do send("#{attribute}_backend").read(I18n.locale) end define_method("#{attribute}=") do |value| send("#{attribute}_backend").write(I18n.locale, value) end end end No ActiveRecord No ActiveSupport
plugins.each { |plugin| backend_subclass.include plugin } attributes.each do |attribute| define_accessor(attribute) define_backend(attribute, backend_subclass) end backend_subclass.setup_model(self, attributes) end def define_backend(attribute, backend_class) define_method "#{attribute}_backend" do @backends ||= {} @backends[attribute] ||= backend_class.new(self, attribute) end end def define_accessor(attribute) define_method(attribute) do send("#{attribute}_backend").read(I18n.locale) end define_method("#{attribute}=") do |value| send("#{attribute}_backend").write(I18n.locale, value) end end end No ActiveRecord No ActiveSupport No Persisted Storage
plugins.each { |plugin| backend_subclass.include plugin } attributes.each do |attribute| define_accessor(attribute) define_backend(attribute, backend_subclass) end backend_subclass.setup_model(self, attributes) end def define_backend(attribute, backend_class) define_method "#{attribute}_backend" do @backends ||= {} @backends[attribute] ||= backend_class.new(self, attribute) end end def define_accessor(attribute) define_method(attribute) do send("#{attribute}_backend").read(I18n.locale) end define_method("#{attribute}=") do |value| send("#{attribute}_backend").write(I18n.locale, value) end end end No ActiveRecord No ActiveSupport No Persisted Storage only references to i18n