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.
Files changed (44) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +11 -0
  3. data/.rubocop.yml +60 -0
  4. data/Gemfile +0 -5
  5. data/README.md +0 -1
  6. data/lib/auto_complete.rb +34 -0
  7. data/lib/command/command.rb +63 -11
  8. data/lib/command/command_list.rb +16 -8
  9. data/lib/command/script.rb +33 -0
  10. data/lib/config/config.rb +13 -4
  11. data/lib/config/config_factory.rb +4 -0
  12. data/lib/config/param.rb +17 -11
  13. data/lib/config/param/boolean_param.rb +1 -1
  14. data/lib/config/param_factory.rb +6 -1
  15. data/lib/dsl.rb +17 -0
  16. data/lib/{Exceptions → exceptions}/error_factory.rb +10 -0
  17. data/lib/exceptions/exceptions.rb +60 -0
  18. data/lib/file_management/config_file_manager.rb +3 -7
  19. data/lib/file_management/history_file.rb +0 -2
  20. data/lib/file_management/yaml_manager.rb +10 -1
  21. data/lib/helpers/confirmation.rb +20 -0
  22. data/lib/helpers/timer.rb +5 -0
  23. data/lib/opts/opt_factory.rb +4 -3
  24. data/lib/opts/opts.rb +1 -1
  25. data/lib/shell/shell.rb +82 -19
  26. data/lib/shell/shell_factory.rb +87 -14
  27. data/lib/shell/shell_index.rb +11 -1
  28. data/lib/shelldon.rb +8 -3
  29. data/lib/shelldon/version.rb +1 -1
  30. data/shelldon.gemspec +15 -8
  31. data/test_shell/Gemfile +1 -2
  32. data/test_shell/Gemfile.lock +7 -6
  33. data/test_shell/dependency_test/Gemfile +2 -0
  34. data/test_shell/dependency_test/Gemfile.lock +21 -0
  35. data/test_shell/dependency_test/dependency_test.rb +20 -0
  36. data/test_shell/dependency_test/dt_commands.rb +66 -0
  37. data/test_shell/dependency_test/dt_config.rb +31 -0
  38. data/test_shell/dependency_test/dt_opts.rb +11 -0
  39. data/test_shell/dependency_test/dt_runner.rb +11 -0
  40. data/test_shell/simple_shell.rb +6 -6
  41. data/test_shell/test_shell.rb +46 -3
  42. data/test_shell/useful_commands.rb +1 -1
  43. metadata +80 -41
  44. data/Gemfile.lock +0 -43
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 1050dd8126c65561d242ce862a4cf2947ed61618
4
- data.tar.gz: fd6ad927cc21f2087011bd1584e652d4b4ac415d
3
+ metadata.gz: 4c9b127c3231b3a6616c774fe92a69847b25bb10
4
+ data.tar.gz: d9a68228b4bcfe2ac70c55123c3b08ce99ca4a41
5
5
  SHA512:
6
- metadata.gz: f9a2c2be6b2cba4b8bd61fa6b666fd1b5daf9d15bc9d8d04eb2c1bfb2c7811aa3836f18357d779d8ca86ef6f98b9fbe64cdcbb2c0c48f23d2ee0150bb1a767c4
7
- data.tar.gz: 168ab3b8d30c478081e3d2dbac3f032f5b74f93d93736c618eb2909e235207eb5f0bcf9a409bdb75ae8bf440b05c270aee8148e81feb79fcdea04d457f77787d
6
+ metadata.gz: 3b2f291dd74ff9ab4e29f2626a3331f93a72da07629f0f3eb6026466b188eff6e4b92af70c3371f41bc0eddc03fd6bc6787768ef8b45270389d95551f51828e3
7
+ data.tar.gz: 413aa23e7e03186a0d6684c3a74b38226f6d8f7ee05a46dcab1297638122446667efb1ec3c38db8864afefb0bf9e55f638cfb1a3acd1b2be3ed17d71e02e519d
@@ -0,0 +1,11 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ *.gem
11
+ send_to_opsadm01.sh
@@ -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
@@ -1,8 +1,3 @@
1
1
  source 'https://rubygems.org'
2
2
 
3
- gem 'byebug'
4
- gem 'terminal-table'
5
- gem 'rb-readline'
6
- gem 'getopt'
7
-
8
3
  gemspec
data/README.md CHANGED
@@ -10,7 +10,6 @@ There are some good gems out there for building command-line executables, but I
10
10
  # Gemfile
11
11
  gem 'shelldon'
12
12
 
13
-
14
13
  $ bundle install
15
14
  ```
16
15
  Or just `gem install shelldon` -- You know the drill.
@@ -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
@@ -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 = [tokens] unless tokens.is_a?(Array)
38
- instance_exec(tokens.join(' '), &@action)
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 timeout(i = nil)
102
- i ? @timeout = i : @timeout
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 StandardError }
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
@@ -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 = [['Command', cmd.christian_name]]
42
- res << ['Help', cmd.help] if cmd.help
43
- res << ['Usage', "\"#{cmd.usage}\""] if cmd.usage
44
- res << ['Examples', cmd.examples] if cmd.examples
45
- res << ['Subcommands', cmd.subcommands.values.map(&:name)] unless cmd.subcommands.empty?
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 StandardError
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 ? [cmd.name, cmd.aliases, cmd.help] : nil }
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
@@ -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 StandardError if @config.key?(param.name)
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 { |k, v| [k, v.pretty] }.sort_by(&:first)
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(StandardError) : false
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) ? set(key, v) : fail(StandardError)
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
@@ -1,5 +1,9 @@
1
+ require 'logger'
2
+
1
3
  module Shelldon
2
4
  class ConfigFactory
5
+ attr_accessor :on_opts, :config_file_manager
6
+
3
7
  def self.create(shell, &block)
4
8
  ConfigFactory.new(shell, &block)
5
9
  end
@@ -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.nil?
17
- if Shelldon.opts.key?(@opt)
18
- Shelldon.opts[@opt]
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(StandardError)
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)