D
Dale Martenson
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, rimary_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' )
}
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, rimary_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' )
}