shelldon 0.0.1 → 0.0.7
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/.gitignore +11 -0
- data/.rubocop.yml +60 -0
- data/Gemfile +0 -5
- data/README.md +0 -1
- data/lib/auto_complete.rb +34 -0
- data/lib/command/command.rb +63 -11
- data/lib/command/command_list.rb +16 -8
- data/lib/command/script.rb +33 -0
- data/lib/config/config.rb +13 -4
- data/lib/config/config_factory.rb +4 -0
- data/lib/config/param.rb +17 -11
- data/lib/config/param/boolean_param.rb +1 -1
- data/lib/config/param_factory.rb +6 -1
- data/lib/dsl.rb +17 -0
- data/lib/{Exceptions → exceptions}/error_factory.rb +10 -0
- data/lib/exceptions/exceptions.rb +60 -0
- data/lib/file_management/config_file_manager.rb +3 -7
- data/lib/file_management/history_file.rb +0 -2
- data/lib/file_management/yaml_manager.rb +10 -1
- data/lib/helpers/confirmation.rb +20 -0
- data/lib/helpers/timer.rb +5 -0
- data/lib/opts/opt_factory.rb +4 -3
- data/lib/opts/opts.rb +1 -1
- data/lib/shell/shell.rb +82 -19
- data/lib/shell/shell_factory.rb +87 -14
- data/lib/shell/shell_index.rb +11 -1
- data/lib/shelldon.rb +8 -3
- data/lib/shelldon/version.rb +1 -1
- data/shelldon.gemspec +15 -8
- data/test_shell/Gemfile +1 -2
- data/test_shell/Gemfile.lock +7 -6
- data/test_shell/dependency_test/Gemfile +2 -0
- data/test_shell/dependency_test/Gemfile.lock +21 -0
- data/test_shell/dependency_test/dependency_test.rb +20 -0
- data/test_shell/dependency_test/dt_commands.rb +66 -0
- data/test_shell/dependency_test/dt_config.rb +31 -0
- data/test_shell/dependency_test/dt_opts.rb +11 -0
- data/test_shell/dependency_test/dt_runner.rb +11 -0
- data/test_shell/simple_shell.rb +6 -6
- data/test_shell/test_shell.rb +46 -3
- data/test_shell/useful_commands.rb +1 -1
- metadata +80 -41
- data/Gemfile.lock +0 -43
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4c9b127c3231b3a6616c774fe92a69847b25bb10
|
4
|
+
data.tar.gz: d9a68228b4bcfe2ac70c55123c3b08ce99ca4a41
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3b2f291dd74ff9ab4e29f2626a3331f93a72da07629f0f3eb6026466b188eff6e4b92af70c3371f41bc0eddc03fd6bc6787768ef8b45270389d95551f51828e3
|
7
|
+
data.tar.gz: 413aa23e7e03186a0d6684c3a74b38226f6d8f7ee05a46dcab1297638122446667efb1ec3c38db8864afefb0bf9e55f638cfb1a3acd1b2be3ed17d71e02e519d
|
data/.gitignore
ADDED
data/.rubocop.yml
ADDED
@@ -0,0 +1,60 @@
|
|
1
|
+
#inherit_from: ../.rubocop.yml
|
2
|
+
|
3
|
+
# Why do I even use robocop lol
|
4
|
+
# Oh yeah because it puts a space in before my comments.
|
5
|
+
|
6
|
+
AllCops:
|
7
|
+
Exclude:
|
8
|
+
- test_scripts/*
|
9
|
+
- example_data/*
|
10
|
+
|
11
|
+
Metrics/LineLength:
|
12
|
+
Enabled: false
|
13
|
+
|
14
|
+
Style/Documentation:
|
15
|
+
Enabled: false
|
16
|
+
|
17
|
+
Style/Encoding:
|
18
|
+
Enabled: false
|
19
|
+
|
20
|
+
Style/Semicolon:
|
21
|
+
Enabled: false
|
22
|
+
|
23
|
+
Style/AccessorMethodName:
|
24
|
+
Enabled: false
|
25
|
+
|
26
|
+
Metrics/MethodLength:
|
27
|
+
Enabled: false
|
28
|
+
|
29
|
+
Metrics/AbcSize:
|
30
|
+
Enabled: false
|
31
|
+
|
32
|
+
Metrics/ParameterLists:
|
33
|
+
Enabled: false
|
34
|
+
|
35
|
+
Style/Next:
|
36
|
+
Enabled: false
|
37
|
+
|
38
|
+
Style/FileName:
|
39
|
+
Enabled: false
|
40
|
+
|
41
|
+
Style/PredicateName:
|
42
|
+
Enabled: false
|
43
|
+
|
44
|
+
Style/NestedTernaryOperator:
|
45
|
+
Enabled: false
|
46
|
+
|
47
|
+
Metrics/CyclomaticComplexity:
|
48
|
+
Enabled: false
|
49
|
+
|
50
|
+
Metrics/PerceivedComplexity:
|
51
|
+
Enabled: false
|
52
|
+
|
53
|
+
Metrics/ClassLength:
|
54
|
+
Enabled: false
|
55
|
+
|
56
|
+
Lint/AssignmentInCondition:
|
57
|
+
Enabled: false
|
58
|
+
|
59
|
+
Style/TrivialAccessors:
|
60
|
+
Enabled: false
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -0,0 +1,34 @@
|
|
1
|
+
# require 'abbrev'
|
2
|
+
|
3
|
+
module Shelldon
|
4
|
+
class AutoComplete
|
5
|
+
def initialize(shell)
|
6
|
+
@shell = shell
|
7
|
+
end
|
8
|
+
|
9
|
+
def set_proc
|
10
|
+
@comp = proc { |s| auto_comp.grep(/^#{Regexp.escape(s)}/) }
|
11
|
+
Readline.completion_append_character = ' '
|
12
|
+
Readline.completion_proc = @comp
|
13
|
+
end
|
14
|
+
|
15
|
+
def buf
|
16
|
+
Readline.line_buffer
|
17
|
+
end
|
18
|
+
|
19
|
+
def auto_comp
|
20
|
+
Readline.completion_append_character = ' '
|
21
|
+
@commands = @shell.command_list.commands.map(&:to_s)
|
22
|
+
length = buf.split(' ').length
|
23
|
+
return @commands if length <= 1 && !buf.end_with?(' ')
|
24
|
+
cmd, = @shell.command_list.find(buf)
|
25
|
+
return [] unless cmd
|
26
|
+
remainder = buf.gsub("#{cmd.christian_name} ", '')
|
27
|
+
cmd.complete(remainder)
|
28
|
+
end
|
29
|
+
|
30
|
+
def tokenize(str)
|
31
|
+
str.split(' ')
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
data/lib/command/command.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
module Shelldon
|
2
2
|
class Command
|
3
|
-
attr_reader :name, :aliases, :subcommands, :parent
|
3
|
+
attr_reader :name, :aliases, :subcommands, :parent, :autocomplete, :times_out
|
4
4
|
|
5
5
|
def initialize(name, parent, &block)
|
6
6
|
@name = name
|
@@ -8,6 +8,7 @@ module Shelldon
|
|
8
8
|
@subcommands = {}
|
9
9
|
@show = true
|
10
10
|
@parent = parent
|
11
|
+
@times_out = true
|
11
12
|
instance_eval(&block)
|
12
13
|
end
|
13
14
|
|
@@ -19,8 +20,12 @@ module Shelldon
|
|
19
20
|
end
|
20
21
|
end
|
21
22
|
|
23
|
+
def fuzzy(cmd)
|
24
|
+
FuzzyMatch.new(command_list.to_a.map(&:first).map(&:to_s)).find(cmd)
|
25
|
+
end
|
26
|
+
|
22
27
|
def command_list
|
23
|
-
@parent
|
28
|
+
@parent.command_list
|
24
29
|
end
|
25
30
|
|
26
31
|
def shell
|
@@ -34,8 +39,10 @@ module Shelldon
|
|
34
39
|
end
|
35
40
|
|
36
41
|
def run(tokens = [])
|
37
|
-
tokens
|
38
|
-
|
42
|
+
tokens = [tokens] unless tokens.is_a?(Array)
|
43
|
+
Timeout.timeout(timeout_length, Shelldon::TimeoutError) do
|
44
|
+
instance_exec(tokens.join(' '), &@action)
|
45
|
+
end
|
39
46
|
end
|
40
47
|
|
41
48
|
def valid?(input)
|
@@ -47,10 +54,6 @@ module Shelldon
|
|
47
54
|
end
|
48
55
|
end
|
49
56
|
|
50
|
-
def auto_complete(_input)
|
51
|
-
@autocomplete = @subcommands.values
|
52
|
-
end
|
53
|
-
|
54
57
|
def has_subcommand?
|
55
58
|
!@subcommands.empty?
|
56
59
|
end
|
@@ -98,14 +101,41 @@ module Shelldon
|
|
98
101
|
end
|
99
102
|
end
|
100
103
|
|
101
|
-
def
|
102
|
-
|
104
|
+
def to_a
|
105
|
+
[@name, @aliases.map { |a| "'#{a}'" }.join(', '), @help || '']
|
106
|
+
end
|
107
|
+
|
108
|
+
def sub_to_a
|
109
|
+
@subcommands.values.uniq
|
110
|
+
.map { |cmd| cmd.show ? cmd.to_a : nil }
|
111
|
+
.compact.sort_by { |(n, _, _)| n.to_s }
|
112
|
+
end
|
113
|
+
|
114
|
+
def timeout_length(_i = nil)
|
115
|
+
return 0 unless @times_out
|
116
|
+
return shell.config[:timeout] unless @timeout
|
117
|
+
@timeout
|
118
|
+
end
|
119
|
+
|
120
|
+
def complete(buf)
|
121
|
+
length = buf.split(' ').length
|
122
|
+
res = (length <= 1 && !buf.end_with?(' ')) ? subcommand_list : []
|
123
|
+
res += instance_exec(buf, &@autocomplete) if @autocomplete
|
124
|
+
res
|
103
125
|
end
|
104
126
|
|
105
127
|
# DSL Only
|
106
128
|
|
107
129
|
private
|
108
130
|
|
131
|
+
def times_out(bool = true)
|
132
|
+
@times_out = bool
|
133
|
+
end
|
134
|
+
|
135
|
+
def timeout(i = nil)
|
136
|
+
i ? @timeout = i : @timeout
|
137
|
+
end
|
138
|
+
|
109
139
|
def validate(error, &block)
|
110
140
|
@error = error if error
|
111
141
|
@validator = block
|
@@ -123,12 +153,34 @@ module Shelldon
|
|
123
153
|
@subcommands[name.to_sym] = Shelldon::Command.new(name, self, &block)
|
124
154
|
end
|
125
155
|
|
156
|
+
def subcommand_list
|
157
|
+
return [] if @subcommands.empty?
|
158
|
+
@subcommands.keys.map(&:to_s)
|
159
|
+
end
|
160
|
+
|
161
|
+
def script(dir)
|
162
|
+
Shelldon::Script.from_dir(dir, self).each do |cmd|
|
163
|
+
@subcommands[cmd.name.to_sym] = cmd
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
alias_method :scripts, :script
|
168
|
+
|
126
169
|
def completion(arr = [], &block)
|
127
170
|
@completion = (block_given? ? block : arr)
|
128
171
|
end
|
129
172
|
|
130
173
|
def placeholder
|
131
|
-
@action = proc { fail
|
174
|
+
@action = proc { fail Shelldon::NotImplementedError }
|
175
|
+
end
|
176
|
+
|
177
|
+
def autocomplete(arr = nil, &block)
|
178
|
+
if block_given?
|
179
|
+
@autocomplete = block.to_proc
|
180
|
+
else
|
181
|
+
arr ||= []
|
182
|
+
@autocomplete = proc { arr }
|
183
|
+
end
|
132
184
|
end
|
133
185
|
end
|
134
186
|
end
|
data/lib/command/command_list.rb
CHANGED
@@ -13,6 +13,10 @@ module Shelldon
|
|
13
13
|
command.aliases.each { |a| @commands[a.to_sym] = command }
|
14
14
|
end
|
15
15
|
|
16
|
+
def command_list
|
17
|
+
self
|
18
|
+
end
|
19
|
+
|
16
20
|
def register_default(cmd)
|
17
21
|
@default_command = cmd
|
18
22
|
end
|
@@ -38,11 +42,11 @@ module Shelldon
|
|
38
42
|
end
|
39
43
|
|
40
44
|
def compile_help(cmd)
|
41
|
-
res
|
42
|
-
res
|
43
|
-
res
|
44
|
-
res
|
45
|
-
res
|
45
|
+
res = { command: cmd.christian_name }
|
46
|
+
res[:help] = cmd.help if cmd.help
|
47
|
+
res[:usage] = "\"#{cmd.usage}\"" if cmd.usage
|
48
|
+
res[:examples] = cmd.examples if cmd.examples
|
49
|
+
res[:subcommands] = cmd.subcommands.values.map(&:name).join(', ') unless cmd.subcommands.empty?
|
46
50
|
res
|
47
51
|
end
|
48
52
|
|
@@ -52,9 +56,9 @@ module Shelldon
|
|
52
56
|
else
|
53
57
|
cmd = find(str).first
|
54
58
|
if cmd.show && !is_default?(cmd)
|
55
|
-
compile_help(cmd)
|
59
|
+
[compile_help(cmd), cmd.sub_to_a]
|
56
60
|
else
|
57
|
-
fail
|
61
|
+
fail Shelldon::NoSuchCommandError
|
58
62
|
end
|
59
63
|
end
|
60
64
|
end
|
@@ -65,8 +69,12 @@ module Shelldon
|
|
65
69
|
|
66
70
|
def to_a
|
67
71
|
@commands.values.uniq
|
68
|
-
.map { |cmd| cmd.show ?
|
72
|
+
.map { |cmd| cmd.show ? cmd.to_a : nil }
|
69
73
|
.compact.sort_by { |(n, _, _)| n.to_s }
|
70
74
|
end
|
75
|
+
|
76
|
+
def commands
|
77
|
+
@commands.keys
|
78
|
+
end
|
71
79
|
end
|
72
80
|
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module Shelldon
|
2
|
+
class Script < Command
|
3
|
+
def self.from_dir(dir, shell)
|
4
|
+
commands = []
|
5
|
+
Dir["#{Pathname.new(dir).expand_path}/*"].reject { |f| File.directory?(f) }.each do |script|
|
6
|
+
commands << new(script, shell.command_list)
|
7
|
+
end
|
8
|
+
commands
|
9
|
+
end
|
10
|
+
|
11
|
+
def initialize(filepath, parent, &block)
|
12
|
+
@path = Pathname.new(filepath)
|
13
|
+
@name = @path.basename.to_s.split('.')[0].to_sym
|
14
|
+
@aliases = []
|
15
|
+
@subcommands = {}
|
16
|
+
@show = true
|
17
|
+
@parent = parent
|
18
|
+
instance_eval(&block) if block_given?
|
19
|
+
end
|
20
|
+
|
21
|
+
def run(tokens = [], &block)
|
22
|
+
tokens = [tokens] unless tokens.is_a?(Array)
|
23
|
+
cmd = "#{@path.expand_path}"
|
24
|
+
cmd << " #{tokens.join(' ')}" unless tokens.empty?
|
25
|
+
res = `#{@path.expand_path} #{tokens.join(' ')}`
|
26
|
+
if block_given?
|
27
|
+
instance_exec(res, &block)
|
28
|
+
else
|
29
|
+
puts res
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
data/lib/config/config.rb
CHANGED
@@ -20,8 +20,13 @@ module Shelldon
|
|
20
20
|
load_config_file
|
21
21
|
end
|
22
22
|
|
23
|
+
def toggle(key)
|
24
|
+
fail Shelldon::NotBooleanError unless @config[key].is_a?(Shelldon::BooleanParam)
|
25
|
+
@config[key].toggle
|
26
|
+
end
|
27
|
+
|
23
28
|
def register(param)
|
24
|
-
fail
|
29
|
+
fail Shelldon::DuplicateParamError if @config.key?(param.name)
|
25
30
|
@config[param.name] = param
|
26
31
|
end
|
27
32
|
|
@@ -43,7 +48,7 @@ module Shelldon
|
|
43
48
|
end
|
44
49
|
|
45
50
|
def to_a
|
46
|
-
@config.map
|
51
|
+
@config.values.map(&:to_a).sort_by(&:first)
|
47
52
|
end
|
48
53
|
|
49
54
|
def to_hash
|
@@ -54,7 +59,7 @@ module Shelldon
|
|
54
59
|
if @config.key?(key.to_sym)
|
55
60
|
true
|
56
61
|
else
|
57
|
-
raise ? fail(
|
62
|
+
raise ? fail(Shelldon::NoSuchParamError) : false
|
58
63
|
end
|
59
64
|
end
|
60
65
|
|
@@ -67,7 +72,11 @@ module Shelldon
|
|
67
72
|
# Then we validate them all
|
68
73
|
hash.each do |k, v|
|
69
74
|
key = k.to_sym
|
70
|
-
@config.key?(key)
|
75
|
+
if @config.key?(key)
|
76
|
+
set(key, v) unless @config[key].override || Shelldon.opts.key?(@config[key].opt)
|
77
|
+
else
|
78
|
+
fail(Shelldon::NoSuchParamError)
|
79
|
+
end
|
71
80
|
end
|
72
81
|
hash.each do |k, _|
|
73
82
|
@config[k].valid? unless @config[k].val == @config[k].default
|
data/lib/config/param.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
module Shelldon
|
2
2
|
class Param
|
3
|
-
attr_accessor :pretty, :default, :opt, :validator, :adjustor, :error
|
3
|
+
attr_accessor :pretty, :default, :opt, :validator, :adjustor, :error, :override
|
4
4
|
attr_reader :name
|
5
5
|
|
6
6
|
def self.create(name, &block)
|
@@ -13,20 +13,14 @@ module Shelldon
|
|
13
13
|
end
|
14
14
|
|
15
15
|
def val
|
16
|
-
if @val
|
17
|
-
|
18
|
-
|
19
|
-
else
|
20
|
-
@default
|
21
|
-
end
|
22
|
-
else
|
23
|
-
@val
|
24
|
-
end
|
16
|
+
return @val if @val
|
17
|
+
return @override if @override
|
18
|
+
@val = Shelldon.opts.key?(@opt) ? Shelldon.opts[@opt] : @default
|
25
19
|
end
|
26
20
|
|
27
21
|
def val=(value)
|
28
22
|
value = instance_exec(value, &adjustor) if adjustor
|
29
|
-
valid?(value) ? @val = value : fail(
|
23
|
+
valid?(value) ? @val = value : fail(Shelldon::InvalidParamValueError)
|
30
24
|
end
|
31
25
|
|
32
26
|
def set(value)
|
@@ -34,6 +28,18 @@ module Shelldon
|
|
34
28
|
@val = value
|
35
29
|
end
|
36
30
|
|
31
|
+
def to_a
|
32
|
+
flag =
|
33
|
+
if @opt.nil?
|
34
|
+
''
|
35
|
+
elsif @opt.length > 1
|
36
|
+
"'--#{@opt}'"
|
37
|
+
else
|
38
|
+
"'-#{@opt}'"
|
39
|
+
end
|
40
|
+
[@name, pretty, "#{flag}"]
|
41
|
+
end
|
42
|
+
|
37
43
|
def pretty
|
38
44
|
if @pretty
|
39
45
|
instance_exec(val, &@pretty)
|