runfile 0.12.0 → 1.0.0.rc1
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 +4 -4
- data/README.md +108 -37
- data/bin/runn +5 -0
- data/examples/default-action/runfile +9 -0
- data/examples/default-action-2/runfile +11 -0
- data/examples/default-action-2/server.runfile +6 -0
- data/examples/different-name/runfile.rb +8 -0
- data/examples/example/runfile +10 -0
- data/examples/example-multiline/runfile +16 -0
- data/examples/execute/runfile +14 -0
- data/examples/execute/server.runfile +11 -0
- data/examples/full/runfile +24 -0
- data/examples/import/more_tasks/spec.runfile +7 -0
- data/examples/import/runfile +10 -0
- data/examples/import/tasks/server.runfile +13 -0
- data/examples/minimal/runfile +4 -0
- data/examples/multiple-runfiles/runfile +11 -0
- data/examples/multiple-runfiles/server.runfile +13 -0
- data/examples/named-only/deploy.runfile +7 -0
- data/examples/named-only/server.runfile +11 -0
- data/examples/naval-fate/runfile +47 -0
- data/examples/shortcut/runfile +31 -0
- data/lib/runfile/action.rb +40 -14
- data/lib/runfile/concerns/dsl.rb +132 -0
- data/lib/runfile/concerns/inspectable.rb +13 -0
- data/lib/runfile/concerns/renderable.rb +16 -0
- data/lib/runfile/entrypoint.rb +50 -0
- data/lib/runfile/exceptions.rb +13 -0
- data/lib/runfile/gem_finder.rb +29 -0
- data/lib/runfile/initiator.rb +87 -0
- data/lib/runfile/meta.rb +65 -0
- data/lib/runfile/runner.rb +10 -173
- data/lib/runfile/templates/runfile +13 -0
- data/lib/runfile/userfile.rb +111 -0
- data/lib/runfile/version.rb +2 -2
- data/lib/runfile/views/initiator.gtx +28 -0
- data/lib/runfile/views/userfile.gtx +93 -0
- data/lib/runfile.rb +13 -10
- metadata +98 -24
- data/bin/run +0 -10
- data/bin/run! +0 -16
- data/lib/runfile/compatibility.rb +0 -84
- data/lib/runfile/docopt_helper.rb +0 -128
- data/lib/runfile/dsl.rb +0 -90
- data/lib/runfile/refinements.rb +0 -22
- data/lib/runfile/runfile_helper.rb +0 -165
- data/lib/runfile/settings.rb +0 -34
- data/lib/runfile/setup.rb +0 -19
- data/lib/runfile/templates/Runfile +0 -16
- data/lib/runfile/terminal.rb +0 -32
@@ -0,0 +1,132 @@
|
|
1
|
+
module Runfile
|
2
|
+
module DSL
|
3
|
+
# Commands
|
4
|
+
|
5
|
+
attr_reader :default_action
|
6
|
+
|
7
|
+
def action(name = nil, shortcut = nil, &block)
|
8
|
+
current_action.block = block
|
9
|
+
current_action.name = name
|
10
|
+
current_action.shortcut = shortcut if shortcut
|
11
|
+
current_action.prefix = action_prefix if action_prefix
|
12
|
+
|
13
|
+
# if default_action && name
|
14
|
+
# raise SyntaxError, <<~ERROR
|
15
|
+
# Cannot define action nub`#{name}` since a default action was already defined
|
16
|
+
# ERROR
|
17
|
+
# end
|
18
|
+
|
19
|
+
actions[name || :default] = current_action
|
20
|
+
@default_action = current_action unless name
|
21
|
+
@current_action = nil
|
22
|
+
end
|
23
|
+
|
24
|
+
def env_var(name, help)
|
25
|
+
env_vars[name] = help
|
26
|
+
end
|
27
|
+
|
28
|
+
def example(text)
|
29
|
+
examples.push text
|
30
|
+
end
|
31
|
+
|
32
|
+
def help(message)
|
33
|
+
current_action.help = message
|
34
|
+
end
|
35
|
+
|
36
|
+
def import(pathspec)
|
37
|
+
imports.push pathspec
|
38
|
+
end
|
39
|
+
|
40
|
+
def import_gem(gem_name, runfile_path, context = nil)
|
41
|
+
if context && !context.is_a?(Hash)
|
42
|
+
raise SyntaxError, <<~ERROR
|
43
|
+
The third argument to nub`import_gem` must be a hash
|
44
|
+
got rb`#{context.inspect}`
|
45
|
+
ERROR
|
46
|
+
end
|
47
|
+
|
48
|
+
path = GemFinder.find gem_name, runfile_path
|
49
|
+
imports.push path
|
50
|
+
contexts[runfile_path] = context if context
|
51
|
+
end
|
52
|
+
|
53
|
+
def option(name, help)
|
54
|
+
options[name] = help
|
55
|
+
end
|
56
|
+
|
57
|
+
def param(name, help)
|
58
|
+
params[name] = help
|
59
|
+
end
|
60
|
+
|
61
|
+
def shortcut(name)
|
62
|
+
current_action.shortcut = name
|
63
|
+
end
|
64
|
+
|
65
|
+
def summary(text = nil)
|
66
|
+
return @summary unless text
|
67
|
+
|
68
|
+
@summary = text
|
69
|
+
end
|
70
|
+
|
71
|
+
def title(text = nil)
|
72
|
+
return @title unless text
|
73
|
+
|
74
|
+
@title = text
|
75
|
+
end
|
76
|
+
|
77
|
+
def usage(message)
|
78
|
+
message = "#{action_prefix} #{message}" if action_prefix
|
79
|
+
current_action.usages.push message
|
80
|
+
end
|
81
|
+
|
82
|
+
def version(text = nil)
|
83
|
+
return @version unless text
|
84
|
+
|
85
|
+
@version = text
|
86
|
+
end
|
87
|
+
|
88
|
+
def execute(command_line)
|
89
|
+
run Shellwords.split(command_line)
|
90
|
+
end
|
91
|
+
|
92
|
+
# Evaluation Artifacts
|
93
|
+
|
94
|
+
def action_prefix
|
95
|
+
nil
|
96
|
+
end
|
97
|
+
|
98
|
+
def contexts
|
99
|
+
@contexts ||= {}
|
100
|
+
end
|
101
|
+
|
102
|
+
def actions
|
103
|
+
@actions ||= {}
|
104
|
+
end
|
105
|
+
|
106
|
+
def params
|
107
|
+
@params ||= {}
|
108
|
+
end
|
109
|
+
|
110
|
+
def env_vars
|
111
|
+
@env_vars ||= {}
|
112
|
+
end
|
113
|
+
|
114
|
+
def examples
|
115
|
+
@examples ||= []
|
116
|
+
end
|
117
|
+
|
118
|
+
def options
|
119
|
+
@options ||= {}
|
120
|
+
end
|
121
|
+
|
122
|
+
def imports
|
123
|
+
@imports ||= []
|
124
|
+
end
|
125
|
+
|
126
|
+
private
|
127
|
+
|
128
|
+
def current_action
|
129
|
+
@current_action ||= Action.new
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module Runfile
|
2
|
+
module Renderable
|
3
|
+
include Colsole
|
4
|
+
|
5
|
+
def render(view, context: nil)
|
6
|
+
path = "#{base_view_path}/#{view}.gtx"
|
7
|
+
GTX.render_file path, context: context, filename: path
|
8
|
+
end
|
9
|
+
|
10
|
+
private
|
11
|
+
|
12
|
+
def base_view_path
|
13
|
+
@base_view_path ||= ::File.expand_path '../views', __dir__
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
module Runfile
|
2
|
+
# Serves as the initial entrypoint when running +run+.
|
3
|
+
class Entrypoint
|
4
|
+
include Inspectable
|
5
|
+
include Renderable
|
6
|
+
include Colsole
|
7
|
+
|
8
|
+
attr_reader :argv
|
9
|
+
|
10
|
+
def initialize(argv = ARGV)
|
11
|
+
@argv = argv
|
12
|
+
end
|
13
|
+
|
14
|
+
def inspectable
|
15
|
+
{ argv: argv }
|
16
|
+
end
|
17
|
+
|
18
|
+
def run
|
19
|
+
meta.handler(argv).run argv
|
20
|
+
end
|
21
|
+
|
22
|
+
def run!
|
23
|
+
run
|
24
|
+
rescue Runfile::ExitWithUsage => e
|
25
|
+
say e.message
|
26
|
+
1
|
27
|
+
rescue Runfile::UserError => e
|
28
|
+
puts e.backtrace.reverse if ENV['DEBUG']
|
29
|
+
say! "mib` #{e.class} `"
|
30
|
+
say! e.message
|
31
|
+
1
|
32
|
+
rescue Interrupt
|
33
|
+
say! 'm`Goodbye`', replace: true
|
34
|
+
1
|
35
|
+
rescue => e
|
36
|
+
puts e.backtrace.reverse if ENV['DEBUG']
|
37
|
+
origin = e.backtrace_locations.first
|
38
|
+
location = "#{origin.path}:#{origin.lineno}"
|
39
|
+
say! "rib` #{e.class} ` in nu`#{location}`"
|
40
|
+
say! e.message
|
41
|
+
1
|
42
|
+
end
|
43
|
+
|
44
|
+
private
|
45
|
+
|
46
|
+
def meta
|
47
|
+
@meta ||= Meta.new
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module Runfile
|
2
|
+
# All exceptions are rescued in bin/run, but using different styling
|
3
|
+
# Note that UserError types are displayed without location and are intended
|
4
|
+
# to be used when location is not important.
|
5
|
+
|
6
|
+
class Error < StandardError; end
|
7
|
+
class UserError < Error; end
|
8
|
+
class ExitWithUsage < Error; end
|
9
|
+
|
10
|
+
class ActionNotFound < UserError; end
|
11
|
+
class GemNotFound < UserError; end
|
12
|
+
class SyntaxError < UserError; end
|
13
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Runfile
|
2
|
+
# Finds the path of an installed or bundled gem
|
3
|
+
# Adapted from Rubocop <https://github.com/rubocop/rubocop/blob/master/lib/rubocop/config_loader_resolver.rb#L268>
|
4
|
+
class GemFinder
|
5
|
+
class << self
|
6
|
+
def find(gem_name, file = nil)
|
7
|
+
gem_path = find_gem_path gem_name
|
8
|
+
file ? File.join(gem_path, file) : gem_path
|
9
|
+
rescue Gem::LoadError
|
10
|
+
raise GemNotFound, "Cannot import gem nub`#{gem_name}`\nTry running g`gem install #{gem_name}`"
|
11
|
+
end
|
12
|
+
|
13
|
+
private
|
14
|
+
|
15
|
+
def find_gem_path(gem_name)
|
16
|
+
if bundler?
|
17
|
+
gem = Bundler.load.specs[gem_name].first
|
18
|
+
gem_path = gem.full_gem_path if gem
|
19
|
+
end
|
20
|
+
|
21
|
+
gem_path || Gem::Specification.find_by_name(gem_name).gem_dir
|
22
|
+
end
|
23
|
+
|
24
|
+
def bundler?
|
25
|
+
defined? Bundler
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
|
3
|
+
module Runfile
|
4
|
+
# Creates a new runfile when running +run new+ in a directory without
|
5
|
+
# runfiles.
|
6
|
+
class Initiator
|
7
|
+
include Inspectable
|
8
|
+
include Renderable
|
9
|
+
|
10
|
+
def run(argv = ARGV)
|
11
|
+
Runner.run docopt, argv: argv, version: VERSION do |args|
|
12
|
+
execute_command args
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def execute_command(args)
|
19
|
+
return create_new_file if args['new']
|
20
|
+
|
21
|
+
if args['NAME']
|
22
|
+
create_example args['NAME']
|
23
|
+
else
|
24
|
+
list_examples
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def create_new_file
|
29
|
+
template = File.expand_path 'templates/runfile', __dir__
|
30
|
+
FileUtils.cp template, '.'
|
31
|
+
say 'Created g`runfile`'
|
32
|
+
say_tip
|
33
|
+
end
|
34
|
+
|
35
|
+
def list_examples
|
36
|
+
say "nu`Available Examples`\n"
|
37
|
+
examples.each { |x| puts " #{x}" }
|
38
|
+
say ''
|
39
|
+
say <<~TIP
|
40
|
+
Run g`run example EXAMPLE` with any of these examples to copy the files
|
41
|
+
to the current directory.
|
42
|
+
|
43
|
+
If you are not sure, try g`run example naval-fate`.
|
44
|
+
TIP
|
45
|
+
end
|
46
|
+
|
47
|
+
def create_example(name)
|
48
|
+
dir = "#{examples_dir}/#{name}"
|
49
|
+
files = Dir["#{dir}/{runfile,*.runfile,*.rb}"]
|
50
|
+
raise UserError, "No such example: nu`#{name}`" if files.empty?
|
51
|
+
|
52
|
+
files.each { |file| safe_copy file }
|
53
|
+
say_tip
|
54
|
+
end
|
55
|
+
|
56
|
+
def say_tip
|
57
|
+
say ''
|
58
|
+
say 'Run g`run` or g`run --help` to see your runfile'
|
59
|
+
say 'Delete the copied files to go back to the initial state'
|
60
|
+
end
|
61
|
+
|
62
|
+
def safe_copy(file)
|
63
|
+
target = File.basename file
|
64
|
+
# This will never happen since if there is a runfile, the initiator will
|
65
|
+
# not be called. Nonetheless, keep it for safety
|
66
|
+
return if File.exist? target
|
67
|
+
|
68
|
+
FileUtils.cp file, '.'
|
69
|
+
say "Copied g`#{target}`"
|
70
|
+
end
|
71
|
+
|
72
|
+
def examples
|
73
|
+
@examples ||= Dir["#{examples_dir}/*"]
|
74
|
+
.select { |f| File.directory? f }
|
75
|
+
.map { |f| File.basename f }
|
76
|
+
.sort
|
77
|
+
end
|
78
|
+
|
79
|
+
def examples_dir
|
80
|
+
@examples_dir ||= File.expand_path '../../examples', __dir__
|
81
|
+
end
|
82
|
+
|
83
|
+
def docopt
|
84
|
+
@docopt ||= render('initiator', context: self)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
data/lib/runfile/meta.rb
ADDED
@@ -0,0 +1,65 @@
|
|
1
|
+
module Runfile
|
2
|
+
# Holds meta information about the state of runfiles in a given directory
|
3
|
+
class Meta
|
4
|
+
include Inspectable
|
5
|
+
|
6
|
+
MASTERFILE_NAMES = %w[runfile Runfile runfile.rb]
|
7
|
+
|
8
|
+
def masterfile_path
|
9
|
+
@masterfile_path ||= begin
|
10
|
+
result = nil
|
11
|
+
|
12
|
+
MASTERFILE_NAMES.each do |name|
|
13
|
+
if File.exist? name
|
14
|
+
result = name
|
15
|
+
break
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
result
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def handler(_argv = ARGV)
|
24
|
+
masterfile || dummy || initiator
|
25
|
+
end
|
26
|
+
|
27
|
+
# If there are external files and no masterfile, we will use a dummy empty
|
28
|
+
# runfile as a masterfile to serve as the access point to the named
|
29
|
+
# runfiles
|
30
|
+
def dummy
|
31
|
+
return nil unless external_files.any?
|
32
|
+
|
33
|
+
Userfile.new
|
34
|
+
end
|
35
|
+
|
36
|
+
def initiator
|
37
|
+
Initiator.new
|
38
|
+
end
|
39
|
+
|
40
|
+
def masterfile
|
41
|
+
return nil unless masterfile_path
|
42
|
+
|
43
|
+
@masterfile ||= Userfile.load_file masterfile_path
|
44
|
+
end
|
45
|
+
|
46
|
+
# def title
|
47
|
+
# masterfile&.title
|
48
|
+
# end
|
49
|
+
|
50
|
+
# def summary
|
51
|
+
# masterfile&.summary
|
52
|
+
# end
|
53
|
+
|
54
|
+
def globs
|
55
|
+
@globs ||= (masterfile ? ['*'] + masterfile.imports : ['*'])
|
56
|
+
end
|
57
|
+
|
58
|
+
def external_files
|
59
|
+
@external_files ||= globs
|
60
|
+
.map { |glob| Dir["#{glob}.runfile"].sort }
|
61
|
+
.flatten
|
62
|
+
.to_h { |file| [File.basename(file, '.runfile'), Userfile.load_file(file)] }
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
data/lib/runfile/runner.rb
CHANGED
@@ -1,183 +1,20 @@
|
|
1
|
-
require 'singleton'
|
2
|
-
require 'docopt'
|
3
|
-
|
4
1
|
module Runfile
|
5
|
-
|
6
|
-
# The Runner class is the main workhorse behind Runfile.
|
7
|
-
# It handles all the Runfile DSL commands and executes the
|
8
|
-
# Runfile with the help of two more specialized classes:
|
9
|
-
# 1. DocoptHelper - for deeper docopt related actions
|
10
|
-
# 2. RunfileHelper - for Runfile creation and system wide search
|
2
|
+
# Executes docopt.
|
11
3
|
class Runner
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
:params, :env_vars
|
18
|
-
|
19
|
-
# Initialize all variables to sensible defaults.
|
20
|
-
def initialize
|
21
|
-
@superspace = nil # used when filename != Runfile
|
22
|
-
@last_usage = nil # dsl: usage
|
23
|
-
@last_help = nil # dsl: help
|
24
|
-
@namespace = nil # dsl: command
|
25
|
-
@actions = {} # dsl: action
|
26
|
-
@options = {} # dsl: option
|
27
|
-
@params = {} # dsl: param
|
28
|
-
@examples = [] # dsl: example
|
29
|
-
@env_vars = {} # dsl: env_var
|
30
|
-
@name = "Runfile" # dsl: name
|
31
|
-
@version = false # dsl: version
|
32
|
-
@summary = false # dsl: summary
|
33
|
-
end
|
34
|
-
|
35
|
-
# Load and execute a Runfile call.
|
36
|
-
def execute(argv, filename='Runfile')
|
37
|
-
@ignore_settings = !filename
|
38
|
-
argv = expand_shortcuts argv
|
39
|
-
filename and File.file?(filename) or handle_no_runfile argv
|
40
|
-
|
41
|
-
begin
|
42
|
-
load settings.helper if settings.helper
|
43
|
-
load filename
|
44
|
-
rescue => ex
|
45
|
-
abort "Runfile error:\n#{ex.message}\n#{ex.backtrace[0]}"
|
46
|
-
end
|
47
|
-
run(*argv)
|
48
|
-
end
|
49
|
-
|
50
|
-
# Add an action to the @actions array, and use the last known
|
51
|
-
# usage and help messages sent by the DSL.
|
52
|
-
def add_action(name, altname = nil, &block)
|
53
|
-
if @last_usage.nil?
|
54
|
-
@last_usage = altname ? "(#{name}|#{altname})" : name
|
55
|
-
end
|
56
|
-
[@namespace, @superspace].each do |prefix|
|
57
|
-
prefix or next
|
58
|
-
name = "#{prefix}_#{name}"
|
59
|
-
@last_usage = "#{prefix} #{last_usage}" unless @last_usage == false
|
60
|
-
end
|
61
|
-
name = name.to_sym
|
62
|
-
@actions[name] = Action.new(block, @last_usage, @last_help)
|
63
|
-
@last_usage = nil
|
64
|
-
@last_help = nil
|
65
|
-
if altname
|
66
|
-
@last_usage = false
|
67
|
-
add_action(altname, nil, &block)
|
68
|
-
end
|
69
|
-
end
|
70
|
-
|
71
|
-
# Add an option flag and its help text.
|
72
|
-
def add_option(flag, text, scope = nil)
|
73
|
-
scope ||= 'Options'
|
74
|
-
@options[scope] ||= {}
|
75
|
-
@options[scope][flag] = text
|
76
|
-
end
|
77
|
-
|
78
|
-
# Add a patameter and its help text.
|
79
|
-
def add_param(name, text, scope = nil)
|
80
|
-
scope ||= 'Parameters'
|
81
|
-
@params[scope] ||= {}
|
82
|
-
@params[scope][name] = text
|
83
|
-
end
|
84
|
-
|
85
|
-
# Add env_var command.
|
86
|
-
def add_env_var(name, text, scope = nil)
|
87
|
-
scope ||= 'Environment Variables'
|
88
|
-
@env_vars[scope] ||= {}
|
89
|
-
@env_vars[scope][name] = text
|
90
|
-
end
|
91
|
-
|
92
|
-
# Add example command.
|
93
|
-
def add_example(command)
|
94
|
-
@examples << (@namespace ? "#{@namespace} #{command}" : command)
|
95
|
-
end
|
96
|
-
|
97
|
-
# Run the command. This is a wrapper around docopt. It will
|
98
|
-
# generate the docopt document on the fly, using all the
|
99
|
-
# information collected so far.
|
100
|
-
def run(*argv)
|
101
|
-
begin
|
102
|
-
docopt_exec argv
|
103
|
-
rescue Docopt::Exit => ex
|
104
|
-
puts ex.message
|
105
|
-
exit 2
|
4
|
+
class << self
|
5
|
+
def run(docopt, version: nil, argv: nil)
|
6
|
+
args = call_docopt docopt, argv: argv, version: version
|
7
|
+
yield args if block_given?
|
8
|
+
args
|
106
9
|
end
|
107
|
-
end
|
108
|
-
|
109
|
-
# Invoke action from another action. Used by the DSL's #execute
|
110
|
-
# function. Expects to get a single string that looks as if
|
111
|
-
# it was typed in the command prompt.
|
112
|
-
def cross_call(command_string)
|
113
|
-
argv = command_string.split(/\s(?=(?:[^"]|"[^"]*")*$)/)
|
114
|
-
begin
|
115
|
-
docopt_exec argv
|
116
|
-
rescue Docopt::Exit => ex
|
117
|
-
puts "Cross call failed: #{command_string}"
|
118
|
-
abort ex.message
|
119
|
-
end
|
120
|
-
end
|
121
10
|
|
122
11
|
private
|
123
12
|
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
def docopt_exec(argv)
|
129
|
-
helper = DocoptHelper.new(self)
|
130
|
-
args = helper.args argv
|
131
|
-
action = find_action argv
|
132
|
-
action or abort "Runfile error: Action not found"
|
133
|
-
@actions[action].execute args
|
134
|
-
end
|
135
|
-
|
136
|
-
# Inspect the first three arguments in the argv and look for
|
137
|
-
# a matching action.
|
138
|
-
# We will first look for a_b_c action, then for a_b and
|
139
|
-
# finally for a. This is intended to allow "overloading" of
|
140
|
-
# the command as an action (e.g. also allow a global action
|
141
|
-
# called 'a').
|
142
|
-
# if no command was found, but we have a :global command,
|
143
|
-
# assume this is the requested one (since we will not reach
|
144
|
-
# this point unless the usage pattern matches).
|
145
|
-
def find_action(argv)
|
146
|
-
3.downto(1).each do |count|
|
147
|
-
next unless argv.size >= count
|
148
|
-
action = argv[0..count-1].join('_').to_sym
|
149
|
-
return action if @actions.has_key? action
|
150
|
-
end
|
151
|
-
return :global if @actions.has_key? :global
|
152
|
-
return "#{superspace}_global".to_sym if @superspace and @actions.has_key? "#{superspace}_global".to_sym
|
153
|
-
return false
|
154
|
-
end
|
155
|
-
|
156
|
-
# When `run` is called without a Runfile (or runfile not
|
157
|
-
# found), hand over handling to the RunfileHelper class.
|
158
|
-
# If will either return false if no further handling is needed
|
159
|
-
# on our part, or the name of a runfile to execute.
|
160
|
-
def handle_no_runfile(argv)
|
161
|
-
maker = RunfileHelper.new
|
162
|
-
maker.purge_settings if @ignore_settings
|
163
|
-
runfile = maker.handle argv
|
164
|
-
|
165
|
-
exit 3 unless runfile
|
166
|
-
|
167
|
-
@superspace = argv[0]
|
168
|
-
execute argv, runfile
|
169
|
-
exit
|
170
|
-
end
|
171
|
-
|
172
|
-
def expand_shortcuts(argv)
|
173
|
-
possible_candidate = argv[0]
|
174
|
-
if settings.shortcuts and settings.shortcuts[possible_candidate]
|
175
|
-
shortcut_value = settings.shortcuts[argv[0]]
|
176
|
-
expanded = shortcut_value.split ' '
|
177
|
-
argv.shift
|
178
|
-
argv = expanded + argv
|
13
|
+
def call_docopt(docopt, version: nil, argv: nil)
|
14
|
+
Docopt.docopt docopt, argv: argv, version: version
|
15
|
+
rescue Docopt::Exit => e
|
16
|
+
raise ExitWithUsage, e.message
|
179
17
|
end
|
180
|
-
argv
|
181
18
|
end
|
182
19
|
end
|
183
20
|
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
title 'Greeter'
|
2
|
+
summary 'A sample runfile'
|
3
|
+
|
4
|
+
usage 'hello [NAME --shout]'
|
5
|
+
help 'Say hello'
|
6
|
+
option '--shout, -s', 'Greet louder'
|
7
|
+
action 'hello' do |args|
|
8
|
+
name = args['NAME'] || 'You...'
|
9
|
+
message = "Hello #{name}"
|
10
|
+
message = "#{message.upcase}!" if args['--shout']
|
11
|
+
|
12
|
+
say "gu`#{message}`"
|
13
|
+
end
|