require "activesupport" class Sqld4r_core def initialize(options) super() @options = options @logfile = File::new( @options["log_file"], "a" ) if @options["logging"] end def run notice "sqld4r: Starting at " + Time.now.strftime("%Y/%m/%d %H:%M:%S") notice "start to parse about SQLDesigner xml file" @structure = Sqld4r_parser.new.parse(@options["sqld_path"]) notice "finish to parse" @structure.each do |table| generate_model_for(table) end @structure.each do |table| add_relationship_to(table) unless @options["skip-relation"] end add_index_for_all(@structure) unless @options["skip-index"] copy_sqld_xml_file unless @options["copy_sqld_to"].nil? execute_command_list unless @options["skip_command_list"] notice "sqld4r: Complete at " + Time.now.strftime("%Y/%m/%d %H:%M:%S") @logfile.close if @logfile end def paramaters_for_model_generator param_string = " " param_string << "--svn " if @options["svn"] param_string << "--git " if @options["git"] param_string << "--skip-timestamps " if @options["skip-timestamps"] param_string << "--skip-migration " if @options["skip-migration"] param_string << "--skip-fixture " if @options["skip-fixture"] param_string << "--quiet " unless @options["verbose"] param_string end # script/generate model post title:string body:text published:boolean owner:references def model_and_columns_from_structure(table) model_columns_string = "" model_name = tablename2modelname(table["tablename"]) model_columns_string << model_name + " " table["colums"].each do |column| #puts column.inspect next if "id" == column["name"] if column["relation"].nil? model_columns_string << column["name"] + ":" + column["datatype"] + " " else rel_table = Inflector.singularize(column["relation"]["table"]) model_columns_string << rel_table + ":references " end end model_columns_string end =begin script/generate model post title:string body:text published:boolean owner:references =end def generate_model_for(table) notice "generate for " + table["tablename"] command = "script/generate " if @options["rspec"] command << "rspec_model " + paramaters_for_model_generator else command << "model " + paramaters_for_model_generator end command << model_and_columns_from_structure(table) exec_shell_command(command) end =begin { "tablename" => "comments", # => "has_many :comments" to Item model "colums" => [ { "relation" => nil, "comment" => "com", }, { "relation" => {"table" => "items", "column" => "id"}, # => "belongs_to :item" to Comment model "comment" => "has_many", }, ], "comment" => "user has many actions" }, class Post < ActiveRecord::Base end relation_models = [ "app/model/comment.rb", "app/model/sometable.rb", ] =end def add_relationship_to(table) notice "add relationship to " + table["tablename"] current_model_name = tablename2modelname(table["tablename"]) relation_models = [] current_model_relations = [] table["colums"].each do |column| next if column["relation"].nil? current_model_relations << tablename2modelname(column["relation"]["table"]) relation_models << tablename2modelname(column["relation"]["table"]) end # current model notice "-add belongs_to relationship to " + table["tablename"] + " about:" if 0 == current_model_relations.size notice "--skip. becase this model dose not have relationship." else notice "--" + current_model_relations.join(",") text_insert_to(modelname2modelpath(current_model_name)) do |file, line| file.puts line if /^class\s.+\s<\sActiveRecord::Base$/ =~ line file.puts '#' + table["comment"] unless table["comment"].nil? current_model_relations.each do |rel| file.puts " belongs_to :" + Inflector.singularize(rel) end end end end # target models notice "-add has_one/has_many relationship to:" if 0 == relation_models.size notice "--skip. because this model dose not have relationship" else notice "--" + relation_models.join(",") relation_models.each do |target_model| text_insert_to(modelname2modelpath(target_model)) do |file, line| file.puts line if /^class\s.+\s<\sActiveRecord::Base$/ =~ line single_name = Inflector.singularize(table["tablename"]) plural_name = table["tablename"] file.puts ' # has_one :' + single_name + ' # TODO:CHECK_ME' file.puts ' has_many :' + plural_name end end end end end def tablename2modelname(tablename) Inflector.singularize(tablename).classify end def modelname2modelpath(modelname) "app/models/" + modelname.underscore + ".rb" end def text_insert_to(filename) current_model_contents = [] File::open(filename, "r") do |file| current_model_contents = file.readlines end File::open(filename, "w") do |file| current_model_contents.each do |line| yield(file, line) end end end =begin % script/generate migration add_index_for_all exists db/migrate create db/migrate/20080622130506_add_index_for_all.rb % cat db/migrate/20080622130506_add_index_for_all.rb class AddIndexForAll < ActiveRecord::Migration def self.up end def self.down end end =end def add_index_for_all(structure) notice "add index to a new migrate file" index_list = [] structure.each do |table| index_list << {"table" => table["tablename"], "column" => "id"} table["colums"].each do |column| index_list << {"table" => table["tablename"], "column" => column["name"]} unless column["relation"].nil? end end if 0 == index_list.size notice "--skip. because this database dose not have tables" else begin result = exec_shell_command("script/generate migration add_index_for_all") # result is " exists db/migrate\n create db/migrate/20080624022342_add_index_for_all.rb" migratefile = result.scan(/create\s\s(db\/migrate\/.+_add_index_for_all.rb)$/).first.first rescue migratefile = nil notice "--error. can not find migration file" end if migratefile text_insert_to(migratefile) do |file, line| file.puts line if /def\sself\.up$/ =~ line index_list.each do |target| file.puts " add_index :" + target["table"] + ", :" + target["column"] end end if /def\sself\.down$/ =~ line index_list.each do |target| file.puts " remove_index :" + target["table"] + ", :" + target["column"] end end end end notice "--modifyed index on " + migratefile end end def copy_sqld_xml_file notice "save this database xml file to " + @options["copy_sqld_to"] exec_shell_command("cp " + @options["sqld_path"] + " " + @options["copy_sqld_to"]) end def execute_command_list notice "execute commands from " + @options["command_list_path"] File::open(@options["command_list_path"], "r") do |file| file.readlines.each { |command| exec_shell_command(command) unless /^#.*/ =~ command or command.chomp.empty? } end end def notice(message) puts "* " + message if @options["verbose"] @logfile.puts "* " + message if @options["logging"] and @logfile end def exec_shell_command(command) command << " > /dev/null" unless @options["verbose"] command = "sudo " + command if @options["sudo"] puts '->' + command if @options["verbose"] @logfile.puts '->' + command if @options["logging"] result = `#{command}`.chomp unless @options["emulate"] puts '-->' + result if @options["verbose"] and not result.nil? and not result.empty? @logfile.puts '-->' + result if @options["logging"] and not result.nil? and not result.empty? Sqld4r_options::error_with_show_usage "receive error from command." unless 0 == $? result end end