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
@@ -10,7 +10,7 @@ module Shelldon
10
10
  v
11
11
  elsif v.is_a?(String)
12
12
  return true if v == true || v =~ (/(true|t|yes|y|1)$/i)
13
- return false if v == false || v.blank? || v =~ (/(false|f|no|n|0)$/i)
13
+ return false if v == false || v =~ (/(false|f|no|n|0)$/i)
14
14
  fail(ArgumentError, "invalid value for Boolean: \"#{v}\"")
15
15
  else
16
16
  v ? true : false
@@ -21,6 +21,10 @@ module Shelldon
21
21
  @default = default_value
22
22
  end
23
23
 
24
+ def override(value)
25
+ @override = value
26
+ end
27
+
24
28
  def opt(opt)
25
29
  @opt = opt
26
30
  end
@@ -30,13 +34,14 @@ module Shelldon
30
34
  if @param
31
35
  @param.pretty = @pretty_proc if @pretty_proc
32
36
  @param.default = @default unless @default.nil?
37
+ @param.override = @override if @override
33
38
  @param.opt = @opt if @opt
34
39
  @param.error = @error if @error
35
40
  @param.validator = @validator if @validator
36
41
  @param.adjustor = @adjustor if @adjustor
37
42
  @config.register(@param)
38
43
  else
39
- fail StandardError
44
+ fail Shelldon::RegisterNilParamError
40
45
  end
41
46
  end
42
47
 
data/lib/dsl.rb CHANGED
@@ -7,6 +7,10 @@ module Shelldon
7
7
  ShellIndex.instance << shell if shell.is_a?(Shelldon::Shell)
8
8
  end
9
9
 
10
+ def self.first?(sym)
11
+ ShellIndex.first?(sym)
12
+ end
13
+
10
14
  def self.shell(name = (:default), &block)
11
15
  ShellFactory.new(name.to_sym, &block)
12
16
  end
@@ -18,4 +22,17 @@ module Shelldon
18
22
  def self.opts
19
23
  Shelldon::Opts.instance.opts
20
24
  end
25
+
26
+ def self.method_missing(meth, *args, &block)
27
+ ShellIndex.instance[:default].send(meth, *args, &block)
28
+ end
29
+
30
+ def self.confirm(*args)
31
+ Shelldon::Confirmation.ask(*args)
32
+ end
33
+
34
+ def self.has_shell?(sym)
35
+ sym = sym.to_sym unless sym
36
+ ShellIndex.instance.key?(sym)
37
+ end
21
38
  end
@@ -1,5 +1,7 @@
1
1
  module Shelldon
2
2
  class ErrorFactory
3
+ attr_reader :on_accept_error, :on_reject_error
4
+
3
5
  def initialize(&block)
4
6
  @accept_errors = {}
5
7
  @reject_errors = {}
@@ -19,6 +21,14 @@ module Shelldon
19
21
  @reject_errors[e] = (block_given? ? block : nil)
20
22
  end
21
23
 
24
+ def on_accept(&block)
25
+ @on_accept_error = block
26
+ end
27
+
28
+ def on_reject(&block)
29
+ @on_reject_error = block
30
+ end
31
+
22
32
  def get
23
33
  [@accept_errors, @reject_errors]
24
34
  end
