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