1*276da39aSCy Schubert# ========================================== 2*276da39aSCy Schubert# Unity Project - A Test Framework for C 3*276da39aSCy Schubert# Copyright (c) 2007 Mike Karlesky, Mark VanderVoord, Greg Williams 4*276da39aSCy Schubert# [Released under MIT License. Please refer to license.txt for details] 5*276da39aSCy Schubert# ========================================== 6*276da39aSCy Schubert 7*276da39aSCy Schubert# This script creates all the files with start code necessary for a new module. 8*276da39aSCy Schubert# A simple module only requires a source file, header file, and test file. 9*276da39aSCy Schubert# Triad modules require a source, header, and test file for each triad type (like model, conductor, and hardware). 10*276da39aSCy Schubert 11*276da39aSCy Schubertrequire 'rubygems' 12*276da39aSCy Schubertrequire 'fileutils' 13*276da39aSCy Schubert 14*276da39aSCy SchubertHERE = File.expand_path(File.dirname(__FILE__)) + '/' 15*276da39aSCy Schubert 16*276da39aSCy Schubert#help text when requested 17*276da39aSCy SchubertHELP_TEXT = [ "\nGENERATE MODULE\n-------- ------", 18*276da39aSCy Schubert "\nUsage: ruby generate_module [options] module_name", 19*276da39aSCy Schubert " -i\"include\" sets the path to output headers to 'include' (DEFAULT ../src)", 20*276da39aSCy Schubert " -s\"../src\" sets the path to output source to '../src' (DEFAULT ../src)", 21*276da39aSCy Schubert " -t\"C:/test\" sets the path to output source to 'C:/test' (DEFAULT ../test)", 22*276da39aSCy Schubert " -p\"MCH\" sets the output pattern to MCH.", 23*276da39aSCy Schubert " dh - driver hardware.", 24*276da39aSCy Schubert " dih - driver interrupt hardware.", 25*276da39aSCy Schubert " mch - model conductor hardware.", 26*276da39aSCy Schubert " mvp - model view presenter.", 27*276da39aSCy Schubert " src - just a single source module. (DEFAULT)", 28*276da39aSCy Schubert " -d destroy module instead of creating it.", 29*276da39aSCy Schubert " -u update subversion too (requires subversion command line)", 30*276da39aSCy Schubert " -y\"my.yml\" selects a different yaml config file for module generation", 31*276da39aSCy Schubert "" ].join("\n") 32*276da39aSCy Schubert 33*276da39aSCy Schubert#Built in patterns 34*276da39aSCy SchubertPATTERNS = { 'src' => {'' => { :inc => [] } }, 35*276da39aSCy Schubert 'dh' => {'Driver' => { :inc => ['%1$sHardware.h'] }, 36*276da39aSCy Schubert 'Hardware' => { :inc => [] } 37*276da39aSCy Schubert }, 38*276da39aSCy Schubert 'dih' => {'Driver' => { :inc => ['%1$sHardware.h', '%1$sInterrupt.h'] }, 39*276da39aSCy Schubert 'Interrupt'=> { :inc => ['%1$sHardware.h'] }, 40*276da39aSCy Schubert 'Hardware' => { :inc => [] } 41*276da39aSCy Schubert }, 42*276da39aSCy Schubert 'mch' => {'Model' => { :inc => [] }, 43*276da39aSCy Schubert 'Conductor'=> { :inc => ['%1$sModel.h', '%1$sHardware.h'] }, 44*276da39aSCy Schubert 'Hardware' => { :inc => [] } 45*276da39aSCy Schubert }, 46*276da39aSCy Schubert 'mvp' => {'Model' => { :inc => [] }, 47*276da39aSCy Schubert 'Presenter'=> { :inc => ['%1$sModel.h', '%1$sView.h'] }, 48*276da39aSCy Schubert 'View' => { :inc => [] } 49*276da39aSCy Schubert } 50*276da39aSCy Schubert } 51*276da39aSCy Schubert 52*276da39aSCy Schubert#TEMPLATE_TST 53*276da39aSCy SchubertTEMPLATE_TST = %q[#include "unity.h" 54*276da39aSCy Schubert%2$s#include "%1$s.h" 55*276da39aSCy Schubert 56*276da39aSCy Schubertvoid setUp(void) 57*276da39aSCy Schubert{ 58*276da39aSCy Schubert} 59*276da39aSCy Schubert 60*276da39aSCy Schubertvoid tearDown(void) 61*276da39aSCy Schubert{ 62*276da39aSCy Schubert} 63*276da39aSCy Schubert 64*276da39aSCy Schubertvoid test_%1$s_NeedToImplement(void) 65*276da39aSCy Schubert{ 66*276da39aSCy Schubert TEST_IGNORE(); 67*276da39aSCy Schubert} 68*276da39aSCy Schubert] 69*276da39aSCy Schubert 70*276da39aSCy Schubert#TEMPLATE_SRC 71*276da39aSCy SchubertTEMPLATE_SRC = %q[%2$s#include "%1$s.h" 72*276da39aSCy Schubert] 73*276da39aSCy Schubert 74*276da39aSCy Schubert#TEMPLATE_INC 75*276da39aSCy SchubertTEMPLATE_INC = %q[#ifndef _%3$s_H 76*276da39aSCy Schubert#define _%3$s_H%2$s 77*276da39aSCy Schubert 78*276da39aSCy Schubert#endif // _%3$s_H 79*276da39aSCy Schubert] 80*276da39aSCy Schubert 81*276da39aSCy Schubert# Parse the command line parameters. 82*276da39aSCy SchubertARGV.each do |arg| 83*276da39aSCy Schubert case(arg) 84*276da39aSCy Schubert when /^-d/ then @destroy = true 85*276da39aSCy Schubert when /^-u/ then @update_svn = true 86*276da39aSCy Schubert when /^-p(\w+)/ then @pattern = $1 87*276da39aSCy Schubert when /^-s(.+)/ then @path_src = $1 88*276da39aSCy Schubert when /^-i(.+)/ then @path_inc = $1 89*276da39aSCy Schubert when /^-t(.+)/ then @path_tst = $1 90*276da39aSCy Schubert when /^-y(.+)/ then @yaml_config = $1 91*276da39aSCy Schubert when /^(\w+)/ 92*276da39aSCy Schubert raise "ERROR: You can't have more than one Module name specified!" unless @module_name.nil? 93*276da39aSCy Schubert @module_name = arg 94*276da39aSCy Schubert when /^-(h|-help)/ 95*276da39aSCy Schubert puts HELP_TEXT 96*276da39aSCy Schubert exit 97*276da39aSCy Schubert else 98*276da39aSCy Schubert raise "ERROR: Unknown option specified '#{arg}'" 99*276da39aSCy Schubert end 100*276da39aSCy Schubertend 101*276da39aSCy Schubertraise "ERROR: You must have a Module name specified! (use option -h for help)" if @module_name.nil? 102*276da39aSCy Schubert 103*276da39aSCy Schubert#load yaml file if one was requested 104*276da39aSCy Schubertif @yaml_config 105*276da39aSCy Schubert require 'yaml' 106*276da39aSCy Schubert cfg = YAML.load_file(HERE + @yaml_config)[:generate_module] 107*276da39aSCy Schubert @path_src = cfg[:defaults][:path_src] if @path_src.nil? 108*276da39aSCy Schubert @path_inc = cfg[:defaults][:path_inc] if @path_inc.nil? 109*276da39aSCy Schubert @path_tst = cfg[:defaults][:path_tst] if @path_tst.nil? 110*276da39aSCy Schubert @update_svn = cfg[:defaults][:update_svn] if @update_svn.nil? 111*276da39aSCy Schubert @extra_inc = cfg[:includes] 112*276da39aSCy Schubert @boilerplates = cfg[:boilerplates] 113*276da39aSCy Schubertelse 114*276da39aSCy Schubert @boilerplates = {} 115*276da39aSCy Schubertend 116*276da39aSCy Schubert 117*276da39aSCy Schubert# Create default file paths if none were provided 118*276da39aSCy Schubert@path_src = HERE + "../src/" if @path_src.nil? 119*276da39aSCy Schubert@path_inc = @path_src if @path_inc.nil? 120*276da39aSCy Schubert@path_tst = HERE + "../test/" if @path_tst.nil? 121*276da39aSCy Schubert@path_src += '/' unless (@path_src[-1] == 47) 122*276da39aSCy Schubert@path_inc += '/' unless (@path_inc[-1] == 47) 123*276da39aSCy Schubert@path_tst += '/' unless (@path_tst[-1] == 47) 124*276da39aSCy Schubert@pattern = 'src' if @pattern.nil? 125*276da39aSCy Schubert@includes = { :src => [], :inc => [], :tst => [] } 126*276da39aSCy Schubert@includes.merge!(@extra_inc) unless @extra_inc.nil? 127*276da39aSCy Schubert 128*276da39aSCy Schubert#create triad definition 129*276da39aSCy SchubertTRIAD = [ { :ext => '.c', :path => @path_src, :template => TEMPLATE_SRC, :inc => :src, :boilerplate => @boilerplates[:src] }, 130*276da39aSCy Schubert { :ext => '.h', :path => @path_inc, :template => TEMPLATE_INC, :inc => :inc, :boilerplate => @boilerplates[:inc] }, 131*276da39aSCy Schubert { :ext => '.c', :path => @path_tst+'Test', :template => TEMPLATE_TST, :inc => :tst, :boilerplate => @boilerplates[:tst] }, 132*276da39aSCy Schubert ] 133*276da39aSCy Schubert 134*276da39aSCy Schubert#prepare the pattern for use 135*276da39aSCy Schubert@patterns = PATTERNS[@pattern.downcase] 136*276da39aSCy Schubertraise "ERROR: The design pattern specified isn't one that I recognize!" if @patterns.nil? 137*276da39aSCy Schubert 138*276da39aSCy Schubert# Assemble the path/names of the files we need to work with. 139*276da39aSCy Schubertfiles = [] 140*276da39aSCy SchubertTRIAD.each do |triad| 141*276da39aSCy Schubert @patterns.each_pair do |pattern_file, pattern_traits| 142*276da39aSCy Schubert files << { 143*276da39aSCy Schubert :path => "#{triad[:path]}#{@module_name}#{pattern_file}#{triad[:ext]}", 144*276da39aSCy Schubert :name => "#{@module_name}#{pattern_file}", 145*276da39aSCy Schubert :template => triad[:template], 146*276da39aSCy Schubert :boilerplate => triad[:boilerplate], 147*276da39aSCy Schubert :includes => case(triad[:inc]) 148*276da39aSCy Schubert when :src then @includes[:src] | pattern_traits[:inc].map{|f| f % [@module_name]} 149*276da39aSCy Schubert when :inc then @includes[:inc] 150*276da39aSCy Schubert when :tst then @includes[:tst] | pattern_traits[:inc].map{|f| "Mock#{f}"% [@module_name]} 151*276da39aSCy Schubert end 152*276da39aSCy Schubert } 153*276da39aSCy Schubert end 154*276da39aSCy Schubertend 155*276da39aSCy Schubert 156*276da39aSCy Schubert# destroy files if that was what was requested 157*276da39aSCy Schubertif @destroy 158*276da39aSCy Schubert files.each do |filespec| 159*276da39aSCy Schubert file = filespec[:path] 160*276da39aSCy Schubert if File.exist?(file) 161*276da39aSCy Schubert if @update_svn 162*276da39aSCy Schubert `svn delete \"#{file}\" --force` 163*276da39aSCy Schubert puts "File #{file} deleted and removed from source control" 164*276da39aSCy Schubert else 165*276da39aSCy Schubert FileUtils.remove(file) 166*276da39aSCy Schubert puts "File #{file} deleted" 167*276da39aSCy Schubert end 168*276da39aSCy Schubert else 169*276da39aSCy Schubert puts "File #{file} does not exist so cannot be removed." 170*276da39aSCy Schubert end 171*276da39aSCy Schubert end 172*276da39aSCy Schubert puts "Destroy Complete" 173*276da39aSCy Schubert exit 174*276da39aSCy Schubertend 175*276da39aSCy Schubert 176*276da39aSCy Schubert#Abort if any module already exists 177*276da39aSCy Schubertfiles.each do |file| 178*276da39aSCy Schubert raise "ERROR: File #{file[:name]} already exists. Exiting." if File.exist?(file[:path]) 179*276da39aSCy Schubertend 180*276da39aSCy Schubert 181*276da39aSCy Schubert# Create Source Modules 182*276da39aSCy Schubertfiles.each_with_index do |file, i| 183*276da39aSCy Schubert File.open(file[:path], 'w') do |f| 184*276da39aSCy Schubert f.write(file[:boilerplate] % [file[:name]]) unless file[:boilerplate].nil? 185*276da39aSCy Schubert f.write(file[:template] % [ file[:name], 186*276da39aSCy Schubert file[:includes].map{|f| "#include \"#{f}\"\n"}.join, 187*276da39aSCy Schubert file[:name].upcase ] 188*276da39aSCy Schubert ) 189*276da39aSCy Schubert end 190*276da39aSCy Schubert if (@update_svn) 191*276da39aSCy Schubert `svn add \"#{file[:path]}\"` 192*276da39aSCy Schubert if $?.exitstatus == 0 193*276da39aSCy Schubert puts "File #{file[:path]} created and added to source control" 194*276da39aSCy Schubert else 195*276da39aSCy Schubert puts "File #{file[:path]} created but FAILED adding to source control!" 196*276da39aSCy Schubert end 197*276da39aSCy Schubert else 198*276da39aSCy Schubert puts "File #{file[:path]} created" 199*276da39aSCy Schubert end 200*276da39aSCy Schubertend 201*276da39aSCy Schubert 202*276da39aSCy Schubertputs 'Generate Complete' 203