Repository: ruby-git/ruby-git (Ruby)

Issue:
Git.clone requires 2 arguments instead of 1
### Subject of the issue

In the example usage of `Git.clone`, the [documentation](https://rubydoc.info/gems/git/Git.clone) says that it can be called with only the URL of the repo, like so:

```ruby
git = Git.clone('https://github.com/ruby-git/ruby-git.git')
```

However, the method itself requires both the URL and the name of the directory. You can't just use the default

### Your environment
* Git 2.34.0
* ruby-git 1.8.1
* Ruby 2.7.4

### Steps to reproduce

```ruby
git = Git.clone('https://github.com/ruby-git/ruby-git.git')
```

### Expected behaviour
The clone will work and use `ruby-git` as the default name of the clone directory

### Actual behaviour
The method fails with `wrong number of arguments (given 1, expected 2..3)`


Discussion:
also if you do `g = Git.clone(GIT_URL, branch: 'master')` it will clone into a folder named `{/branch=>"master"}` resulting in

```
/Users/kain/.rvm/gems/ruby-3.0.0/gems/git-1.10.2/lib/git/base.rb:613:in `expand_path': no implicit conversion of Hash into String (TypeError)
	from /Users/kain/.rvm/gems/ruby-3.0.0/gems/git-1.10.2/lib/git/base.rb:613:in `normalize_working_directory'
	from /Users/kain/.rvm/gems/ruby-3.0.0/gems/git-1.10.2/lib/git/base.rb:592:in `normalize_paths'
	from /Users/kain/.rvm/gems/ruby-3.0.0/gems/git-1.10.2/lib/git/base.rb:22:in `clone'
	from /Users/kain/.rvm/gems/ruby-3.0.0/gems/git-1.10.2/lib/git.rb:161:in `clone'
	from main.rb:69:in `<main>'
```
Take a look at #578 which makes the `directory` parameter to `Git.clone` optional which means that you can:

```ruby
# assume I am starting in the `/Users/me/Projects` directory
g = Git.clone('https://github.com/ruby-git/ruby-git')
g.dir.to_s #=> "/Users/me/Projects/ruby-git"
```

Since the definition of Git.clone is:

```ruby
def self.clone(repository_url, directory = nil, options = {})
```

In order to pass a an option, you will need to pass `nil` for directory.  So this won't have the desired effect:

```ruby
g = Git.clone(GIT_URL, branch: 'master')
```

Instead, you will need to do this:

```ruby
g = Git.clone(GIT_URL, nil, branch: 'master')
```

I think we will need to transition to using keyword parameters (or move the `directory` parameter to an option) in order to make `Git.clone(url, branch: 'master')` work like you want.



Patch:
diff --git a/README.md b/README.md
index ab63d2fa..bb0b81d6 100644
--- a/README.md
+++ b/README.md
@@ -204,13 +204,23 @@ g = Git.init
   { :repository => '/opt/git/proj.git',
       :index => '/tmp/index'} )
 
-g = Git.clone(URI, NAME, :path => '/tmp/checkout')
+# Clone from a git url
+git_url = 'https://github.com/ruby-git/ruby-git.git'
+# Clone into the ruby-git directory
+g = Git.clone(git_url)
+
+# Clone into /tmp/clone/ruby-git-clean
+name = 'ruby-git-clean'
+path = '/tmp/clone'
+g = Git.clone(git_url, name, :path => path)
+g.dir #=> /tmp/clone/ruby-git-clean
+
 g.config('user.name', 'Scott Chacon')
 g.config('user.email', 'email@email.com')
 
 # Clone can take an optional logger
 logger = Logger.new
-g = Git.clone(URI, NAME, :log => logger)
+g = Git.clone(git_url, NAME, :log => logger)
 
 g.add                                   # git add -- "."
 g.add(:all=>true)                       # git add --all -- "."
diff --git a/lib/git.rb b/lib/git.rb
index addb0d59..1da03ce5 100644
--- a/lib/git.rb
+++ b/lib/git.rb
@@ -107,11 +107,23 @@ def self.bare(git_dir, options = {})
   # @see https://git-scm.com/docs/git-clone git clone
   # @see https://git-scm.com/docs/git-clone#_git_urls_a_id_urls_a GIT URLs
   #
-  # @param [URI, Pathname] repository The (possibly remote) repository to clone
+  # @param repository_url [URI, Pathname] The (possibly remote) repository url to clone
   #   from. See [GIT URLS](https://git-scm.com/docs/git-clone#_git_urls_a_id_urls_a)
   #   for more information.
   #
