lib/bundler/cli/gem.rb in bundler-1.7.15 vs lib/bundler/cli/gem.rb in bundler-1.8.0.pre

- old
+ new

@@ -1,78 +1,166 @@ +require 'pathname' + module Bundler class CLI::Gem - attr_reader :options, :gem_name, :thor + attr_reader :options, :gem_name, :thor, :name, :target + def initialize(options, gem_name, thor) @options = options - @gem_name = gem_name + @gem_name = resolve_name(gem_name) @thor = thor + + @name = @gem_name + @target = Pathname.pwd.join(gem_name) + + validate_ext_name if options[:ext] end def run - if options[:ext] && 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 + Bundler.ui.confirm "Creating gem '#{name}'..." - name = gem_name.chomp("/") # remove trailing slash if present underscored_name = name.tr('-', '_') namespaced_path = name.tr('-', '/') - target = File.join(Dir.pwd, name) constant_name = name.split('_').map{|p| p[0..0].upcase + p[1..-1] }.join constant_name = constant_name.split('-').map{|q| q[0..0].upcase + q[1..-1] }.join('::') if constant_name =~ /-/ constant_array = constant_name.split('::') git_user_name = `git config user.name`.chomp git_user_email = `git config user.email`.chomp + opts = { :name => name, :underscored_name => underscored_name, :namespaced_path => namespaced_path, :makefile_path => "#{underscored_name}/#{underscored_name}", :constant_name => constant_name, :constant_array => constant_array, :author => git_user_name.empty? ? "TODO: Write your name" : git_user_name, :email => git_user_email.empty? ? "TODO: Write your email address" : git_user_email, :test => options[:test], - :ext => options[:ext] + :ext => options[:ext], + :bin => options[:bin] } - gemspec_dest = File.join(target, "#{name}.gemspec") - thor.template(File.join("newgem/Gemfile.tt"), File.join(target, "Gemfile"), opts) - thor.template(File.join("newgem/Rakefile.tt"), File.join(target, "Rakefile"), opts) - thor.template(File.join("newgem/LICENSE.txt.tt"), File.join(target, "LICENSE.txt"), opts) - thor.template(File.join("newgem/README.md.tt"), File.join(target, "README.md"), opts) - thor.template(File.join("newgem/gitignore.tt"), File.join(target, ".gitignore"), opts) - thor.template(File.join("newgem/newgem.gemspec.tt"), gemspec_dest, opts) - thor.template(File.join("newgem/lib/newgem.rb.tt"), File.join(target, "lib/#{namespaced_path}.rb"), opts) - thor.template(File.join("newgem/lib/newgem/version.rb.tt"), File.join(target, "lib/#{namespaced_path}/version.rb"), opts) - if options[:bin] - thor.template(File.join("newgem/bin/newgem.tt"), File.join(target, 'bin', name), opts) + + templates = { + "Gemfile.tt" => "Gemfile", + "gitignore.tt" => ".gitignore", + "lib/newgem.rb.tt" => "lib/#{namespaced_path}.rb", + "lib/newgem/version.rb.tt" => "lib/#{namespaced_path}/version.rb", + "newgem.gemspec.tt" => "#{name}.gemspec", + "Rakefile.tt" => "Rakefile", + "README.md.tt" => "README.md", + "bin/console.tt" => "bin/console", + "bin/setup.tt" => "bin/setup" + } + + 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 - case options[:test] - when 'rspec' - thor.template(File.join("newgem/rspec.tt"), File.join(target, ".rspec"), opts) - thor.template(File.join("newgem/spec/spec_helper.rb.tt"), File.join(target, "spec/spec_helper.rb"), opts) - thor.template(File.join("newgem/spec/newgem_spec.rb.tt"), File.join(target, "spec/#{namespaced_path}_spec.rb"), opts) - when 'minitest' - thor.template(File.join("newgem/test/minitest_helper.rb.tt"), File.join(target, "test/minitest_helper.rb"), opts) - thor.template(File.join("newgem/test/test_newgem.rb.tt"), File.join(target, "test/test_#{namespaced_path}.rb"), opts) + + 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." + ) + templates.merge!("LICENSE.txt.tt" => "LICENSE.txt") end - if options[:test] - thor.template(File.join("newgem/.travis.yml.tt"), File.join(target, ".travis.yml"), opts) + + 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/newgem_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] - thor.template(File.join("newgem/ext/newgem/extconf.rb.tt"), File.join(target, "ext/#{name}/extconf.rb"), opts) - thor.template(File.join("newgem/ext/newgem/newgem.h.tt"), File.join(target, "ext/#{name}/#{underscored_name}.h"), opts) - thor.template(File.join("newgem/ext/newgem/newgem.c.tt"), File.join(target, "ext/#{name}/#{underscored_name}.c"), opts) + 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 + + templates.each do |src, dst| + thor.template("newgem/#{src}", target.join(dst), opts) + end + Bundler.ui.info "Initializing git repo in #{target}" Dir.chdir(target) { `git init`; `git add .` } if options[:edit] - thor.run("#{options["edit"]} \"#{gemspec_dest}\"") # Open gemspec in editor + # Open gemspec in editor + thor.run("#{options["edit"]} \"#{target.join("#{name}.gemspec")}\"") end + end + + private + + def resolve_name(name) + Pathname.pwd.join(name).basename.to_s + end + + def ask_and_set(key, header, message) + result = options[key] + if !Bundler.settings.all.include?("gem.#{key}") + if result.nil? + Bundler.ui.confirm header + result = Bundler.ui.ask("#{message} y/(n):") == "y" + end + + Bundler.settings.set_global("gem.#{key}", result) + end + + result || Bundler.settings["gem.#{key}"] + 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 + + return if test_framework == "false" + test_framework end end end