generate_module.rb 9.1 KB
Newer Older
M
Mark VanderVoord 已提交
1 2 3 4
# ==========================================
#   Unity Project - A Test Framework for C
#   Copyright (c) 2007 Mike Karlesky, Mark VanderVoord, Greg Williams
#   [Released under MIT License. Please refer to license.txt for details]
5
# ==========================================
M
Mark VanderVoord 已提交
6 7 8 9 10 11 12 13 14

# This script creates all the files with start code necessary for a new module.
# A simple module only requires a source file, header file, and test file.
# Triad modules require a source, header, and test file for each triad type (like model, conductor, and hardware).

require 'rubygems'
require 'fileutils'

#TEMPLATE_TST
15
TEMPLATE_TST ||= %q[#include "unity.h"
M
Mark VanderVoord 已提交
16 17 18 19 20 21 22 23 24 25 26 27
%2$s#include "%1$s.h"

void setUp(void)
{
}

void tearDown(void)
{
}

void test_%1$s_NeedToImplement(void)
{
28
    TEST_IGNORE_MESSAGE("Need to Implement %1$s");
M
Mark VanderVoord 已提交
29 30 31 32
}
]

#TEMPLATE_SRC
33
TEMPLATE_SRC ||= %q[%2$s#include "%1$s.h"
M
Mark VanderVoord 已提交
34 35 36
]

#TEMPLATE_INC
37
TEMPLATE_INC ||= %q[#ifndef _%3$s_H
M
Mark VanderVoord 已提交
38 39 40 41 42
#define _%3$s_H%2$s

#endif // _%3$s_H
]

43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83
class UnityModuleGenerator

  ############################
  def initialize(options=nil)

    here = File.expand_path(File.dirname(__FILE__)) + '/'

    @options = UnityModuleGenerator.default_options
    case(options)
      when NilClass then @options
      when String   then @options.merge!(UnityModuleGenerator.grab_config(options))
      when Hash     then @options.merge!(options)
      else          raise "If you specify arguments, it should be a filename or a hash of options"
    end

    # Create default file paths if none were provided
    @options[:path_src] = here + "../src/"    if @options[:path_src].nil?
    @options[:path_inc] = @options[:path_src] if @options[:path_inc].nil?
    @options[:path_tst] = here + "../test/"   if @options[:path_tst].nil?
    @options[:path_src] += '/'                unless (@options[:path_src][-1] == 47)
    @options[:path_inc] += '/'                unless (@options[:path_inc][-1] == 47)
    @options[:path_tst] += '/'                unless (@options[:path_tst][-1] == 47)

    #Built in patterns
    @patterns = { 'src' => {''         => { :inc => [] } },
                  'dh'  => {'Driver'   => { :inc => ['%1$sHardware.h'] },
                            'Hardware' => { :inc => [] }
                           },
                  'dih' => {'Driver'   => { :inc => ['%1$sHardware.h', '%1$sInterrupt.h'] },
                            'Interrupt'=> { :inc => ['%1$sHardware.h'] },
                            'Hardware' => { :inc => [] }
                           },
                  'mch' => {'Model'    => { :inc => [] },
                            'Conductor'=> { :inc => ['%1$sModel.h', '%1$sHardware.h'] },
                            'Hardware' => { :inc => [] }
                           },
                  'mvp' => {'Model'    => { :inc => [] },
                            'Presenter'=> { :inc => ['%1$sModel.h', '%1$sView.h'] },
                            'View'     => { :inc => [] }
                           }
                }
M
Mark VanderVoord 已提交
84 85
  end

86 87 88 89 90 91 92 93 94 95 96 97 98
  ############################
  def self.default_options
    {
      :pattern         => "src",
      :includes        =>
      {
          :src         => [],
          :inc         => [],
          :tst         => [],
      },
      :update_svn      => false,
      :boilerplates    => {},
      :test_prefix     => 'Test',
99
      :mock_prefix     => 'Mock',
M
Mark VanderVoord 已提交
100 101 102
    }
  end

103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139
  ############################
  def self.grab_config(config_file)
    options = self.default_options
    unless (config_file.nil? or config_file.empty?)
      require 'yaml'
      yaml_guts = YAML.load_file(config_file)
      options.merge!(yaml_guts[:unity] || yaml_guts[:cmock])
      raise "No :unity or :cmock section found in #{config_file}" unless options
    end
    return(options)
  end

  ############################
  def files_to_operate_on(module_name, pattern=nil)
    #create triad definition
    prefix = @options[:test_prefix] || 'Test'
    triad = [ { :ext => '.c', :path => @options[:path_src],        :template => TEMPLATE_SRC, :inc => :src, :boilerplate => @options[:boilerplates][:src] },
              { :ext => '.h', :path => @options[:path_inc],        :template => TEMPLATE_INC, :inc => :inc, :boilerplate => @options[:boilerplates][:inc] },
              { :ext => '.c', :path => @options[:path_tst]+prefix, :template => TEMPLATE_TST, :inc => :tst, :boilerplate => @options[:boilerplates][:tst] },
            ]

    #prepare the pattern for use
    patterns = @patterns[(pattern || @options[:pattern] || 'src').downcase]
    raise "ERROR: The design pattern '#{pattern}' specified isn't one that I recognize!" if patterns.nil?

    # Assemble the path/names of the files we need to work with.
    files = []
    triad.each do |triad|
      patterns.each_pair do |pattern_file, pattern_traits|
        files << {
          :path => "#{triad[:path]}#{module_name}#{pattern_file}#{triad[:ext]}",
          :name => "#{module_name}#{pattern_file}",
          :template => triad[:template],
          :boilerplate => triad[:boilerplate],
          :includes => case(triad[:inc])
                         when :src then @options[:includes][:src] | pattern_traits[:inc].map{|f| f % [module_name]}
                         when :inc then @options[:includes][:inc]
140
                         when :tst then @options[:includes][:tst] | pattern_traits[:inc].map{|f| "#{@options[:mock_prefix]}#{f}"% [module_name]}
141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174
                       end
        }
      end
    end

    return files
  end

  ############################
  def generate(module_name, pattern=nil)

    files = files_to_operate_on(module_name, pattern)

    #Abort if any module already exists
    files.each do |file|
      raise "ERROR: File #{file[:name]} already exists. Exiting." if File.exist?(file[:path])
    end

    # Create Source Modules
    files.each_with_index do |file, i|
      File.open(file[:path], 'w') do |f|
        f.write(file[:boilerplate] % [file[:name]]) unless file[:boilerplate].nil?
        f.write(file[:template] % [ file[:name],
                                    file[:includes].map{|f| "#include \"#{f}\"\n"}.join,
                                    file[:name].upcase ]
               )
      end
      if (@options[:update_svn])
        `svn add \"#{file[:path]}\"`
        if $?.exitstatus == 0
          puts "File #{file[:path]} created and added to source control"
        else
          puts "File #{file[:path]} created but FAILED adding to source control!"
        end
M
Mark VanderVoord 已提交
175
      else
176
        puts "File #{file[:path]} created"
M
Mark VanderVoord 已提交
177 178
      end
    end
179
    puts 'Generate Complete'
M
Mark VanderVoord 已提交
180 181
  end

182 183
  ############################
  def destroy(module_name, pattern=nil)
M
Mark VanderVoord 已提交
184

185 186 187 188 189 190 191 192 193 194 195 196 197 198 199
    files_to_operate_on(module_name, pattern).each do |filespec|
      file = filespec[:path]
      if File.exist?(file)
        if @options[:update_svn]
          `svn delete \"#{file}\" --force`
          puts "File #{file} deleted and removed from source control"
        else
          FileUtils.remove(file)
          puts "File #{file} deleted"
        end
      else
        puts "File #{file} does not exist so cannot be removed."
      end
    end
    puts "Destroy Complete"
M
Mark VanderVoord 已提交
200
  end
201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227

end

############################
#Handle As Command Line If Called That Way
if ($0 == __FILE__)
  destroy = false
  options = { }
  module_name = nil

  # Parse the command line parameters.
  ARGV.each do |arg|
    case(arg)
      when /^-d/      then destroy = true
      when /^-u/      then options[:update_svn] = true
      when /^-p(\w+)/ then options[:pattern] = $1
      when /^-s(.+)/  then options[:path_src] = $1
      when /^-i(.+)/  then options[:path_inc] = $1
      when /^-t(.+)/  then options[:path_tst] = $1
      when /^-y(.+)/  then options = UnityModuleGenerator.grab_config($1)
      when /^(\w+)/
        raise "ERROR: You can't have more than one Module name specified!" unless module_name.nil?
        module_name = arg
      when /^-(h|-help)/
        ARGV = []
      else
        raise "ERROR: Unknown option specified '#{arg}'"
M
Mark VanderVoord 已提交
228
    end
229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252
  end

  if (!ARGV[0])
    puts [ "\nGENERATE MODULE\n-------- ------",
           "\nUsage: ruby generate_module [options] module_name",
           "  -i\"include\" sets the path to output headers to 'include' (DEFAULT ../src)",
           "  -s\"../src\"  sets the path to output source to '../src'   (DEFAULT ../src)",
           "  -t\"C:/test\" sets the path to output source to 'C:/test'  (DEFAULT ../test)",
           "  -p\"MCH\"     sets the output pattern to MCH.",
           "              dh  - driver hardware.",
           "              dih - driver interrupt hardware.",
           "              mch - model conductor hardware.",
           "              mvp - model view presenter.",
           "              src - just a single source module. (DEFAULT)",
           "  -d          destroy module instead of creating it.",
           "  -u          update subversion too (requires subversion command line)",
           "  -y\"my.yml\"  selects a different yaml config file for module generation",
           "" ].join("\n")
    exit
  end

  raise "ERROR: You must have a Module name specified! (use option -h for help)" if module_name.nil?
  if (destroy)
    UnityModuleGenerator.new(options).destroy(module_name)
M
Mark VanderVoord 已提交
253
  else
254
    UnityModuleGenerator.new(options).generate(module_name)
M
Mark VanderVoord 已提交
255
  end
256

M
Mark VanderVoord 已提交
257 258
end

259