-  # @param [Pathname] name The directory to clone into.
+  # @param directory [Pathname, nil] The directory to clone into
+  #
+  #   If `directory` is a relative directory it is relative to the `path` option if
+  #   given. If `path` is not given, `directory` is relative to the current working
+  #   directory.
+  #
+  #   If `nil`, `directory` will be set to the basename of the last component of
+  #   the path from the `repository_url`. For example, for the URL:
+  #   `https://github.com/org/repo.git`, `directory` will be set to `repo`.
+  #
+  #   If the last component of the path is `.git`, the next-to-last component of
+  #   the path is used. For example, for the URL `/Users/me/foo/.git`, `directory`
+  #   will be set to `foo`.
   #
   # @param [Hash] options The options for this command (see list of valid
   #   options below)
@@ -158,8 +170,10 @@ def self.bare(git_dir, options = {})
   # @return [Git::Base] an object that can execute git commands in the context
   #   of the cloned local working copy or cloned repository.
   #
-  def self.clone(repository, name, options = {})
-    Base.clone(repository, name, options)
+  def self.clone(repository_url, directory = nil, options = {})
+    clone_to_options = options.select { |key, _value| %i[bare mirror].include?(key) }
+    directory ||= Git::URL.clone_to(repository_url, **clone_to_options)
+    Base.clone(repository_url, directory, options)
   end
 
   # Export the current HEAD (or a branch, if <tt>options[:branch]</tt>
diff --git a/lib/git/base.rb b/lib/git/base.rb
index 815fc36a..541cc554 100644
--- a/lib/git/base.rb
+++ b/lib/git/base.rb
@@ -17,10 +17,10 @@ def self.bare(git_dir, options = {})
     end
 
     # (see Git.clone)
-    def self.clone(repository, name, options = {})
-      new_options = Git::Lib.new(nil, options[:log]).clone(repository, name, options)
+    def self.clone(repository_url, directory, options = {})
+      new_options = Git::Lib.new(nil, options[:log]).clone(repository_url, directory, options)
       normalize_paths(new_options, bare: options[:bare] || options[:mirror])
-      self.new(new_options)
+      new(new_options)
     end
 
     # Returns (and initialize if needed) a Git::Config instance
diff --git a/lib/git/lib.rb b/lib/git/lib.rb
index 0fdae6f8..5bf2e455 100644
--- a/lib/git/lib.rb
+++ b/lib/git/lib.rb
@@ -95,9 +95,9 @@ def init(opts={})
     #
     # @return [Hash] the options to pass to {Git::Base.new}
     #
-    def clone(repository, name, opts = {})
+    def clone(repository_url, directory, opts = {})
       @path = opts[:path] || '.'
-      clone_dir = opts[:path] ? File.join(@path, name) : name
+      clone_dir = opts[:path] ? File.join(@path, directory) : directory
 
       arr_opts = []
       arr_opts << '--bare' if opts[:bare]
@@ -106,11 +106,11 @@ def clone(repository, name, opts = {})
       arr_opts << '--config' << opts[:config] if opts[:config]
       arr_opts << '--origin' << opts[:remote] || opts[:origin] if opts[:remote] || opts[:origin]
       arr_opts << '--recursive' if opts[:recursive]
-      arr_opts << "--mirror" if opts[:mirror]
+      arr_opts << '--mirror' if opts[:mirror]
 
       arr_opts << '--'
 
-      arr_opts << repository
+      arr_opts << repository_url
       arr_opts << clone_dir
 
       command('clone', arr_opts)


Test patch:
diff --git a/tests/units/test_git_clone.rb b/tests/units/test_git_clone.rb
new file mode 100644
index 00000000..8a5d1806
--- /dev/null
+++ b/tests/units/test_git_clone.rb
@@ -0,0 +1,36 @@
+# frozen_string_literal: true
+
+require 'test/unit'
+require_relative '../test_helper'
+
+# Tests for Git.clone
+class TestGitClone < Test::Unit::TestCase
+  def setup_repo
+    Git.init('repository.git', bare: true)
+    git = Git.clone('repository.git', 'temp')
+    File.write('temp/test.txt', 'test')
+    git.add('test.txt')
+    git.commit('Initial commit')
+  end
+
+  def test_git_clone_with_name
+    in_temp_dir do |path|
+      setup_repo
+      clone_dir = 'clone_to_this_dir'
+      git = Git.clone('repository.git', clone_dir)
+      assert(Dir.exist?(clone_dir))
+      expected_dir = File.realpath(clone_dir)
+      assert_equal(expected_dir, git.dir.to_s)
+    end
+  end
+
+  def test_git_clone_with_no_name
+    in_temp_dir do |path|
+      setup_repo
+      git = Git.clone('repository.git')
+      assert(Dir.exist?('repository'))
+      expected_dir = File.realpath('repository')
+      assert_equal(expected_dir, git.dir.to_s)
+    end
+  end
+end