@@ -0,0 +1,60 @@
1
+ module Shelldon
2
+ class Error < StandardError
3
+ end
4
+
5
+ class ConfirmationError < Error
6
+ define_method(:message) { 'User did not provide a valid confirmation.' }
7
+ end
8
+
9
+ class NotImplementedError < Error
10
+ define_method(:message) { 'This command has not been implemented, or is a placeholder' }
11
+ end
12
+
13
+ class NoSuchCommandError < Error
14
+ define_method(:message) { 'No such command exists' }
15
+ end
16
+
17
+ class NotBooleanError < Error
18
+ define_method(:message) { 'The specified config param is not a boolean' }
19
+ end
20
+
21
+ class NotProcError < Error
22
+ define_method(:message) { 'Autocomplete must be a Proc or an Array' }
23
+ end
24
+
25
+ class DuplicateParamError < Error
26
+ define_method(:message) { 'Cannot create two params with the same name' }
27
+ end
28
+
29
+ class NoSuchParamError < Error
30
+ define_method(:message) { 'No such param exists' }
31
+ end
32
+
33
+ class InvalidParamValueError < Error
34
+ define_method(:message) { 'Param failed to pass validation' }
35
+ end
36
+
37
+ class RegisterNilParamError < Error
38
+ define_method(:message) { 'The Param Factory is attempting to register a nil.' }
39
+ end
40
+
41
+ class NoSuchOptTypeError < Error
42
+ define_method(:message) { 'The specified opt type was not :boolean or :required' }
43
+ end
44
+
45
+ class RedefineOptsError < Error
46
+ define_method(:message) { 'Cannot re-define opts' }
47
+ end
48
+
49
+ class NoSuchShellError < Error
50
+ define_method(:message) { 'The shell index does not contain that shell' }
51
+ end
52
+
53
+ class NotAShellError < Error
54
+ define_method(:message) { 'Cannot add non-shells to the shell index' }
55
+ end
56
+
57
+ class TimeoutError < Error
58
+ define_method(:message) { 'Operation timed out.' }
59
+ end
60
+ end
@@ -4,24 +4,20 @@ module Shelldon
4
4
  class ConfigFileManager < YamlManager
5
5
  def initialize(shell, config_file)
6
6
  @shell = shell
7
- @config_file = config_file
7
+ @file = config_file
8
8
  end
9
9
 
10
10
  def ensure_dir(dir)
11
11
  FileUtils.mkdir_p(dir)
12
12
  end
13
13
 
14
- def ensure_file(file)
15
- File.open(file, 'w') { |f| f.write({}.to_yaml) } unless File.exist?(file)
16
- end
17
-
18
14
  def export
19
15
  super(@shell.config)
20
16
  end
21
17
 
22
18
  def setup
23
- @file = @config_file.expand_path
24
- @file_dir = @config_file.dirname.expand_path
19
+ @file = @file.expand_path
20
+ @file_dir = @file.dirname.expand_path
25
21
  ensure_dir(@file_dir)
26
22
  ensure_file(@file)
27
23
  end
@@ -10,8 +10,6 @@ module Shelldon
10
10
  @file = Pathname.new(@file).expand_path
11
11
  hist = File.open(@file, 'r') { |f| f.read }.split("\n")
12
12
  hist.each do |line|
13
- # puts line
14
- # pp Readline::HISTORY.to_a
15
13
  Readline::HISTORY.push(line)
16
14
  end
17
15
  end
@@ -1,4 +1,3 @@
1
-
2
1
  module Shelldon
3
2
  class YamlManager < FileManager
4
3
  def ensure_file(file)
@@ -10,7 +9,17 @@ module Shelldon
10
9
  end
11
10
 
12
11
  def import(_yaml)
12
+ reset unless valid?
13
13
  YAML.load_file(@file)
14
14
  end
15
+
16
+ def valid?
17
+ File.exist?(@file) && !File.zero?(@file)
18
+ end
19
+
20
+ def reset
21
+ FileUtils.mv(@file, "#{@file}-#{Time.now.strftime('%y%m%d-%k%M%S')}.invalid")
22
+ ensure_file(@file)
23
+ end
15
24
  end
16
25
  end
@@ -0,0 +1,20 @@
1
+ module Shelldon
2
+ class Confirmation
3
+ def self.ask(*args)
4
+ new(*args).ask
5
+ end
6
+
7
+ def initialize(msg = 'Confirm? (y/n)',
8
+ ok = %w(y Y yes Yes YES))
9
+ @msg = msg
10
+ @ok = ok
11
+ end
12
+
13
+ def ask
14
+ puts @msg
15
+ print '> '
16
+ response = $stdin.gets.chomp
17
+ @ok.include?(response) ? true : fail(Shelldon::ConfirmationError)
18
+ end
19
+ end
20
+ end
@@ -1,5 +1,10 @@
1
1
  module Shelldon
2
2
  class Timer
3
+ def self.start
4
+ t = new
5
+ t.start
6
+ t
7
+ end
3
8
  def initialize(strftime = '%s')
4
9
  @strftime = strftime
5
10
  end
@@ -1,9 +1,10 @@
1
1
  module Shelldon
2
2
  class OptFactory
3
- def initialize(&block)
3
+ def initialize(name, &block)
4
+ @name = name
4
5
  @opt_arr = []
5
6
  instance_eval(&block)
6
- Shelldon.opts = get_opts
7
+ Shelldon.opts = get_opts if Shelldon.first?(@name)
7
8
  end
8
9
 
9
10
  def get_opts
@@ -23,7 +24,7 @@ module Shelldon
23
24
  when :required
24
25
  Getopt::REQUIRED
25
26
  else
26
- fail StandardError
27
+ fail Shelldon::NoSuchOptTypeError
27
28
  end
28
29
  end
29
30
  end
@@ -6,7 +6,7 @@ module Shelldon
6
6
  end
7
7
 
8
8
  def set(opts_arr)
9
- fail StandardError unless @opts.nil?
9
+ fail Shelldon::RedefineOptsError unless @opts.nil?
10
10
  @opts ||= opts_arr
11
11
  end
12
12
  end
@@ -1,11 +1,11 @@
1
- require 'byebug'
2
1
  require 'readline'
2
+ require_relative '../auto_complete'
3
+ # require 'byebug'
3
4
 
4
5
  module Shelldon
5
6
  class Shell
6
- attr_accessor :command_list, :config,
7
- :accept_errors, :reject_errors
8
- attr_reader :home, :name
7
+ attr_accessor :command_list, :config, :accept_errors, :reject_errors, :on_opts, :on_pipe
8
+ attr_reader :home, :name, :config, :logger
9
9
  attr_writer :history, :history_file
10
10
 
11
11
  def initialize(name, &block)
@@ -15,25 +15,39 @@ module Shelldon
15
15
  @errors = {}
16
16
  @history = true
17
17
  @command_list = CommandList.new(self)
18
- @config = Config.new(self)
18
+ @config = Shelldon::Config.new(self)
19
+ @autocomplete = Shelldon::AutoComplete.new(self) # if defined?(Shelldon::AutoComplete)
20
+ @on_opts = {}
19
21
  setup(&block) if block_given?
20
22
  end
21
23
 
24
+ def shell
25
+ self
26
+ end
27
+
22
28
  def self.method_missing(meth_name, *args, &block)
23
29
  Shelldon::ShellIndex[:default].send(meth_name, *args, &block)
24
30
  end
25
31
 
32
+ def self.[](key)
33
+ fail Shelldon::NoSuchShellError unless Shelldon::ShellIndex[key]
34
+ Shelldon::ShellIndex[key]
35
+ end
36
+
26
37
  def setup(&block)
27
38
  instance_eval(&block)
28
- FileUtils.mkdir_p(@home.to_s) unless File.exist?(@home)
39
+ FileUtils.mkdir_p(@home.to_s) unless File.exist?(@home) if @home
29
40
  Dir.chdir(@home) if @home
30
- Readline.completion_proc = proc { [] }
41
+ if @auto_complete_proc
42
+ Readline.completion_proc = @auto_complete_proc
43
+ else
44
+ @autocomplete.set_proc if @autocomplete
45
+ end
46
+
31
47
  if @history_path && @history
32
48
  @history_helper = Shelldon::HistoryFile.new(@history_path)
33
- @history_helper.load if @history_helper
34
49
  end
35
50
  @config.load_config_file
36
- run
37
51
  end
38
52
 
39
53
  def quit
@@ -42,35 +56,65 @@ module Shelldon
42
56
  exit 0
43
57
  end
44
58
 
59
+ def run_opt_conditions
60
+ @on_opts.each do |opt, procs|
61
+ if Shelldon.opts && Shelldon.opts.key?(opt)
62
+ procs.each do |proc|
63
+ instance_eval(&proc)
64
+ end
65
+ end
66
+ end
67
+ end
68
+
69
+ def handle_piped_input
70
+ return if $stdin.tty?
71
+ if @on_pipe
72
+ instance_exec($stdin.readlines, &@on_pipe)
73
+ else
74
+ $stdin.readlines.each { |cmd| run_commands(cmd) }
75
+ end
76
+ exit 0
77
+ end
78
+
45
79
  def run
80
+ @history_helper.load
81
+ run_opt_conditions
82
+ handle_piped_input
46
83
  instance_eval(&@startup) if @startup
47
84
  begin
48
85
  run_repl
49
86
  rescue *@accept_errors.keys => e
50
87
  print_error(e)
51
- on_error(e, @accept_errors[e.class])
88
+ @logger.warn(e)
89
+ on_error(e, @accept_errors[e.class], :accept)
52
90
  retry
53
91
  rescue *@reject_errors.keys => e
54
92
  print_error(e)
55
- on_error(e, @reject_errors[e.class])
93
+ @logger.fatal(e)
94
+ on_error(e, @reject_errors[e.class], :reject)
56
95
  rescue StandardError => e
57
96
  print_error(e)
58
97
  puts "Reached fatal error. G'bye!"
59
- raise e
60
98
  ensure
99
+ # puts "Last exception: #{$!.inspect}" #if @config[:debug_mode]
100
+ # puts "Last backtrace: \n#{$@.join("\n")}"# if @config[:debug_mode]
61
101
  instance_eval(&@shutdown) if @shutdown
62
102
  @history_helper.save if @history_helper
63
103
  quit
64
104
  end
65
105
  end
66
106
 
67
- def on_error(e, proc)
68
- instance_exec(e, &proc)
107
+ def on_error(e, proc, type = nil)
108
+ run_accept_error(e) if type == :accept
109
+ run_reject_error(e) if type == :reject
110
+ instance_exec(e, &proc) if proc
69
111
  end
70
112
 
71
113
  def print_error(e)
72
- return false unless @config[:debug_mode]
73
- puts e.message
114
+ return unless @config[:debug_mode]
115
+ puts "Hit Error! (#{e.class})"
116
+ msg = (e.message == e.class.to_s ? '' : "(#{e.message})")
117
+ puts msg unless msg == '()'
74
118
  puts e.backtrace.join("\n")
75
119
  end
76
120
 
@@ -101,7 +145,7 @@ module Shelldon
101
145
  end
102
146
 
103
147
  def run_command(cmd)
104
- @history_helper << cmd
148
+ @history_helper << cmd if @history_helper
105
149
  run_precommand(cmd)
106
150
  @command_list.run(cmd)
107
151
  run_postcommand(cmd)
@@ -115,6 +159,14 @@ module Shelldon
115
159
  instance_exec(cmd, &@post_command) if @post_command
116
160
  end
117
161
 
162
+ def run_accept_error(error)
163
+ instance_exec(error, &@on_accept_error) if @on_accept_error
164
+ end
165
+
166
+ def run_reject_error(error)
167
+ instance_exec(error, &@on_reject_error) if @on_reject_error
168
+ end
169
+
118
170
  def init(&block)
119
171
  instance_eval(&block)
120
172
  end
@@ -131,6 +183,11 @@ module Shelldon
131
183
  @history_path = file
132
184
  end
133
185
 
186
+ def log_file(filepath, freq = 'daily')
187
+ filepath = Pathname.new(filepath).expand_path.to_s
188
+ @logger = Logger.new(filepath, freq)
189
+ end
190
+
134
191
  def prompt(str = '> ', &block)
135
192
  if block_given?
136
193
  @prompt_setter = block
@@ -160,8 +217,14 @@ module Shelldon
160
217
  end
161
218
 
162
219
  def errors(&block)
163
- @accept_errors, @reject_errors =
164
- Shelldon::ErrorFactory.new(&block).get
220
+ error_factory = Shelldon::ErrorFactory.new(&block)
221
+ @accept_errors, @reject_errors = error_factory.get
222
+ @on_accept_error = error_factory.on_accept_error
223
+ @on_reject_error = error_factory.on_reject_error
224
+ end
225
+
226
+ def autocomplete(&block)
227
+ @auto_complete_proc = block.to_proc
165
228
  end
166
229
  end
167
230
  end