From: Dale Martenson Date: 2005-11-01T02:14:12+09:00 Subject: TumbleDRYer (#53) - my solution I am not sure I understood the quiz this week. When I first read it, I thought it might be that one should analyze the input, build a dictionary, determine the repetition automatically and generate the output using a simplified form. My first thought was to huffman encode the dictionary based on entity frequency. The result was great and all :-) ... but not very readable. After rereading the quiz, I took it to mean how would you apply the DRY principle to generating this repetitive output. No programmatic analysis required. Here is a solution, using a 'little language' to represent another. My idea was to set the defaults so that they reflected the most common representation. That way only a few special cases were required. Sorry, if I misunderstood the quiz. --Dale module SqlDsl CT_DEFAULTS = { :type => 'MyISAM', :auto_increment => true, :auto_increment_value => 3, :auto_id => true } def ct( name, attributes={} ) a = CT_DEFAULTS.merge(attributes) "CREATE TABLE `#{name}` (\n" + "#{" `id` int(11) NOT NULL auto_increment,\n" if a[:auto_id]}" + (( a[:auto_id] ) ? yield : yield.sub( /,\n$/, "\n" ) ) + "#{" PRIMARY KEY (`id`)\n" if a[:auto_id]}" + ") TYPE=#{a[:type]} #{"AUTO_INCREMENT=#{a[:auto_increment_value]}" if a[:auto_increment]} ;\n\n" end VC_DEFAULTS = { :size => 50, :null_allowed => false, :default => true, :default_value => '' } def vc( name, attributes={} ) a = VC_DEFAULTS.merge(attributes) " `#{name}` varchar(#{a[:size]}) " + not_null(a) + default(a) + ",\n" end TEXT_DEFAULTS = { :null_allowed => false } def text( name, attributes={} ) a = TEXT_DEFAULTS.merge(attributes) " `#{name}` text " + not_null(a) + ",\n" end ID_DEFAULTS = { :size => 11, :null_allowed => false, :default => true, :default_value => '0' } def id( name, attributes={} ) a = ID_DEFAULTS.merge(attributes) " `#{name}` int(#{a[:size]}) " + not_null(a) + default(a) + ",\n" end DATE_DEFAULTS = { :null_allowed => false, :default => true, :default_value => '0000-00-00' } def date( name, attributes={} ) a = DATE_DEFAULTS.merge(attributes) " `#{name}` date " + not_null(a) + default(a) + ",\n" end def pk( name ) " PRIMARY KEY (`#{name}`),\n" end def key( name, value ) " KEY `#{name}` (`#{value}`),\n" end def not_null( a ) "#{" NOT NULL" unless a[:null_allowed]}" end def default( a ) "#{" default '#{a[:default_value]}'" if a[:default]}" end def auto_increment( a ) "#{" auto_increment" if a[:auto_increment]}" end end include SqlDsl print ct( 'authors' ) { vc( 'firstname' ) + vc( 'name' ) + vc( 'nickname' ) + vc( 'contact' ) + vc( 'password' ) + text( 'description' ) } + ct( 'categories' ) { vc( 'name', :size=>20 ) + vc( 'description', :size=>70 ) } + ct( 'categories_documents', :auto_id=>false, :primary_key=>false, :auto_increment=>false ) { id( 'category_id' ) + id( 'document_id' ) } + ct( 'documents', :auto_id=>false, :auto_increment_value=>14 ) { id( 'id', :auto_increment=>true, :default=>false ) + vc( 'title' ) + text( 'description' ) + id( 'author_id' ) + date( 'date' ) + vc( 'filename' ) + pk( 'id' ) + key( 'document', 'title' ) }