|
11 | 11 | require 'rubygems' |
12 | 12 | require 'fileutils' |
13 | 13 |
|
14 | | -HERE = File.expand_path(File.dirname(__FILE__)) + '/' |
15 | | - |
16 | | -#help text when requested |
17 | | -HELP_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 |
34 | | -PATTERNS = { '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 | 14 | #TEMPLATE_TST |
53 | | -TEMPLATE_TST = %q[#include "unity.h" |
| 15 | +TEMPLATE_TST ||= %q[#include "unity.h" |
54 | 16 | %2$s#include "%1$s.h" |
55 | 17 |
|
56 | 18 | void setUp(void) |
|
68 | 30 | ] |
69 | 31 |
|
70 | 32 | #TEMPLATE_SRC |
71 | | -TEMPLATE_SRC = %q[%2$s#include "%1$s.h" |
| 33 | +TEMPLATE_SRC ||= %q[%2$s#include "%1$s.h" |
72 | 34 | ] |
73 | 35 |
|
74 | 36 | #TEMPLATE_INC |
75 | | -TEMPLATE_INC = %q[#ifndef _%3$s_H |
| 37 | +TEMPLATE_INC ||= %q[#ifndef _%3$s_H |
76 | 38 | #define _%3$s_H%2$s |
77 | 39 |
|
78 | 40 | #endif // _%3$s_H |
79 | 41 | ] |
80 | 42 |
|
81 | | -# Parse the command line parameters. |
82 | | -ARGV.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}'" |
| 43 | +class UnityModuleGenerator |
| 44 | + |
| 45 | + ############################ |
| 46 | + def initialize(options=nil) |
| 47 | + |
| 48 | + here = File.expand_path(File.dirname(__FILE__)) + '/' |
| 49 | + |
| 50 | + @options = UnityModuleGenerator.default_options |
| 51 | + case(options) |
| 52 | + when NilClass then @options |
| 53 | + when String then @options.merge!(UnityModuleGenerator.grab_config(options)) |
| 54 | + when Hash then @options.merge!(options) |
| 55 | + else raise "If you specify arguments, it should be a filename or a hash of options" |
| 56 | + end |
| 57 | + |
| 58 | + # Create default file paths if none were provided |
| 59 | + @options[:path_src] = here + "../src/" if @options[:path_src].nil? |
| 60 | + @options[:path_inc] = @options[:path_src] if @options[:path_inc].nil? |
| 61 | + @options[:path_tst] = here + "../test/" if @options[:path_tst].nil? |
| 62 | + @options[:path_src] += '/' unless (@options[:path_src][-1] == 47) |
| 63 | + @options[:path_inc] += '/' unless (@options[:path_inc][-1] == 47) |
| 64 | + @options[:path_tst] += '/' unless (@options[:path_tst][-1] == 47) |
| 65 | + |
| 66 | + #Built in patterns |
| 67 | + @patterns = { 'src' => {'' => { :inc => [] } }, |
| 68 | + 'dh' => {'Driver' => { :inc => ['%1$sHardware.h'] }, |
| 69 | + 'Hardware' => { :inc => [] } |
| 70 | + }, |
| 71 | + 'dih' => {'Driver' => { :inc => ['%1$sHardware.h', '%1$sInterrupt.h'] }, |
| 72 | + 'Interrupt'=> { :inc => ['%1$sHardware.h'] }, |
| 73 | + 'Hardware' => { :inc => [] } |
| 74 | + }, |
| 75 | + 'mch' => {'Model' => { :inc => [] }, |
| 76 | + 'Conductor'=> { :inc => ['%1$sModel.h', '%1$sHardware.h'] }, |
| 77 | + 'Hardware' => { :inc => [] } |
| 78 | + }, |
| 79 | + 'mvp' => {'Model' => { :inc => [] }, |
| 80 | + 'Presenter'=> { :inc => ['%1$sModel.h', '%1$sView.h'] }, |
| 81 | + 'View' => { :inc => [] } |
| 82 | + } |
| 83 | + } |
99 | 84 | end |
100 | | -end |
101 | | -raise "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 |
104 | | -if @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] |
113 | | -else |
114 | | - @boilerplates = {} |
115 | | -end |
116 | 85 |
|
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 |
129 | | -TRIAD = [ { :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] |
136 | | -raise "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. |
139 | | -files = [] |
140 | | -TRIAD.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 |
| 86 | + ############################ |
| 87 | + def self.default_options |
| 88 | + { |
| 89 | + :pattern => "src", |
| 90 | + :includes => |
| 91 | + { |
| 92 | + :src => [], |
| 93 | + :inc => [], |
| 94 | + :tst => [], |
| 95 | + }, |
| 96 | + :update_svn => false, |
| 97 | + :boilerplates => {}, |
| 98 | + :test_prefix => 'Test', |
152 | 99 | } |
153 | 100 | end |
154 | | -end |
155 | 101 |
|
156 | | -# destroy files if that was what was requested |
157 | | -if @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" |
| 102 | + ############################ |
| 103 | + def self.grab_config(config_file) |
| 104 | + options = self.default_options |
| 105 | + unless (config_file.nil? or config_file.empty?) |
| 106 | + require 'yaml' |
| 107 | + yaml_guts = YAML.load_file(config_file) |
| 108 | + options.merge!(yaml_guts[:unity] || yaml_guts[:cmock]) |
| 109 | + raise "No :unity or :cmock section found in #{config_file}" unless options |
| 110 | + end |
| 111 | + return(options) |
| 112 | + end |
| 113 | + |
| 114 | + ############################ |
| 115 | + def files_to_operate_on(module_name, pattern=nil) |
| 116 | + #create triad definition |
| 117 | + prefix = @options[:test_prefix] || 'Test' |
| 118 | + triad = [ { :ext => '.c', :path => @options[:path_src], :template => TEMPLATE_SRC, :inc => :src, :boilerplate => @options[:boilerplates][:src] }, |
| 119 | + { :ext => '.h', :path => @options[:path_inc], :template => TEMPLATE_INC, :inc => :inc, :boilerplate => @options[:boilerplates][:inc] }, |
| 120 | + { :ext => '.c', :path => @options[:path_tst]+prefix, :template => TEMPLATE_TST, :inc => :tst, :boilerplate => @options[:boilerplates][:tst] }, |
| 121 | + ] |
| 122 | + |
| 123 | + #prepare the pattern for use |
| 124 | + patterns = @patterns[(pattern || @options[:pattern] || 'src').downcase] |
| 125 | + raise "ERROR: The design pattern '#{pattern}' specified isn't one that I recognize!" if patterns.nil? |
| 126 | + |
| 127 | + # Assemble the path/names of the files we need to work with. |
| 128 | + files = [] |
| 129 | + triad.each do |triad| |
| 130 | + patterns.each_pair do |pattern_file, pattern_traits| |
| 131 | + puts @options.inspect |
| 132 | + puts pattern_traits.inspect |
| 133 | + puts module_name.inspect |
| 134 | + files << { |
| 135 | + :path => "#{triad[:path]}#{module_name}#{pattern_file}#{triad[:ext]}", |
| 136 | + :name => "#{module_name}#{pattern_file}", |
| 137 | + :template => triad[:template], |
| 138 | + :boilerplate => triad[:boilerplate], |
| 139 | + :includes => case(triad[:inc]) |
| 140 | + when :src then @options[:includes][:src] | pattern_traits[:inc].map{|f| f % [module_name]} |
| 141 | + when :inc then @options[:includes][:inc] |
| 142 | + when :tst then @options[:includes][:tst] | pattern_traits[:inc].map{|f| "Mock#{f}"% [module_name]} |
| 143 | + end |
| 144 | + } |
| 145 | + end |
| 146 | + end |
| 147 | + |
| 148 | + return files |
| 149 | + end |
| 150 | + |
| 151 | + ############################ |
| 152 | + def generate(module_name, pattern=nil) |
| 153 | + |
| 154 | + files = files_to_operate_on(module_name, pattern) |
| 155 | + |
| 156 | + #Abort if any module already exists |
| 157 | + files.each do |file| |
| 158 | + raise "ERROR: File #{file[:name]} already exists. Exiting." if File.exist?(file[:path]) |
| 159 | + end |
| 160 | + |
| 161 | + # Create Source Modules |
| 162 | + files.each_with_index do |file, i| |
| 163 | + File.open(file[:path], 'w') do |f| |
| 164 | + f.write(file[:boilerplate] % [file[:name]]) unless file[:boilerplate].nil? |
| 165 | + f.write(file[:template] % [ file[:name], |
| 166 | + file[:includes].map{|f| "#include \"#{f}\"\n"}.join, |
| 167 | + file[:name].upcase ] |
| 168 | + ) |
| 169 | + end |
| 170 | + if (@options[:update_svn]) |
| 171 | + `svn add \"#{file[:path]}\"` |
| 172 | + if $?.exitstatus == 0 |
| 173 | + puts "File #{file[:path]} created and added to source control" |
| 174 | + else |
| 175 | + puts "File #{file[:path]} created but FAILED adding to source control!" |
| 176 | + end |
164 | 177 | else |
165 | | - FileUtils.remove(file) |
166 | | - puts "File #{file} deleted" |
| 178 | + puts "File #{file[:path]} created" |
167 | 179 | end |
168 | | - else |
169 | | - puts "File #{file} does not exist so cannot be removed." |
170 | 180 | end |
| 181 | + puts 'Generate Complete' |
171 | 182 | end |
172 | | - puts "Destroy Complete" |
173 | | - exit |
174 | | -end |
175 | 183 |
|
176 | | -#Abort if any module already exists |
177 | | -files.each do |file| |
178 | | - raise "ERROR: File #{file[:name]} already exists. Exiting." if File.exist?(file[:path]) |
179 | | -end |
| 184 | + ############################ |
| 185 | + def destroy(module_name, pattern=nil) |
180 | 186 |
|
181 | | -# Create Source Modules |
182 | | -files.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 | | - ) |
| 187 | + files_to_operate_on(module_name, pattern).each do |filespec| |
| 188 | + file = filespec[:path] |
| 189 | + if File.exist?(file) |
| 190 | + if @options[:update_svn] |
| 191 | + `svn delete \"#{file}\" --force` |
| 192 | + puts "File #{file} deleted and removed from source control" |
| 193 | + else |
| 194 | + FileUtils.remove(file) |
| 195 | + puts "File #{file} deleted" |
| 196 | + end |
| 197 | + else |
| 198 | + puts "File #{file} does not exist so cannot be removed." |
| 199 | + end |
| 200 | + end |
| 201 | + puts "Destroy Complete" |
189 | 202 | 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!" |
| 203 | + |
| 204 | +end |
| 205 | + |
| 206 | +############################ |
| 207 | +#Handle As Command Line If Called That Way |
| 208 | +if ($0 == __FILE__) |
| 209 | + destroy = false |
| 210 | + options = { } |
| 211 | + module_name = nil |
| 212 | + |
| 213 | + # Parse the command line parameters. |
| 214 | + ARGV.each do |arg| |
| 215 | + case(arg) |
| 216 | + when /^-d/ then destroy = true |
| 217 | + when /^-u/ then options[:update_svn] = true |
| 218 | + when /^-p(\w+)/ then options[:pattern] = $1 |
| 219 | + when /^-s(.+)/ then options[:path_src] = $1 |
| 220 | + when /^-i(.+)/ then options[:path_inc] = $1 |
| 221 | + when /^-t(.+)/ then options[:path_tst] = $1 |
| 222 | + when /^-y(.+)/ then options = UnityModuleGenerator.grab_config($1) |
| 223 | + when /^(\w+)/ |
| 224 | + raise "ERROR: You can't have more than one Module name specified!" unless module_name.nil? |
| 225 | + module_name = arg |
| 226 | + when /^-(h|-help)/ |
| 227 | + ARGV = [] |
| 228 | + else |
| 229 | + raise "ERROR: Unknown option specified '#{arg}'" |
196 | 230 | end |
| 231 | + end |
| 232 | + |
| 233 | + if (!ARGV[0]) |
| 234 | + puts [ "\nGENERATE MODULE\n-------- ------", |
| 235 | + "\nUsage: ruby generate_module [options] module_name", |
| 236 | + " -i\"include\" sets the path to output headers to 'include' (DEFAULT ../src)", |
| 237 | + " -s\"../src\" sets the path to output source to '../src' (DEFAULT ../src)", |
| 238 | + " -t\"C:/test\" sets the path to output source to 'C:/test' (DEFAULT ../test)", |
| 239 | + " -p\"MCH\" sets the output pattern to MCH.", |
| 240 | + " dh - driver hardware.", |
| 241 | + " dih - driver interrupt hardware.", |
| 242 | + " mch - model conductor hardware.", |
| 243 | + " mvp - model view presenter.", |
| 244 | + " src - just a single source module. (DEFAULT)", |
| 245 | + " -d destroy module instead of creating it.", |
| 246 | + " -u update subversion too (requires subversion command line)", |
| 247 | + " -y\"my.yml\" selects a different yaml config file for module generation", |
| 248 | + "" ].join("\n") |
| 249 | + exit |
| 250 | + end |
| 251 | + |
| 252 | + raise "ERROR: You must have a Module name specified! (use option -h for help)" if module_name.nil? |
| 253 | + if (destroy) |
| 254 | + UnityModuleGenerator.new(options).destroy(module_name) |
197 | 255 | else |
198 | | - puts "File #{file[:path]} created" |
| 256 | + UnityModuleGenerator.new(options).generate(module_name) |
199 | 257 | end |
| 258 | + |
200 | 259 | end |
201 | 260 |
|
202 | | -puts 'Generate Complete' |
| 261 | + |
0 commit comments