fustigit 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
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: