lib/bundlegem/cli/gem.rb in bundlegem-0.0.5 vs lib/bundlegem/cli/gem.rb in bundlegem-0.0.6

- old
+ new

@@ -14,12 +14,10 @@ validate_ext_name if options[:ext] end def run - # Bundler.ui.confirm "Creating gem '#{name}'..." - raise_project_with_that_name_already_exists! if File.exists?(target) underscored_name = name.tr('-', '_') namespaced_path = name.tr('-', '/') constant_name = name.split('_').map{|p| p[0..0].upcase + p[1..-1] unless p.empty?}.join @@ -43,79 +41,16 @@ :ext => options[:ext], :bin => options[:bin], :bundler_version => bundler_dependency_version } ensure_safe_gem_name(name, constant_array) - - # Hmmm... generate dynamically instead? Yes, overwritten below - templates = { - 'Gemfile.tt' => "Gemfile", - 'changelog.tt' => "changelog", - 'gitignore.tt' => ".gitignore", - 'lib/#{name}.rb.tt' => "lib/#{namespaced_path}.rb", - 'lib/#{name}/version.rb.tt' => "lib/#{namespaced_path}/version.rb", - '#{name}.gemspec.tt' => "#{name}.gemspec", - 'Rakefile.tt' => "Rakefile", - 'README.md.tt' => "README.md", - 'bin/console.tt' => "bin/console" - } - - - if ask_and_set(:coc, "Do you want to include a code of conduct in gems you generate?", - "Codes of conduct can increase contributions to your project by contributors who " \ - "prefer collaborative, safe spaces. You can read more about the code of conduct at " \ - "contributor-covenant.org. Having a code of conduct means agreeing to the responsibility " \ - "of enforcing it, so be sure that you are prepared to do that. For suggestions about " \ - "how to enforce codes of conduct, see bit.ly/coc-enforcement." - ) - templates.merge!("CODE_OF_CONDUCT.md.tt" => "CODE_OF_CONDUCT.md") - end - - if ask_and_set(:mit, "Do you want to license your code permissively under the MIT license?", - "This means that any other developer or company will be legally allowed to use your code " \ - "for free as long as they admit you created it. You can read more about the MIT license " \ - "at choosealicense.com/licenses/mit." - ) - config[:mit] = true - templates.merge!("LICENSE.txt.tt" => "LICENSE.txt") - end - - if test_framework = ask_and_set_test_framework - templates.merge!(".travis.yml.tt" => ".travis.yml") - - case test_framework - when 'rspec' - templates.merge!( - "rspec.tt" => ".rspec", - "spec/spec_helper.rb.tt" => "spec/spec_helper.rb", - 'spec/#{name}_spec.rb.tt' => "spec/#{namespaced_path}_spec.rb" - ) - when 'minitest' - templates.merge!( - "test/minitest_helper.rb.tt" => "test/minitest_helper.rb", - "test/test_newgem.rb.tt" => "test/test_#{namespaced_path}.rb" - ) - end - end - - templates.merge!("exe/newgem.tt" => "exe/#{name}") if options[:bin] - - if options[:ext] - templates.merge!( - "ext/newgem/extconf.rb.tt" => "ext/#{name}/extconf.rb", - "ext/newgem/newgem.h.tt" => "ext/#{name}/#{underscored_name}.h", - "ext/newgem/newgem.c.tt" => "ext/#{name}/#{underscored_name}.c" - ) - end - - puts "Creating new project folder\n\n" - template_src = match_template_src template_directories = dynamically_generate_template_directories - templates = dynamically_generate_templates || templates + templates = dynamically_generate_templates(config) + puts "Creating new project folder '#{name}'\n\n" create_template_directories(template_directories, target) templates.each do |src, dst| template("#{template_src}/#{src}", target.join(dst), config) end @@ -137,140 +72,123 @@ private def dynamically_generate_template_directories # return nil if options["template"].nil? - template_src = get_template_src + template_src = TemplateManager.get_template_src(options) template_dirs = {} Dir.glob("#{template_src}/**/*").each do |f| next unless File.directory? f base_path = f[template_src.length+1..-1] template_dirs.merge!(base_path => base_path.gsub('#{name}', "#{name}") ) end template_dirs end - def dynamically_generate_templates - return nil if options["template"].nil? + # This function should be eliminated over time so that other methods conform to the + # new algo for generating templates automatically. + # Really, this function generates a template_src to template_dst naming + # structure so that a later method can copy all the template files from the + # source and rename them properly + def generate_templates_for_built_in_gems(config) + # Hmmm... generate dynamically instead? Yes, overwritten below + templates = { + 'Gemfile.tt' => "Gemfile", + 'changelog.tt' => "changelog", + 'gitignore.tt' => ".gitignore", + 'lib/#{name}.rb.tt' => "lib/#{config[:namespaced_path]}.rb", + 'lib/#{name}/version.rb.tt' => "lib/#{config[:namespaced_path]}/version.rb", + '#{name}.gemspec.tt' => "#{config[:name]}.gemspec", + 'Rakefile.tt' => "Rakefile", + 'README.md.tt' => "README.md", + 'bin/console.tt' => "bin/console" + } - template_src = get_template_src - - templates = {} - Dir.glob("#{template_src}/**/*.tt").each do |f| - base_path = f[template_src.length+1..-1] - templates.merge!(base_path => base_path.gsub(/\.tt$/, "").gsub('#{name}', "#{name}") ) - end - - raise_no_files_in_template_error! if templates.empty? + prompt_coc!(templates) + prompt_mit!(templates, config) + prompt_test_framework!(templates, config) + templates.merge!("exe/newgem.tt" => "exe/#{config[:name]}") if config[:bin] + + if config[:ext] + templates.merge!( + "ext/newgem/extconf.rb.tt" => "ext/#{config[:name]}/extconf.rb", + "ext/newgem/newgem.h.tt" => "ext/#{config[:name]}/#{config[:underscored_name]}.h", + "ext/newgem/newgem.c.tt" => "ext/#{config[:name]}/#{config[:underscored_name]}.c" + ) + end templates end + # Figures out the translation between all the .tt file to their + # destination names + def dynamically_generate_templates(config) + #if options["template"].nil? # if it's doing some of the built in template + # return generate_templates_for_built_in_gems(config) + #else + template_src = TemplateManager.get_template_src(options) + + templates = {} + Dir.glob("#{template_src}/**/{*,.*}.tt").each do |f| + base_path = f[template_src.length+1..-1] + templates.merge!(base_path => base_path.gsub(/\.tt$/, "").gsub('#{name}', "#{name}") ) + end + + raise_no_files_in_template_error! if templates.empty? + + return templates + #end + end + def create_template_directories(template_directories, target) template_directories.each do |k,v| d = "#{target}/#{v}" puts " mkdir #{d} ..." FileUtils.mkdir_p(d) end end + # returns the full path of the template source def match_template_src - template_src = get_template_src + template_src = TemplateManager.get_template_src(options) - if template_exists_within_repo?(template_src) or File.exists?(template_src) + if File.exists?(template_src) return template_src # 'newgem' refers to the built in template that comes with the gem else raise_template_not_found! # else message the user that the template could not be found end end - - def get_template_src - template_name = options["template"].nil? ? "newgem" : options["template"] - - if template_exists_within_repo?(template_name) - gem_template_location = get_internal_template_location - else - gem_template_location = File.expand_path("~/.bundlegem/gem_templates") - end - template_src = "#{gem_template_location}/#{template_name}" - end - def template_exists_within_repo?(template_name) - file_in_source?(template_name) - end - def get_internal_template_location - File.expand_path("#{File.dirname(__FILE__)}/../templates") - end - def resolve_name(name) Pathname.pwd.join(name).basename.to_s end - def ask_and_set(key, header, message) - choice = options[key] # || Bundler.settings["gem.#{key}"] - - if choice.nil? - Bundler.ui.confirm header - choice = (Bundler.ui.ask("#{message} y/(n):") =~ /y|yes/) - Bundler.settings.set_global("gem.#{key}", choice) - end - - choice - end - + def validate_ext_name return unless gem_name.index('-') Bundler.ui.error "You have specified a gem name which does not conform to the \n" \ "naming guidelines for C extensions. For more information, \n" \ "see the 'Extension Naming' section at the following URL:\n" \ "http://guides.rubygems.org/gems-with-extensions/\n" exit 1 end - def ask_and_set_test_framework - test_framework = options[:test] || Bundler.settings["gem.test"] - - if test_framework.nil? - Bundler.ui.confirm "Do you want to generate tests with your gem?" - result = Bundler.ui.ask "Type 'rspec' or 'minitest' to generate those test files now and " \ - "in the future. rspec/minitest/(none):" - if result =~ /rspec|minitest/ - test_framework = result - else - test_framework = false - end - end - - if Bundler.settings["gem.test"].nil? - Bundler.settings.set_global("gem.test", test_framework) - end - - test_framework - end - + def bundler_dependency_version v = Gem::Version.new(Bundler::VERSION) req = v.segments[0..1] req << 'a' if v.prerelease? req.join(".") end - def ensure_safe_gem_name name, constant_array - if name =~ /^\d/ - Bundler.ui.error "Invalid gem name #{name} Please give a name which does not start with numbers." - exit 1 - elsif Object.const_defined?(constant_array.first) - Bundler.ui.error "Invalid gem name #{name} constant #{constant_array.join("::")} is already in use. Please choose another gem name." - exit 1 - end - end + # # EDIT: Reworked from Thor to not rely on Thor (or do so much unneeded stuff) # # Gets an ERB template at the relative source, executes it and makes a copy # at the relative destination. If the destination is not given it's assumed @@ -289,34 +207,22 @@ # def template(source, *args, &block) config = args.last.is_a?(Hash) ? args.pop : {} destination = args.first || source.sub(/#{TEMPLATE_EXTNAME}$/, "") - source = File.expand_path(find_in_source_paths(source.to_s)) + source = File.expand_path(TemplateManager.find_in_source_paths(source.to_s)) context = instance_eval("binding") make_file(destination, config) do content = ERB.new(::File.binread(source), nil, "-", "@output_buffer").result(context) content = block.call(content) if block content end end - # - # EDIT: Reworked from Thor to not rely on Thor (or do so much unneeded stuff) - # - def find_in_source_paths(target) - src_in_source_path = "#{File.dirname(__FILE__)}/../templates/#{target}" - return src_in_source_path if File.exists?(src_in_source_path) - target # failed, hopefully full path to a user specified gem template file - end - def file_in_source?(target) - src_in_source_path = "#{File.dirname(__FILE__)}/../templates/#{target}" - File.exists?(src_in_source_path) - end # # EDIT: Reworked from Thor to not rely on Thor (or do so much unneeded stuff) # def make_file(destination, config, &block) @@ -346,9 +252,105 @@ def raise_template_not_found! err_missing_template = "Could not find template folder '#{options["template"]}' in `~/.bundle/gem_templates/`. Please check to make sure your desired template exists." puts err_missing_template Bundler.ui.error err_missing_template exit 1 + end + + + ############# STUFF THAT SHOULD BE REMOVED DOWN THE ROAD + + # This asks the user if they want to setup rspec or test... + # It's not class based, it's additive based... Plus bundlegem does this already + def ask_and_set_test_framework + test_framework = options[:test] || Bundler.settings["gem.test"] + + if test_framework.nil? + Bundler.ui.confirm "Do you want to generate tests with your gem?" + result = Bundler.ui.ask "Type 'rspec' or 'minitest' to generate those test files now and " \ + "in the future. rspec/minitest/(none):" + if result =~ /rspec|minitest/ + test_framework = result + else + test_framework = false + end + end + + if Bundler.settings["gem.test"].nil? + Bundler.settings.set_global("gem.test", test_framework) + end + + test_framework + end + + def ask_and_set(key, header, message) + choice = options[key] # || Bundler.settings["gem.#{key}"] + + if choice.nil? + Bundler.ui.confirm header + choice = (Bundler.ui.ask("#{message} y/(n):") =~ /y|yes/) + Bundler.settings.set_global("gem.#{key}", choice) + end + + choice + end + + def prompt_coc!(templates) + if ask_and_set(:coc, "Do you want to include a code of conduct in gems you generate?", + "Codes of conduct can increase contributions to your project by contributors who " \ + "prefer collaborative, safe spaces. You can read more about the code of conduct at " \ + "contributor-covenant.org. Having a code of conduct means agreeing to the responsibility " \ + "of enforcing it, so be sure that you are prepared to do that. For suggestions about " \ + "how to enforce codes of conduct, see bit.ly/coc-enforcement." + ) + templates.merge!("CODE_OF_CONDUCT.md.tt" => "CODE_OF_CONDUCT.md") + end + end + + def prompt_mit!(templates, config) + if ask_and_set(:mit, "Do you want to license your code permissively under the MIT license?", + "This means that any other developer or company will be legally allowed to use your code " \ + "for free as long as they admit you created it. You can read more about the MIT license " \ + "at choosealicense.com/licenses/mit." + ) + config[:mit] = true + templates.merge!("LICENSE.txt.tt" => "LICENSE.txt") + end + end + + def prompt_test_framework!(templates, config) + namespaced_path = config[:namespaced_path] + if test_framework = ask_and_set_test_framework + templates.merge!(".travis.yml.tt" => ".travis.yml") + + case test_framework + when 'rspec' + templates.merge!( + "rspec.tt" => ".rspec", + "spec/spec_helper.rb.tt" => "spec/spec_helper.rb", + 'spec/#{name}_spec.rb.tt' => "spec/#{namespaced_path}_spec.rb" + ) + when 'minitest' + templates.merge!( + "test/minitest_helper.rb.tt" => "test/minitest_helper.rb", + "test/test_newgem.rb.tt" => "test/test_#{namespaced_path}.rb" + ) + end + end + end + + # This checks to see that the gem_name is a valid ruby gem name and will 'work' + # and won't overlap with a bundlegem constant apparently... + # + # TODO: This should be defined within the template itself in some way possibly, may have security implications + def ensure_safe_gem_name(name, constant_array) + if name =~ /^\d/ + Bundler.ui.error "Invalid gem name #{name} Please give a name which does not start with numbers." + exit 1 + elsif Object.const_defined?(constant_array.first) + Bundler.ui.error "Invalid gem name #{name} constant #{constant_array.join("::")} is already in use. Please choose another gem name." + exit 1 + end end end end