longjump 0.1.0
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 +7 -0
- data/.gitignore +8 -0
- data/Gemfile +6 -0
- data/Gemfile.lock +24 -0
- data/README.md +73 -0
- data/Rakefile +10 -0
- data/bin/console +7 -0
- data/bin/longjump +5 -0
- data/bin/setup +8 -0
- data/lib/longjump/cli.rb +108 -0
- data/lib/longjump/exceptions.rb +7 -0
- data/lib/longjump/jumpers/base.rb +59 -0
- data/lib/longjump/jumpers.rb +19 -0
- data/lib/longjump/opener.rb +7 -0
- data/lib/longjump/subcommand.rb +26 -0
- data/lib/longjump/version.rb +3 -0
- data/lib/longjump.rb +4 -0
- data/longjump.gemspec +27 -0
- metadata +116 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 5977c83eabf6581782b219db4f1f12c2115cf0eafd48724b67dd2ac012c3481b
|
|
4
|
+
data.tar.gz: 0a06dfcd713e7eea93f8c0b4c56e059178e6034987190e95330eb73f7eb76046
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 8d222e04fc1a166e201604b9bc59ae275393fa27b40d83485b000ecdffcf5ac391b60a3b7b127dbcfc81d70e10247f89dfeb9113e464ef43871197a489d281bf
|
|
7
|
+
data.tar.gz: 0c2a12031e59607ccdbc3f1703addba45c15a4b0bc63e7aec6d2e01f1c8e1e50dc54138594e0d83914342989b1229fa5f9a98e8dbd65cf014bca77849b3fb0a5
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
PATH
|
|
2
|
+
remote: .
|
|
3
|
+
specs:
|
|
4
|
+
longjump (0.1.0)
|
|
5
|
+
|
|
6
|
+
GEM
|
|
7
|
+
remote: https://rubygems.org/
|
|
8
|
+
specs:
|
|
9
|
+
minitest (5.14.4)
|
|
10
|
+
mocha (1.13.0)
|
|
11
|
+
rake (10.5.0)
|
|
12
|
+
|
|
13
|
+
PLATFORMS
|
|
14
|
+
ruby
|
|
15
|
+
|
|
16
|
+
DEPENDENCIES
|
|
17
|
+
bundler (~> 1.17)
|
|
18
|
+
longjump!
|
|
19
|
+
minitest (~> 5.0)
|
|
20
|
+
mocha (~> 1.13)
|
|
21
|
+
rake (~> 10.0)
|
|
22
|
+
|
|
23
|
+
BUNDLED WITH
|
|
24
|
+
1.17.2
|
data/README.md
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# longjump
|
|
2
|
+
|
|
3
|
+
> an athletic event in which competitors jump as far as possible along the ground in one leap.
|
|
4
|
+
|
|
5
|
+
Longjump is an extensible command line tool that lets you jump into applications as far as possible with a single command.
|
|
6
|
+
|
|
7
|
+
## Installation
|
|
8
|
+
|
|
9
|
+
$ gem install longjump
|
|
10
|
+
|
|
11
|
+
## Usage
|
|
12
|
+
|
|
13
|
+
$ longjump
|
|
14
|
+
|
|
15
|
+
We recommend `alias lj=longjump` for convenience. But note that longjump will just tell you it has no available jumpers, unless you install a gem with a longjumper!
|
|
16
|
+
|
|
17
|
+
Gems that contain jumpers begin with `longjumper`.
|
|
18
|
+
|
|
19
|
+
## Why Longjump
|
|
20
|
+
|
|
21
|
+
Remembering URI's is hard - and is mostly solved with tools like browser bookmarks. But there are still situations where a command-line launcher that generates URI's and opens them is useful. A few examples:
|
|
22
|
+
|
|
23
|
+
* You want to jump to a URL in a development environment, but the environment's base URL changes regularly. You want something like `longjump myproject admin` to take you to the admin URL for your project, regardless of which environment you're currently using.
|
|
24
|
+
* You want to open some internal tool with context - maybe feeding a username into a URL structure with something like `longjump directory alex`.
|
|
25
|
+
* You just want a faster way of getting from your command line to a URL, even if it's static.
|
|
26
|
+
|
|
27
|
+
## Writing Your Longjumper
|
|
28
|
+
|
|
29
|
+
You'll need to create a gem. We recommend the convention `longjumper-$name` (e.g., [`longjumper-esv`](https://github.com/alexcwatt/longjumper-esv)) for a gem that has a single jumper or `longjumpers-$collection` for a gem that has a collection of jumpers (e.g., `longjumpers-shopify`). Technically longjump is just looking for gem names beginning with `longjumper`.
|
|
30
|
+
|
|
31
|
+
Then you will need to write one or more "Jumper" classes and put them under `Longjump::Jumpers`. We recommend extending `Base`. Here is an example:
|
|
32
|
+
|
|
33
|
+
```ruby
|
|
34
|
+
require "longjump/jumpers/base"
|
|
35
|
+
|
|
36
|
+
module Longjump
|
|
37
|
+
module Jumpers
|
|
38
|
+
class GitHubDocs < Base
|
|
39
|
+
require "cgi"
|
|
40
|
+
|
|
41
|
+
command :ghdocs
|
|
42
|
+
description "GitHub Docs"
|
|
43
|
+
default_uri "https://docs.github.com/"
|
|
44
|
+
|
|
45
|
+
subcommand :cli, regex: "c|cli", uri: "https://docs.github.com/en/github-cli"
|
|
46
|
+
subcommand :search
|
|
47
|
+
|
|
48
|
+
def search(*args)
|
|
49
|
+
query = args.join(" ")
|
|
50
|
+
"#{default_uri}en?query=#{query}"
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
If your `default_uri` is dynamic, you may want to define a method for it instead:
|
|
58
|
+
|
|
59
|
+
```ruby
|
|
60
|
+
def default_uri
|
|
61
|
+
SomeService.call
|
|
62
|
+
end
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
## Development
|
|
66
|
+
|
|
67
|
+
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
|
68
|
+
|
|
69
|
+
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
|
70
|
+
|
|
71
|
+
## Contributing
|
|
72
|
+
|
|
73
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/alexcwatt/longjump.
|
data/Rakefile
ADDED
data/bin/console
ADDED
data/bin/longjump
ADDED
data/bin/setup
ADDED
data/lib/longjump/cli.rb
ADDED
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
require_relative "opener"
|
|
2
|
+
|
|
3
|
+
module Longjump
|
|
4
|
+
class Cli
|
|
5
|
+
attr_reader :args
|
|
6
|
+
|
|
7
|
+
def initialize(args:, opener:, jumpers:)
|
|
8
|
+
@args = args
|
|
9
|
+
@opener = opener
|
|
10
|
+
@jumpers = jumpers
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def call
|
|
14
|
+
return help_message if args.empty? || subcommand == "help"
|
|
15
|
+
|
|
16
|
+
return jumper_help_message if jumper && subcommand_args[0] == "help"
|
|
17
|
+
|
|
18
|
+
return unless uri
|
|
19
|
+
|
|
20
|
+
opener.call(uri)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
private
|
|
24
|
+
|
|
25
|
+
def jumpers
|
|
26
|
+
@jumpers ||= Longjump::Jumpers
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def opener
|
|
30
|
+
@opener ||= Opener
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def jumper
|
|
34
|
+
@jumper ||= begin
|
|
35
|
+
jumpers.get(subcommand)
|
|
36
|
+
rescue Longjump::CouldNotFindJumper
|
|
37
|
+
puts "longjump could not find jumper: #{subcommand}"
|
|
38
|
+
nil
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def subcommand
|
|
43
|
+
args[0]
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def subcommand_args
|
|
47
|
+
args[1..]
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def subcommand_args_text
|
|
51
|
+
subcommand_args.join(' ')
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def help_message
|
|
55
|
+
puts "longjump opens websites and apps with context"
|
|
56
|
+
puts
|
|
57
|
+
if jumpers.all.any?
|
|
58
|
+
puts "Available jumpers:"
|
|
59
|
+
jumpers.all.each do |jumper|
|
|
60
|
+
puts " #{jumper.command}: #{jumper.description}"
|
|
61
|
+
end
|
|
62
|
+
else
|
|
63
|
+
puts "No jumpers available - try installing one"
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def jumper_help_message
|
|
68
|
+
puts "#{jumper.command}: #{jumper.description}"
|
|
69
|
+
|
|
70
|
+
jumper.subcommands.each do |subcommand|
|
|
71
|
+
puts "- #{subcommand.command}"
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def uri
|
|
76
|
+
@uri ||= (uri_from_jumper || uri_from_exact_match)
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def uri_from_jumper
|
|
80
|
+
return unless jumper
|
|
81
|
+
uri = jumper.call(subcommand_args)
|
|
82
|
+
puts "jumper: #{subcommand} did not recognize: #{subcommand_args_text}" unless uri
|
|
83
|
+
uri
|
|
84
|
+
rescue Longjump::MultipleSubcommandsMatched
|
|
85
|
+
puts "jumper: #{subcommand} found multiple matches: #{subcommand_args_text}"
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def uri_from_exact_match
|
|
89
|
+
jumpers_with_subcommands = jumpers.all.reject { |jumper| jumper.subcommands.empty? }
|
|
90
|
+
command_to_uri = jumpers_with_subcommands.each_with_object({}) do |jumper, hash|
|
|
91
|
+
uri = jumper.call(args)
|
|
92
|
+
hash[jumper.command] = uri if uri
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
if command_to_uri.size == 1
|
|
96
|
+
command, uri = command_to_uri.first
|
|
97
|
+
puts "#{args.join(" ")} matched jumper: #{command}"
|
|
98
|
+
return uri
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
class << self
|
|
103
|
+
def call(args:, opener: nil, jumpers: nil)
|
|
104
|
+
new(args: args, opener: opener, jumpers: jumpers).call
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
end
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
require "longjump/subcommand"
|
|
2
|
+
|
|
3
|
+
module Longjump
|
|
4
|
+
module Jumpers
|
|
5
|
+
class Base
|
|
6
|
+
def call(args)
|
|
7
|
+
return default_uri if args.empty?
|
|
8
|
+
|
|
9
|
+
matching_subcommands = self.class.subcommands.select { |subcommand| subcommand.match?(args[0]) }
|
|
10
|
+
|
|
11
|
+
return nil if matching_subcommands.empty?
|
|
12
|
+
|
|
13
|
+
raise MultipleSubcommandsMatched if matching_subcommands.size > 1
|
|
14
|
+
|
|
15
|
+
matching_subcommands.first.uri(context: self, args: args[1..])
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def default_uri
|
|
19
|
+
self.class.default_uri
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
class << self
|
|
23
|
+
def call(args)
|
|
24
|
+
new.call(args)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def command(name=nil)
|
|
28
|
+
@commands ||= []
|
|
29
|
+
if name
|
|
30
|
+
@commands << name
|
|
31
|
+
else
|
|
32
|
+
@commands[0]
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def commands
|
|
37
|
+
@commands ||= []
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def description(set_text=nil)
|
|
41
|
+
@description ||= set_text
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def default_uri(set_uri=nil)
|
|
45
|
+
@default_uri ||= set_uri
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def subcommand(command, regex: nil, uri: nil)
|
|
49
|
+
@subcommands ||= []
|
|
50
|
+
@subcommands << Subcommand.new(command, regex: regex, uri: uri)
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def subcommands
|
|
54
|
+
@subcommands ||= []
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
require_relative "jumpers/base"
|
|
2
|
+
|
|
3
|
+
longjumper_gems = Gem::Specification.map { |gem| gem.name.downcase }.filter { |name| name.start_with?("longjumper") }
|
|
4
|
+
longjumper_gems.each { |gem| require gem }
|
|
5
|
+
|
|
6
|
+
module Longjump
|
|
7
|
+
module Jumpers
|
|
8
|
+
def self.all
|
|
9
|
+
constants.sort.map { |c| const_get(c) }.select { |c| c < Base }
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def self.get(jumper_name)
|
|
13
|
+
jumpers = all.select { |jumper| jumper.commands.include?(jumper_name.to_sym) }
|
|
14
|
+
raise Longjump::CouldNotFindJumper if jumpers.empty?
|
|
15
|
+
|
|
16
|
+
jumpers.first
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
module Longjump
|
|
2
|
+
class Subcommand
|
|
3
|
+
attr_reader :command, :regex
|
|
4
|
+
|
|
5
|
+
def initialize(command, regex: nil, uri: nil)
|
|
6
|
+
@command = command
|
|
7
|
+
@regex = regex ? /^(#{regex})$/ : nil
|
|
8
|
+
@uri = uri
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def match?(name)
|
|
12
|
+
name == command.to_s || regex&.match?(name)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def uri(context:, args: nil)
|
|
16
|
+
return @uri if @uri
|
|
17
|
+
|
|
18
|
+
begin
|
|
19
|
+
return context.send(command, *args)
|
|
20
|
+
rescue ArgumentError
|
|
21
|
+
puts "Warning: #{command} does not support arguments"
|
|
22
|
+
return context.send(command)
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
data/lib/longjump.rb
ADDED
data/longjump.gemspec
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
|
|
2
|
+
lib = File.expand_path("../lib", __FILE__)
|
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
4
|
+
require "longjump/version"
|
|
5
|
+
|
|
6
|
+
Gem::Specification.new do |spec|
|
|
7
|
+
spec.name = "longjump"
|
|
8
|
+
spec.version = Longjump::VERSION
|
|
9
|
+
spec.authors = ["Alex Watt"]
|
|
10
|
+
spec.email = ["alex@alexcwatt.com"]
|
|
11
|
+
|
|
12
|
+
spec.summary = "Jump to URI's deep inside applications."
|
|
13
|
+
spec.homepage = "https://github.com/alexcwatt/longjump"
|
|
14
|
+
|
|
15
|
+
# Specify which files should be added to the gem when it is released.
|
|
16
|
+
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
|
17
|
+
spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
|
|
18
|
+
`git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
|
19
|
+
end
|
|
20
|
+
spec.executables = ["longjump"]
|
|
21
|
+
spec.require_paths = ["lib"]
|
|
22
|
+
|
|
23
|
+
spec.add_development_dependency "bundler", "~> 1.17"
|
|
24
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
|
25
|
+
spec.add_development_dependency "minitest", "~> 5.0"
|
|
26
|
+
spec.add_development_dependency "mocha", "~> 1.13"
|
|
27
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: longjump
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.1.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Alex Watt
|
|
8
|
+
autorequire:
|
|
9
|
+
bindir: bin
|
|
10
|
+
cert_chain: []
|
|
11
|
+
date: 2021-10-11 00:00:00.000000000 Z
|
|
12
|
+
dependencies:
|
|
13
|
+
- !ruby/object:Gem::Dependency
|
|
14
|
+
name: bundler
|
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
|
16
|
+
requirements:
|
|
17
|
+
- - "~>"
|
|
18
|
+
- !ruby/object:Gem::Version
|
|
19
|
+
version: '1.17'
|
|
20
|
+
type: :development
|
|
21
|
+
prerelease: false
|
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
23
|
+
requirements:
|
|
24
|
+
- - "~>"
|
|
25
|
+
- !ruby/object:Gem::Version
|
|
26
|
+
version: '1.17'
|
|
27
|
+
- !ruby/object:Gem::Dependency
|
|
28
|
+
name: rake
|
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
|
30
|
+
requirements:
|
|
31
|
+
- - "~>"
|
|
32
|
+
- !ruby/object:Gem::Version
|
|
33
|
+
version: '10.0'
|
|
34
|
+
type: :development
|
|
35
|
+
prerelease: false
|
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
37
|
+
requirements:
|
|
38
|
+
- - "~>"
|
|
39
|
+
- !ruby/object:Gem::Version
|
|
40
|
+
version: '10.0'
|
|
41
|
+
- !ruby/object:Gem::Dependency
|
|
42
|
+
name: minitest
|
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
|
44
|
+
requirements:
|
|
45
|
+
- - "~>"
|
|
46
|
+
- !ruby/object:Gem::Version
|
|
47
|
+
version: '5.0'
|
|
48
|
+
type: :development
|
|
49
|
+
prerelease: false
|
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
51
|
+
requirements:
|
|
52
|
+
- - "~>"
|
|
53
|
+
- !ruby/object:Gem::Version
|
|
54
|
+
version: '5.0'
|
|
55
|
+
- !ruby/object:Gem::Dependency
|
|
56
|
+
name: mocha
|
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
|
58
|
+
requirements:
|
|
59
|
+
- - "~>"
|
|
60
|
+
- !ruby/object:Gem::Version
|
|
61
|
+
version: '1.13'
|
|
62
|
+
type: :development
|
|
63
|
+
prerelease: false
|
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
65
|
+
requirements:
|
|
66
|
+
- - "~>"
|
|
67
|
+
- !ruby/object:Gem::Version
|
|
68
|
+
version: '1.13'
|
|
69
|
+
description:
|
|
70
|
+
email:
|
|
71
|
+
- alex@alexcwatt.com
|
|
72
|
+
executables:
|
|
73
|
+
- longjump
|
|
74
|
+
extensions: []
|
|
75
|
+
extra_rdoc_files: []
|
|
76
|
+
files:
|
|
77
|
+
- ".gitignore"
|
|
78
|
+
- Gemfile
|
|
79
|
+
- Gemfile.lock
|
|
80
|
+
- README.md
|
|
81
|
+
- Rakefile
|
|
82
|
+
- bin/console
|
|
83
|
+
- bin/longjump
|
|
84
|
+
- bin/setup
|
|
85
|
+
- lib/longjump.rb
|
|
86
|
+
- lib/longjump/cli.rb
|
|
87
|
+
- lib/longjump/exceptions.rb
|
|
88
|
+
- lib/longjump/jumpers.rb
|
|
89
|
+
- lib/longjump/jumpers/base.rb
|
|
90
|
+
- lib/longjump/opener.rb
|
|
91
|
+
- lib/longjump/subcommand.rb
|
|
92
|
+
- lib/longjump/version.rb
|
|
93
|
+
- longjump.gemspec
|
|
94
|
+
homepage: https://github.com/alexcwatt/longjump
|
|
95
|
+
licenses: []
|
|
96
|
+
metadata: {}
|
|
97
|
+
post_install_message:
|
|
98
|
+
rdoc_options: []
|
|
99
|
+
require_paths:
|
|
100
|
+
- lib
|
|
101
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
102
|
+
requirements:
|
|
103
|
+
- - ">="
|
|
104
|
+
- !ruby/object:Gem::Version
|
|
105
|
+
version: '0'
|
|
106
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
107
|
+
requirements:
|
|
108
|
+
- - ">="
|
|
109
|
+
- !ruby/object:Gem::Version
|
|
110
|
+
version: '0'
|
|
111
|
+
requirements: []
|
|
112
|
+
rubygems_version: 3.0.3
|
|
113
|
+
signing_key:
|
|
114
|
+
specification_version: 4
|
|
115
|
+
summary: Jump to URI's deep inside applications.
|
|
116
|
+
test_files: []
|