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 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
@@ -0,0 +1,8 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /_yardoc/
4
+ /coverage/
5
+ /doc/
6
+ /pkg/
7
+ /spec/reports/
8
+ /tmp/
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ source "https://rubygems.org"
2
+
3
+ git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
4
+
5
+ # Specify your gem's dependencies in longjump.gemspec
6
+ gemspec
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
@@ -0,0 +1,10 @@
1
+ require "bundler/gem_tasks"
2
+ require "rake/testtask"
3
+
4
+ Rake::TestTask.new(:test) do |t|
5
+ t.libs << "test"
6
+ t.libs << "lib"
7
+ t.test_files = FileList["test/**/*_test.rb"]
8
+ end
9
+
10
+ task :default => :test
data/bin/console ADDED
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "longjump"
5
+
6
+ require "irb"
7
+ IRB.start(__FILE__)
data/bin/longjump ADDED
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "longjump"
4
+
5
+ Longjump::Cli.call(args: ARGV)
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -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,7 @@
1
+ module Longjump
2
+ class Error < StandardError; end
3
+
4
+ class CouldNotFindJumper < Error; end
5
+
6
+ class MultipleSubcommandsMatched < Error; end
7
+ 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,7 @@
1
+ module Longjump
2
+ class Opener
3
+ def self.call(uri)
4
+ exec("open #{uri}")
5
+ end
6
+ end
7
+ 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
@@ -0,0 +1,3 @@
1
+ module Longjump
2
+ VERSION = "0.1.0"
3
+ end
data/lib/longjump.rb ADDED
@@ -0,0 +1,4 @@
1
+ require "longjump/cli"
2
+ require "longjump/exceptions"
3
+ require "longjump/jumpers"
4
+ require "longjump/version"
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: []