fustigit 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 551f4ad9ed874b976c1de00a5289a1352d946d64
4
+ data.tar.gz: 1954e7f60f0c10a423f8a2cc0f16d0a09ba4d085
5
+ SHA512:
6
+ metadata.gz: fe5bbee3df3198f8d9d93f7cc88a27c1609c2ee952e25a65884016f07b5e44b15a3d98cbe0c88e773b9f8806dc6788172708eb59be85d8bacee65b353ed88d61
7
+ data.tar.gz: 50f90dbc0e42dca704a759d2ab68feb3a2ab326a380b4733ff848099b45a2e1fbd4e54850c587eb72befbabe34a633b37b908ff41cfdb7ac3d08675767896861
data/CHANGELOG.md ADDED
@@ -0,0 +1,15 @@
1
+ ## Changelog
2
+ All notable changes to this project will be documented in this file.
3
+ This project attempts to adhere to [Semantic Versioning](http://semver.org/).
4
+ This changelog attempts to adhere to [Keep a CHANGELOG](http://keepachangelog.com/).
5
+
6
+ ## [0.1.1] - 09 May 2016
7
+ ### Added
8
+ - Fix Ruby 2.2.0 and 2.3.0 support
9
+ - Add JRuby to Travis checks
10
+ - Make Rubocop print cop names by default
11
+
12
+ ## [0.1.0] - 09 May 2016
13
+ ### Added
14
+ - Initial release
15
+ - README covers usage, licensing, and rationale
data/LICENSE ADDED
@@ -0,0 +1,13 @@
1
+ Copyright 2014-2016 Ryan McKern
2
+
3
+ Licensed under the Apache License, Version 2.0 (the "License");
4
+ you may not use this file except in compliance with the License.
5
+ You may obtain a copy of the License at
6
+
7
+ http://www.apache.org/licenses/LICENSE-2.0
8
+
9
+ Unless required by applicable law or agreed to in writing, software
10
+ distributed under the License is distributed on an "AS IS" BASIS,
11
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ See the License for the specific language governing permissions and
13
+ limitations under the License.
data/README.md ADDED
@@ -0,0 +1,86 @@
1
+ ## Fustigit: gorram Git addresses
2
+
3
+ <dl>
4
+ <dt>Fustigate &#8212; (verb) fus&middot;ti&middot;gate </dd>
5
+ <dd>To beat with a club; cudgel.</dd>
6
+ <dd>To criticize harshly.</dd>
7
+ </dl>
8
+
9
+ [![Build Status](https://travis-ci.org/mckern/fustigit.svg?branch=master)](https://travis-ci.org/mckern/fustigit)
10
+
11
+ ### TL;DR
12
+
13
+ Fustigit will let you "parse" SCP-like address triplets using Ruby's baked-in [URI library](http://ruby-doc.org/stdlib-2.3.1/libdoc/uri/rdoc/index.html) (... and just a *moderate* amount of monkey-patching) and turn them into probably-valid URI objects.
14
+
15
+ ### What's a Triplet?
16
+
17
+ <a href="https://www.debuggex.com/r/UF-0ESZoWXFewi8q"><img src="https://www.debuggex.com/i/UF-0ESZoWXFewi8q.png"></a>
18
+
19
+ A triplet is a format for specifying a remote resource, much like a URI. It looks like this:
20
+
21
+ # The username is optional but the hostname and pathname are not
22
+ <username>@<hostname>:<pathname>
23
+
24
+ Triplets predate the [original ratification of the URI RFC](https://tools.ietf.org/html/rfc2396), and are *tricksy* to parse if you're playing by URI rules since they don't define a protocol and they use a colon to separate the hostname from the pathname. `scp` and `git` are the two most common tools that still use triplets.
25
+
26
+ ### Why would I need to parse triplets?
27
+
28
+ The answer is usually "[Git](https://git-scm.com)" (but sometimes it's `scp`). Git supports a conveniently inconvenient number of formats for expressing where a remote repository is located and/or what protocol should be used to connect to it. Some of them are perfectly valid URIs. Some of them are not. It's the ones that are not that may be a problem.
29
+
30
+ ```yaml
31
+ ---
32
+ # These won't parse and they're both SUPER common
33
+ - example.com:path/to/repo.git
34
+ - git@example.com:user/project.git
35
+
36
+ # But these will parse, which is great since they're also SUPER common
37
+ - https://example.com/user/project.git
38
+ - http://example.com/user/project.git
39
+ ```
40
+
41
+ Enter Fustigit.
42
+
43
+ ### How (do I use this)?
44
+
45
+ <s>Carelessly</s> Without a care in the world!
46
+
47
+ ```ruby
48
+ >> URI.parse "git@github.com:mckern/fustigit.git"
49
+ URI::InvalidURIError: bad URI(is not URI?): git@github.com:mckern/fustigit.git [/some/path/for/ruby/lib/ruby/2.1.0/uri/common.rb:176:in `split']
50
+ >> require 'fustigit'
51
+ => true
52
+ >> uri = URI.parse "git@github.com:mckern/fustigit.git"
53
+ => #<URI::SSH:0x007f8459131f98 URL:git@github.com:mckern/fustigit.git>
54
+ >> uri.host
55
+ => "github.com"
56
+ >> uri.user
57
+ => "git"
58
+ >> uri.path
59
+ => "mckern/fustigit.git"
60
+ >> uri.to_s
61
+ => "git@github.com:mckern/fustigit.git"
62
+ >>
63
+ ```
64
+
65
+ ### How (does it work)?
66
+
67
+ Careful use of `Module#prepend` and `Module#extend` in `URI` and `URI::Parser`, judicious use of regular expressions, and by defining a few new `URI` subclasses: `URI::Git`, `URI::SSH`, `URI::SCP`, and `URI::RSYNC`. Some of these classes then have the `Triplet` module mixed in, which helps smooth over the conversion between a valid RFC-compliant URI and an address triplet.
68
+
69
+ ### What if I'm using `Addressable::URI` instead of `::URI`?
70
+
71
+ Take a look at Martin Emde's [Gitable](https://github.com/martinemde/gitable), which extends `Addressable::URI` with additional support for Git addresses.
72
+
73
+ ### Support & contribution?
74
+
75
+ In the spirit of Jordan Sissel (a hero to admins and operations people everywhere), if fustigit is not helping you parse weird Git addresses, then there is a bug in fustigit. Please open an issue or submit a pull request if something doesn't work.
76
+
77
+ ### License
78
+
79
+ Fustigate is licensed under the Apache License, Version 2.0.
80
+
81
+ > "When in doubt, use brute force."
82
+ > &#8213; <cite>Ken Thompson</cite>
83
+
84
+ ### Maintainer
85
+
86
+ Ryan McKern &lt;ryan@orangefort.com&gt;
data/Rakefile ADDED
@@ -0,0 +1,30 @@
1
+ require "bundler/setup"
2
+ require "bundler/gem_tasks"
3
+ require "rake/testtask"
4
+ require "rubocop/rake_task"
5
+
6
+ desc "Test fustigit"
7
+ namespace :test do
8
+ Rake::TestTask.new(:spec) do |test|
9
+ test.libs << "spec"
10
+ test.pattern = "spec/**/*_spec.rb"
11
+ test.verbose = false
12
+ test.warning = false
13
+ end
14
+
15
+ desc "Test fustigit and calculate test coverage"
16
+ task :coverage do
17
+ ENV["COVERAGE"] = "true"
18
+ Rake::Task["test:spec"].invoke
19
+ end
20
+ end
21
+
22
+ desc "Run RuboCop"
23
+ RuboCop::RakeTask.new(:rubocop) do |task|
24
+ task.patterns = ["lib/**/*.rb"]
25
+ end
26
+
27
+ desc "Run all spec tests and linters"
28
+ task check: %w(test:spec rubocop)
29
+
30
+ task default: :check
data/lib/fustigit.rb ADDED
@@ -0,0 +1,5 @@
1
+ require "uri/triplets"
2
+ require "uri/git"
3
+ require "uri/scp"
4
+ require "uri/ssh"
5
+ require "uri/rsync"
@@ -0,0 +1,5 @@
1
+ module Fustigit
2
+ module Version
3
+ VERSION = "0.1.1".freeze
4
+ end
5
+ end
data/lib/uri/git.rb ADDED
@@ -0,0 +1,17 @@
1
+ require "uri/generic"
2
+
3
+ module URI
4
+ class Git < Generic
5
+ include Triplets
6
+
7
+ DEFAULT_PORT = 9418
8
+ USE_REGISTRY = false
9
+
10
+ COMPONENT = [
11
+ :scheme,
12
+ :userinfo,
13
+ :host, :port, :path
14
+ ].freeze
15
+ end
16
+ @@schemes["GIT"] = Git
17
+ end
data/lib/uri/rsync.rb ADDED
@@ -0,0 +1,8 @@
1
+ require "uri/generic"
2
+
3
+ module URI
4
+ class RSYNC < Generic
5
+ DEFAULT_PORT = 873
6
+ end
7
+ @@schemes["RSYNC"] = RSYNC
8
+ end
data/lib/uri/scp.rb ADDED
@@ -0,0 +1,16 @@
1
+ require "uri/generic"
2
+
3
+ module URI
4
+ class SCP < Generic
5
+ include Triplets
6
+
7
+ DEFAULT_PORT = 22
8
+
9
+ COMPONENT = [
10
+ :scheme,
11
+ :userinfo,
12
+ :host, :port, :path
13
+ ].freeze
14
+ end
15
+ @@schemes["SCP"] = SCP
16
+ end
data/lib/uri/ssh.rb ADDED
@@ -0,0 +1,16 @@
1
+ require "uri/generic"
2
+
3
+ module URI
4
+ class SSH < Generic
5
+ include Triplets
6
+
7
+ DEFAULT_PORT = 22
8
+
9
+ COMPONENT = [
10
+ :scheme,
11
+ :userinfo,
12
+ :host, :port, :path
13
+ ].freeze
14
+ end
15
+ @@schemes["SSH"] = SSH
16
+ end
@@ -0,0 +1,123 @@
1
+ require "uri"
2
+
3
+ # Triplets is a mix-in for subclasses of URI::Generic, which
4
+ # allows URI to use SCP-style Triplet URLs in a somewhat more
5
+ # meaningful way.
6
+ module Triplets
7
+ attr_accessor :scheme, :user, :host, :path
8
+
9
+ # @return [String] a string representation of the URI components
10
+ # as an SCP-style Triplet
11
+ def triplet
12
+ str = ""
13
+ str << "#{user}@" if user && !user.empty?
14
+ str << "#{host}:#{path}".squeeze("/")
15
+ end
16
+ private :triplet
17
+
18
+ # @return [String] a string representation of the URI components
19
+ # as a valid RFC compliant URI
20
+ # rubocop:disable Metrics/AbcSize
21
+ def rfc_uri
22
+ str = ""
23
+ str << "#{scheme}://" if scheme
24
+ str << "#{user}@" if user
25
+ if port && port != self.class::DEFAULT_PORT
26
+ host_info [host, port].join(":")
27
+ str << [host_info, path].join("/").squeeze("/")
28
+ else
29
+ str << [host, path].join("/").squeeze("/")
30
+ end
31
+ end
32
+ private :rfc_uri
33
+
34
+ # if self.path is a relative path, assume that this was parsed
35
+ # as a triplet and return a Triplet. Otherwise, assume that
36
+ # this is a valid URI and print an RFC compliant URI. This
37
+ # may not be the most robust method of determining if a
38
+ # triplet should be used, but everything starts someplace.
39
+ def to_s
40
+ return triplet if relative?
41
+ rfc_uri
42
+ end
43
+ end
44
+
45
+ # A SCP Triplet is *not* a canonical URI. It doesn't follow any RFCs that
46
+ # I've been able to find, and it's difficult to reason about if you
47
+ # try to force it into a URI::Generic as-is. TripletInterruptus provides
48
+ # helper methods that preserve the upstream behavior of URI::Generic
49
+ # but extend it just enough that it doesn't choke on SCP Triplets if
50
+ # they're passed.
51
+ module TripletInterruptus
52
+ # Determine if a string can be teased apart into URI-like components
53
+ TRIPLET = %r{\A(?:(?<userinfo>.+)[@]+)?(?<host>[\w.]+):(?<path>.*)\z}
54
+
55
+ # Determine if a string is prefixed with a URI scheme like http:// or ssh://
56
+ SCHEME = %r{\A(?:(?<scheme>[a-z]+)://)}
57
+
58
+ def parse(uri)
59
+ return build_triplet(uri) if triplet?(uri)
60
+ super(uri)
61
+ end
62
+
63
+ def triplet?(address)
64
+ address.match(TRIPLET) && !address.match(SCHEME)
65
+ end
66
+
67
+ def build_triplet(address)
68
+ values = parse_triplet(address)
69
+ return nil unless values
70
+ URI.scheme_list[URI.default_triplet_type].build(values)
71
+ end
72
+ private :build_triplet
73
+
74
+ def parse_triplet(address)
75
+ parts = address.match(TRIPLET)
76
+ return nil unless parts
77
+ Hash[parts.names.map(&:to_sym).zip(parts.captures)]
78
+ end
79
+ private :parse_triplet
80
+ end
81
+
82
+ module TripletHandling
83
+ TRIPLET_CLASSES = %w(Git SCP SSH).freeze
84
+
85
+ def self.included(base)
86
+ base.extend(TripletHandling)
87
+ end
88
+
89
+ def default_triplet_type
90
+ @default_triplet_type ||= "SSH"
91
+ end
92
+
93
+ def default_triplet_type=(value)
94
+ unless TRIPLET_CLASSES.include?(value)
95
+ raise ArgumentError, "'#{value}' is not one of: #{TRIPLET_CLASSES.join(', ')}"
96
+ end
97
+ @default_triplet_type = value
98
+ end
99
+ end
100
+
101
+ # Reopen URI and include TripletHandling (which will then
102
+ # extend URI to add triplet-specific class methods).
103
+ module URI
104
+ include TripletHandling
105
+ end
106
+
107
+ module URI
108
+ # Reopen URI::Parser and prepend TripletInterruptus. This
109
+ # allows us to hook into URI::Parser.parse and attempt to
110
+ # parse a triplet before URI::Parser can reject it. Otherwise
111
+ # fall through to the original URI::Parser.parse method.
112
+ #
113
+ if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new("2.2.0")
114
+ # rubocop:disable Style/ClassAndModuleCamelCase
115
+ class RFC3986_Parser
116
+ prepend TripletInterruptus
117
+ end
118
+ else
119
+ class Parser
120
+ prepend TripletInterruptus
121
+ end
122
+ end
123
+ end
@@ -0,0 +1,22 @@
1
+ require "bundler/setup"
2
+ require "minitest/spec"
3
+ require "minitest/autorun"
4
+ require "minitest/reporters"
5
+ require "simplecov"
6
+ require "json"
7
+
8
+ Minitest::Reporters.use! Minitest::Reporters::DefaultReporter.new
9
+
10
+ if ENV["COVERAGE"]
11
+ SimpleCov.start do
12
+ # exclude common Bundler locations
13
+ %w(.bundle vendor).each { |dir| add_filter dir }
14
+ # exclude test code
15
+ add_filter "spec"
16
+ end
17
+ end
18
+
19
+ def fixture(path)
20
+ path = File.join(File.dirname(__FILE__), "fixtures", path)
21
+ File.read(path)
22
+ end
@@ -0,0 +1,31 @@
1
+ require "spec_helper"
2
+ require "fustigit"
3
+
4
+ describe URI do
5
+ @git_repos = JSON.load(fixture("formats.json"))
6
+ @git_repos["URIs"].each do |protocol, repos|
7
+ repos.each do |repo|
8
+ describe %(#parse takes given URI "#{repo}") do
9
+ it "returns URI::#{protocol}" do
10
+ URI.parse(repo).is_a?(URI.const_get(protocol)).must_equal true
11
+ end
12
+ end
13
+ end
14
+ end
15
+
16
+ @git_repos["paths"].each do |repo|
17
+ describe %(#parse takes path "#{repo}") do
18
+ it "returns URI::Generic" do
19
+ URI.parse(repo).is_a?(URI::Generic).must_equal true
20
+ end
21
+ end
22
+ end
23
+
24
+ @git_repos["triplets"].each do |repo|
25
+ describe %(#parse takes triplet "#{repo}") do
26
+ it "returns URI::#{URI.default_triplet_type}" do
27
+ URI.parse(repo).is_a?(URI.const_get(URI.default_triplet_type)).must_equal true
28
+ end
29
+ end
30
+ end
31
+ end
metadata ADDED
@@ -0,0 +1,60 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: fustigit
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.1
5
+ platform: ruby
6
+ authors:
7
+ - Ryan McKern
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2016-05-09 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: '"Parse" SCP-like address triplets with the Standard Ruby URI Library.'
14
+ email: ryan@orangefort.com
15
+ executables: []
16
+ extensions: []
17
+ extra_rdoc_files: []
18
+ files:
19
+ - CHANGELOG.md
20
+ - LICENSE
21
+ - README.md
22
+ - Rakefile
23
+ - lib/fustigit.rb
24
+ - lib/fustigit/version.rb
25
+ - lib/uri/git.rb
26
+ - lib/uri/rsync.rb
27
+ - lib/uri/scp.rb
28
+ - lib/uri/ssh.rb
29
+ - lib/uri/triplets.rb
30
+ - spec/spec_helper.rb
31
+ - spec/uri/fustigit_spec.rb
32
+ homepage: http://github.com/mckern/fustigit
33
+ licenses:
34
+ - Apache-2.0
35
+ metadata: {}
36
+ post_install_message:
37
+ rdoc_options: []
38
+ require_paths:
39
+ - lib
40
+ required_ruby_version: !ruby/object:Gem::Requirement
41
+ requirements:
42
+ - - ">="
43
+ - !ruby/object:Gem::Version
44
+ version: 2.1.0
45
+ required_rubygems_version: !ruby/object:Gem::Requirement
46
+ requirements:
47
+ - - ">="
48
+ - !ruby/object:Gem::Version
49
+ version: '0'
50
+ requirements: []
51
+ rubyforge_project:
52
+ rubygems_version: 2.6.4
53
+ signing_key:
54
+ specification_version: 3
55
+ summary: Use URI to "parse" SCP-like triplets
56
+ test_files:
57
+ - Rakefile
58
+ - spec/spec_helper.rb
59
+ - spec/uri/fustigit_spec.rb
60
+ has_rdoc: