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