shelldon 0.0.7 → 0.0.8
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/.rbenv-gemsets +1 -0
- data/README.md +63 -88
- data/lib/command/command.rb +2 -0
- data/lib/command/command_list.rb +4 -1
- data/lib/config/config.rb +3 -2
- data/lib/config/config_factory.rb +3 -2
- data/lib/config/param.rb +2 -1
- data/lib/dsl.rb +25 -1
- data/lib/exceptions/exceptions.rb +19 -0
- data/lib/index.rb +40 -0
- data/lib/module/module.rb +43 -0
- data/lib/module/module_factory.rb +33 -0
- data/lib/module/module_index.rb +16 -0
- data/lib/shell/shell.rb +11 -3
- data/lib/shell/shell_factory.rb +31 -1
- data/lib/shell/shell_factory_index.rb +16 -0
- data/lib/shell/shell_index.rb +4 -30
- data/lib/shelldon.rb +5 -0
- data/lib/shelldon/version.rb +1 -1
- data/test_shell/dependency_test/dependency_test.rb +2 -1
- data/test_shell/dependency_test/dt_config.rb +0 -6
- data/test_shell/dependency_test/dt_runner.rb +21 -2
- data/test_shell/dependency_test/test_module.rb +16 -0
- data/test_shell/simple_shell.rb +1 -1
- data/test_shell/simplest_shell.rb +12 -0
- data/test_shell/test_shell.rb +1 -1
- metadata +11 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0c0b0a7f5f6649588679a69a1173b3fbb8908cc7
|
4
|
+
data.tar.gz: b71f5389f97fd747ed80973fbf14993ffc88cc4d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 23f12ce391adccd268f03d11fbcf48496956b9f4428f95cf31591e3456c111edd9c72f3330c724f48e1c253e0c5a4a09b29a45295453797524ae4d821ae119b4
|
7
|
+
data.tar.gz: c22ce281321e342ae0345a051eadd38cb2d0563f3e1bcc240321ec3de3262bbf95bd411bef116f6931586cbb619ab9997bda8f7c8e219c42b0b7092313987e63
|
data/.rbenv-gemsets
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
-global
|
data/README.md
CHANGED
@@ -1,4 +1,6 @@
|
|
1
|
-
# Shelldon
|
1
|
+
# <img src="http://www.wesleyboynton.com/wp-content/uploads/2016/04/shelldon.png" width="100"> Shelldon
|
2
|
+
|
3
|
+
[](https://badge.fury.io/rb/shelldon)
|
2
4
|
|
3
5
|
Shelldon is an expressive DSL for building interactive terminal applications, or REPLs (Read-Evaluate-Print-Loops).
|
4
6
|
|
@@ -16,116 +18,89 @@ Or just `gem install shelldon` -- You know the drill.
|
|
16
18
|
|
17
19
|
## Usage
|
18
20
|
|
19
|
-
Here's a
|
21
|
+
Shelldon is made to be dead-simple to use. Here's a breakdown of the usage!
|
20
22
|
|
21
|
-
|
22
|
-
require 'shelldon'
|
23
|
-
require 'pp'
|
23
|
+
Start defining a shell like this:
|
24
24
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
25
|
+
``` ruby
|
26
|
+
Shelldon.shell :example do
|
27
|
+
end
|
28
|
+
Shelldon.run(:example)
|
29
29
|
|
30
|
-
|
31
|
-
# Set the config file, which can hold values one level higher than their default
|
32
|
-
# The order of precedence for params is: Set in-session > set by command-line flag > set by config file > default
|
33
|
-
config_file '.my-config-file'
|
30
|
+
```
|
34
31
|
|
35
|
-
|
36
|
-
type :boolean # Make it a boolean
|
37
|
-
default false # Make its default value false
|
38
|
-
opt 'myopt' # Override it with the value of command-line opt '--myopt' if present
|
39
|
-
end
|
40
|
-
end
|
32
|
+
### Commands
|
41
33
|
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
action do |args|
|
53
|
-
tokens = args.split(' ')
|
54
|
-
config[tokens[0].to_sym] = tokens[1]
|
55
|
-
end
|
34
|
+
Define a command with a `command` block:
|
35
|
+
|
36
|
+
``` ruby
|
37
|
+
Shelldon.shell :example do
|
38
|
+
command :test do
|
39
|
+
aliased 'test_command'
|
40
|
+
help "Run a test command to show some text. Optionally, add an arg."
|
41
|
+
usage "test"
|
42
|
+
examples ['test', 'test blah']
|
43
|
+
action { |arg = ''| puts "This is a test! #{arg}" }
|
56
44
|
end
|
45
|
+
end
|
46
|
+
Shelldon.run(:example)
|
57
47
|
|
48
|
+
```
|
58
49
|
|
59
|
-
|
60
|
-
command :arg do
|
61
|
-
help 'Show your args off!'
|
62
|
-
action { |args| puts args }
|
63
|
-
end
|
50
|
+
### Sub-Commands
|
64
51
|
|
65
|
-
|
66
|
-
# show the value of a specific option if called with an argument
|
67
|
-
command :config do
|
68
|
-
help 'Show the configuration of the current session.'
|
69
|
-
usage 'config'
|
70
|
-
action do |args|
|
71
|
-
if args.empty?
|
72
|
-
pp config.to_a
|
73
|
-
else
|
74
|
-
param = config.find(args.to_sym)
|
75
|
-
puts "#{param.name}: #{param.val}"
|
76
|
-
end
|
77
|
-
end
|
52
|
+
You can nest commands into other commands with the `subcommand` block. This is great for organizing functionality. You can retain the functionality of your higher-level commands, or if you want a higher-level command to act as a placeholder you can just tell Shelldon so!
|
78
53
|
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
54
|
+
For instance, you could run the command `test foobar` like this:
|
55
|
+
``` ruby
|
56
|
+
command :test do
|
57
|
+
placeholder
|
58
|
+
|
59
|
+
subcommand :foobar do
|
60
|
+
help "Print out 'Foobar!'"
|
61
|
+
action {puts "Foobar!"}
|
85
62
|
end
|
86
63
|
end
|
64
|
+
```
|
87
65
|
|
66
|
+
### Default Command ("No Such Command Found")
|
67
|
+
You can use the `command_missing` block to define behaviour when a command isn't explicitly registered. This can be anything from writing "No Such Command" to doing a similarity-search to passing the command to some other resource.
|
88
68
|
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
help 'Show help. Optionally specify specific command for more information.'
|
95
|
-
usage 'help [cmd]'
|
96
|
-
examples ['help', 'help quit']
|
97
|
-
end
|
98
|
-
|
99
|
-
# Define a default command - This is what happens when a command doesn't match up
|
100
|
-
command_missing do
|
101
|
-
action { |cmd| puts "No such command \"#{cmd}\"" }
|
102
|
-
end
|
69
|
+
``` ruby
|
70
|
+
command_missing do
|
71
|
+
action { |cmd| puts "No such command \"#{cmd}\"" }
|
72
|
+
end
|
73
|
+
```
|
103
74
|
|
104
|
-
|
105
|
-
|
106
|
-
# You can make your prompt a string or a block
|
107
|
-
prompt 'shelldon> ' # This is okay
|
108
|
-
prompt { "shelldon#{4+2}>" } # This is okay too
|
75
|
+
### Configuration
|
76
|
+
What good is a shell without config? The `config` block will allow you to set up parameters, validate and adjust input, set a configuration yml file, and interact with command-line opts.
|
109
77
|
|
110
|
-
|
111
|
-
home '~/.shelldon-test'
|
78
|
+
Here's an example that implements the bash 'set -o vi/emacs' functionality in the shell
|
112
79
|
|
113
|
-
|
114
|
-
history true
|
80
|
+
``` ruby
|
115
81
|
|
116
|
-
|
117
|
-
|
82
|
+
config do
|
83
|
+
config_file '.shelldon_config'
|
118
84
|
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
85
|
+
param :'-o' do
|
86
|
+
type :string
|
87
|
+
default 'emacs'
|
88
|
+
# adjust runs before validate, and can 'fix' your input. In this case, allow 'vim' for 'vi'
|
89
|
+
adjust { |s| s.to_s.downcase.strip.gsub('vim', 'vi') }
|
90
|
+
# validate looks for a 'true' result, but in this case we're also using it to take action
|
91
|
+
validate do |s|
|
92
|
+
return false unless s == 'emacs' || s == 'vi'
|
93
|
+
if s == 'emacs'
|
94
|
+
Readline.emacs_editing_mode; true
|
95
|
+
else
|
96
|
+
Readline.vi_editing_mode; true
|
97
|
+
end
|
125
98
|
end
|
126
99
|
end
|
127
100
|
end
|
128
101
|
```
|
102
|
+
|
103
|
+
|
129
104
|
## Contributing
|
130
105
|
Bug reports and pull requests are welcome on GitHub at https://github.com/wwboynton/shelldon.
|
131
106
|
|
data/lib/command/command.rb
CHANGED
data/lib/command/command_list.rb
CHANGED
@@ -56,7 +56,10 @@ module Shelldon
|
|
56
56
|
else
|
57
57
|
cmd = find(str).first
|
58
58
|
if cmd.show && !is_default?(cmd)
|
59
|
-
|
59
|
+
subcommands = cmd.sub_to_a
|
60
|
+
res = [compile_help(cmd).values]
|
61
|
+
res << subcommands unless subcommands.empty?
|
62
|
+
res
|
60
63
|
else
|
61
64
|
fail Shelldon::NoSuchCommandError
|
62
65
|
end
|
data/lib/config/config.rb
CHANGED
@@ -17,7 +17,7 @@ module Shelldon
|
|
17
17
|
end
|
18
18
|
|
19
19
|
def setup
|
20
|
-
load_config_file
|
20
|
+
load_config_file if @config_file_manager
|
21
21
|
end
|
22
22
|
|
23
23
|
def toggle(key)
|
@@ -73,7 +73,8 @@ module Shelldon
|
|
73
73
|
hash.each do |k, v|
|
74
74
|
key = k.to_sym
|
75
75
|
if @config.key?(key)
|
76
|
-
set(key, v) unless @config[key].override ||
|
76
|
+
set(key, v) unless @config[key].override ||
|
77
|
+
(Shelldon.opts &&Shelldon.opts.key?(@config[key].opt))
|
77
78
|
else
|
78
79
|
fail(Shelldon::NoSuchParamError)
|
79
80
|
end
|
@@ -9,8 +9,9 @@ module Shelldon
|
|
9
9
|
end
|
10
10
|
|
11
11
|
def initialize(shell, &block)
|
12
|
-
@shell
|
13
|
-
@config
|
12
|
+
@shell = shell
|
13
|
+
@shell.config ||= Shelldon::Config.new(@shell)
|
14
|
+
@config = @shell.config
|
14
15
|
instance_eval(&block)
|
15
16
|
@shell.config = @config
|
16
17
|
end
|
data/lib/config/param.rb
CHANGED
@@ -15,7 +15,8 @@ module Shelldon
|
|
15
15
|
def val
|
16
16
|
return @val if @val
|
17
17
|
return @override if @override
|
18
|
-
|
18
|
+
return @default unless Shelldon.opts
|
19
|
+
@val = Shelldon.opts.has_key?(@opt) ? Shelldon.opts[@opt] : @default
|
19
20
|
end
|
20
21
|
|
21
22
|
def val=(value)
|
data/lib/dsl.rb
CHANGED
@@ -12,7 +12,11 @@ module Shelldon
|
|
12
12
|
end
|
13
13
|
|
14
14
|
def self.shell(name = (:default), &block)
|
15
|
-
|
15
|
+
if shell_factory_index.has_key?(name)
|
16
|
+
shell_factory_index[name].load(&block)
|
17
|
+
else
|
18
|
+
ShellFactory.new(name.to_sym, &block)
|
19
|
+
end
|
16
20
|
end
|
17
21
|
|
18
22
|
def self.opts=(opts_arr)
|
@@ -35,4 +39,24 @@ module Shelldon
|
|
35
39
|
sym = sym.to_sym unless sym
|
36
40
|
ShellIndex.instance.key?(sym)
|
37
41
|
end
|
42
|
+
|
43
|
+
def self.module(name, &block)
|
44
|
+
ModuleFactory.new(name.to_sym, &block)
|
45
|
+
end
|
46
|
+
|
47
|
+
def self.module_index
|
48
|
+
Shelldon::ModuleIndex.instance
|
49
|
+
end
|
50
|
+
|
51
|
+
def self.modules
|
52
|
+
module_index
|
53
|
+
end
|
54
|
+
|
55
|
+
def self.shell_factory_index
|
56
|
+
Shelldon::ShellFactoryIndex.instance
|
57
|
+
end
|
58
|
+
|
59
|
+
def self.run(shell_name = (:default))
|
60
|
+
shell_factory_index[shell_name].run
|
61
|
+
end
|
38
62
|
end
|
@@ -1,5 +1,8 @@
|
|
1
1
|
module Shelldon
|
2
2
|
class Error < StandardError
|
3
|
+
def initialize(msg = nil)
|
4
|
+
@msg = msg
|
5
|
+
end
|
3
6
|
end
|
4
7
|
|
5
8
|
class ConfirmationError < Error
|
@@ -54,6 +57,22 @@ module Shelldon
|
|
54
57
|
define_method(:message) { 'Cannot add non-shells to the shell index' }
|
55
58
|
end
|
56
59
|
|
60
|
+
class NotAShellFactoryError < Error
|
61
|
+
define_method(:message) { 'Cannot add non-shell-factories to the shell factory index' }
|
62
|
+
end
|
63
|
+
|
64
|
+
class NotAModuleError < Error
|
65
|
+
define_method(:message) { 'Cannot add non-modules to the module index' }
|
66
|
+
end
|
67
|
+
|
68
|
+
class NoSuchModuleError < Error
|
69
|
+
define_method(:message) { "No such module #{@msg} found." }
|
70
|
+
end
|
71
|
+
|
72
|
+
class DuplicateIndexError < Error
|
73
|
+
define_method(:message) { 'There is already an object with that name in the index' }
|
74
|
+
end
|
75
|
+
|
57
76
|
class TimeoutError < Error
|
58
77
|
define_method(:message) { 'Operation timed out.' }
|
59
78
|
end
|
data/lib/index.rb
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
module Shelldon
|
2
|
+
class Index
|
3
|
+
include Singleton
|
4
|
+
|
5
|
+
def self.method_missing(meth_name, *args, &block)
|
6
|
+
if block_given?
|
7
|
+
instance.send(meth_name, *args, &block)
|
8
|
+
else
|
9
|
+
instance.send(meth_name, *args)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def initialize
|
14
|
+
@index = {}
|
15
|
+
end
|
16
|
+
|
17
|
+
def [](key)
|
18
|
+
@index[key.to_sym]
|
19
|
+
end
|
20
|
+
|
21
|
+
def []=(key, val)
|
22
|
+
@index[key.to_sym] = val
|
23
|
+
end
|
24
|
+
|
25
|
+
def has_key?(key)
|
26
|
+
@index.key?(key)
|
27
|
+
end
|
28
|
+
|
29
|
+
def <<(obj)
|
30
|
+
@first = obj.name if @index.empty?
|
31
|
+
fail Shelldon::DuplicateIndexError if @index.key?(obj.name)
|
32
|
+
@index[obj.name] = obj
|
33
|
+
end
|
34
|
+
|
35
|
+
def first?(sym)
|
36
|
+
sym = sym.to_sym unless sym.is_a?(Symbol)
|
37
|
+
sym == @first
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module Shelldon
|
2
|
+
class Module
|
3
|
+
attr_reader :name
|
4
|
+
def initialize(name)
|
5
|
+
@name = name.to_sym
|
6
|
+
@commands = []
|
7
|
+
@configs = []
|
8
|
+
@shell_blocks = []
|
9
|
+
@command_missing = []
|
10
|
+
end
|
11
|
+
|
12
|
+
def add_command(name, lambda)
|
13
|
+
@commands << [name, lambda]
|
14
|
+
end
|
15
|
+
|
16
|
+
def add_config(lambda)
|
17
|
+
@configs << lambda
|
18
|
+
end
|
19
|
+
|
20
|
+
def add_shell_block(lambda)
|
21
|
+
@shell_blocks << lambda
|
22
|
+
end
|
23
|
+
|
24
|
+
def add_command_missing(lambda)
|
25
|
+
@command_missing[0] = lambda
|
26
|
+
end
|
27
|
+
|
28
|
+
def install(shell_name)
|
29
|
+
@commands.each do |(name, lambda)|
|
30
|
+
Shelldon.shell(shell_name) { command(name, &lambda.to_proc) }
|
31
|
+
end
|
32
|
+
@configs.each do |lambda|
|
33
|
+
Shelldon.shell(shell_name) { config(&lambda.to_proc) }
|
34
|
+
end
|
35
|
+
@shell_blocks.each do |lambda|
|
36
|
+
Shelldon.shell(shell_name) { shell(&lambda.to_proc) }
|
37
|
+
end
|
38
|
+
@command_missing.each do |lambda|
|
39
|
+
Shelldon.shell(shell_name) { command_missing(&lambda.to_proc) }
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module Shelldon
|
2
|
+
class ModuleFactory
|
3
|
+
def initialize(name, &block)
|
4
|
+
@name = name
|
5
|
+
register Shelldon::Module.new(name) unless Shelldon.modules.has_key?(name)
|
6
|
+
instance_exec(@name, &block.to_proc)
|
7
|
+
end
|
8
|
+
|
9
|
+
def this_module
|
10
|
+
Shelldon.modules[@name]
|
11
|
+
end
|
12
|
+
|
13
|
+
def command(name, &block)
|
14
|
+
this_module.add_command(name, block)
|
15
|
+
end
|
16
|
+
|
17
|
+
def config(&block)
|
18
|
+
this_module.add_config(block)
|
19
|
+
end
|
20
|
+
|
21
|
+
def shell(&block)
|
22
|
+
this_module.add_shell_block(block)
|
23
|
+
end
|
24
|
+
|
25
|
+
def command_missing(&block)
|
26
|
+
this_module.add_command_missing(block)
|
27
|
+
end
|
28
|
+
|
29
|
+
def register(mod)
|
30
|
+
Shelldon.modules << mod
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# This allows subshelling - You can define multiple shells in one program and nest them.
|
2
|
+
# This is the opposite approach to shell-as-singleton, which makes access easy but prevents multiple shells.
|
3
|
+
# This is why all of the factories pass the shell parent into their respective products.
|
4
|
+
|
5
|
+
module Shelldon
|
6
|
+
class ModuleIndex < Index
|
7
|
+
def <<(mod)
|
8
|
+
if mod.is_a?(Shelldon::Module)
|
9
|
+
fail Shelldon::DuplicateIndexError if @index.key?(mod.name)
|
10
|
+
@index[mod.name] = mod
|
11
|
+
else
|
12
|
+
fail Shelldon::NotAModuleError
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
data/lib/shell/shell.rb
CHANGED
@@ -77,7 +77,7 @@ module Shelldon
|
|
77
77
|
end
|
78
78
|
|
79
79
|
def run
|
80
|
-
@history_helper.load
|
80
|
+
@history_helper.load if @history_helper
|
81
81
|
run_opt_conditions
|
82
82
|
handle_piped_input
|
83
83
|
instance_eval(&@startup) if @startup
|
@@ -85,12 +85,12 @@ module Shelldon
|
|
85
85
|
run_repl
|
86
86
|
rescue *@accept_errors.keys => e
|
87
87
|
print_error(e)
|
88
|
-
|
88
|
+
log_warn(e)
|
89
89
|
on_error(e, @accept_errors[e.class], :accept)
|
90
90
|
retry
|
91
91
|
rescue *@reject_errors.keys => e
|
92
92
|
print_error(e)
|
93
|
-
|
93
|
+
log_fatal(e)
|
94
94
|
on_error(e, @reject_errors[e.class], :reject)
|
95
95
|
rescue StandardError => e
|
96
96
|
print_error(e)
|
@@ -104,6 +104,14 @@ module Shelldon
|
|
104
104
|
end
|
105
105
|
end
|
106
106
|
|
107
|
+
def log_warn(e)
|
108
|
+
@logger.warn(e) if @logger
|
109
|
+
end
|
110
|
+
|
111
|
+
def log_fatal(e)
|
112
|
+
@logger.fatal(e) if @logger
|
113
|
+
end
|
114
|
+
|
107
115
|
def on_error(e, proc, type = nil)
|
108
116
|
run_accept_error(e) if type == :accept
|
109
117
|
run_reject_error(e) if type == :reject
|
data/lib/shell/shell_factory.rb
CHANGED
@@ -1,14 +1,21 @@
|
|
1
1
|
module Shelldon
|
2
2
|
class ShellFactory
|
3
|
+
attr_reader :name
|
4
|
+
|
3
5
|
def initialize(name, &block)
|
4
6
|
@name = name
|
7
|
+
Shelldon.shell_factory_index << self
|
5
8
|
setup_vars
|
6
9
|
register(Shell.new(name)) unless Shelldon[name]
|
10
|
+
load(&block)
|
11
|
+
end
|
12
|
+
|
13
|
+
def load(&block)
|
7
14
|
instance_eval(&block)
|
8
|
-
make_it_rain
|
9
15
|
end
|
10
16
|
|
11
17
|
def setup_vars
|
18
|
+
@modules = []
|
12
19
|
@new_opts = []
|
13
20
|
@new_configs = []
|
14
21
|
@new_on_opts = []
|
@@ -16,9 +23,16 @@ module Shelldon
|
|
16
23
|
@new_script_dirs = []
|
17
24
|
end
|
18
25
|
|
26
|
+
def run
|
27
|
+
make_it_rain
|
28
|
+
Shelldon[@name].run
|
29
|
+
end
|
30
|
+
|
19
31
|
def make_it_rain
|
32
|
+
install_modules
|
20
33
|
make_opts
|
21
34
|
make_configs
|
35
|
+
this_shell.config.setup
|
22
36
|
make_on_opts
|
23
37
|
make_commands
|
24
38
|
make_scripts
|
@@ -62,6 +76,22 @@ module Shelldon
|
|
62
76
|
|
63
77
|
alias_method :scripts, :script
|
64
78
|
|
79
|
+
def modules(mods)
|
80
|
+
mods = [mods] unless mods.is_a?(Array)
|
81
|
+
@modules += mods.map(&:to_sym)
|
82
|
+
end
|
83
|
+
|
84
|
+
def install_modules
|
85
|
+
@modules.each do |mod_name|
|
86
|
+
if Shelldon.modules.has_key?(mod_name)
|
87
|
+
Shelldon.modules[mod_name].install(@name)
|
88
|
+
else
|
89
|
+
raise Shelldon::NoSuchModuleError mod_name
|
90
|
+
end
|
91
|
+
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
65
95
|
def config(&block)
|
66
96
|
@new_configs << block
|
67
97
|
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# This allows subshelling - You can define multiple shells in one program and nest them.
|
2
|
+
# This is the opposite approach to shell-as-singleton, which makes access easy but prevents multiple shells.
|
3
|
+
# This is why all of the factories pass the shell parent into their respective products.
|
4
|
+
|
5
|
+
module Shelldon
|
6
|
+
class ShellFactoryIndex < Index
|
7
|
+
def <<(shell_factory)
|
8
|
+
if shell_factory.is_a?(Shelldon::ShellFactory)
|
9
|
+
fail Shelldon::DuplicateIndexError if @index.key?(shell_factory.name)
|
10
|
+
@index[shell_factory.name] = shell_factory
|
11
|
+
else
|
12
|
+
fail Shelldon::NotAShellFactoryError
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
data/lib/shell/shell_index.rb
CHANGED
@@ -3,41 +3,15 @@
|
|
3
3
|
# This is why all of the factories pass the shell parent into their respective products.
|
4
4
|
|
5
5
|
module Shelldon
|
6
|
-
class ShellIndex
|
7
|
-
include Singleton
|
8
|
-
|
9
|
-
def self.method_missing(meth_name, *args, &block)
|
10
|
-
if block_given?
|
11
|
-
instance.send(meth_name, *args, &block)
|
12
|
-
else
|
13
|
-
instance.send(meth_name, *args)
|
14
|
-
end
|
15
|
-
end
|
16
|
-
|
17
|
-
def initialize
|
18
|
-
@shell_index = {}
|
19
|
-
end
|
20
|
-
|
21
|
-
def [](key)
|
22
|
-
@shell_index[key.to_sym]
|
23
|
-
end
|
24
|
-
|
25
|
-
def has_key?(key)
|
26
|
-
@shell_index.key?(key)
|
27
|
-
end
|
28
|
-
|
6
|
+
class ShellIndex < Index
|
29
7
|
def <<(shell)
|
30
8
|
if shell.is_a?(Shelldon::Shell)
|
31
|
-
|
32
|
-
@
|
9
|
+
fail Shelldon::DuplicateIndexError if @index.key?(shell.name)
|
10
|
+
@first = shell.name if @index.empty?
|
11
|
+
@index[shell.name] = shell
|
33
12
|
else
|
34
13
|
fail Shelldon::NotAShellError
|
35
14
|
end
|
36
15
|
end
|
37
|
-
|
38
|
-
def first?(sym)
|
39
|
-
sym = sym.to_sym unless sym.is_a?(Symbol)
|
40
|
-
sym == @first
|
41
|
-
end
|
42
16
|
end
|
43
17
|
end
|
data/lib/shelldon.rb
CHANGED
@@ -4,9 +4,14 @@ require 'readline'
|
|
4
4
|
require 'getopt/long'
|
5
5
|
require 'yaml'
|
6
6
|
require 'fuzzy_match'
|
7
|
+
require 'index'
|
7
8
|
require 'shell/shell_index'
|
9
|
+
require 'shell/shell_factory_index'
|
8
10
|
require 'dsl'
|
9
11
|
require 'shell/shell'
|
12
|
+
require 'module/module'
|
13
|
+
require 'module/module_factory'
|
14
|
+
require 'module/module_index'
|
10
15
|
require 'config/config'
|
11
16
|
require 'config/param'
|
12
17
|
require 'config/param/string_param'
|
data/lib/shelldon/version.rb
CHANGED
@@ -1,11 +1,30 @@
|
|
1
1
|
# This is a split-up version of the test_shell.rb
|
2
2
|
# It exists so you can screw around with when the different parts are required and ensure that
|
3
|
-
# the order doesn't matter.
|
3
|
+
# the order doesn't matter and multiple blocks of the same type all load in correctly.
|
4
4
|
|
5
5
|
require 'shelldon'
|
6
6
|
require_relative 'dependency_test'
|
7
7
|
require_relative 'dt_commands'
|
8
8
|
require_relative 'dt_opts'
|
9
9
|
require_relative 'dt_config'
|
10
|
+
require_relative 'test_module'
|
10
11
|
|
11
|
-
Shelldon
|
12
|
+
Shelldon.shell :test do
|
13
|
+
command :superderp do
|
14
|
+
action { puts 'beh' }
|
15
|
+
help 'test'
|
16
|
+
end
|
17
|
+
|
18
|
+
config do
|
19
|
+
param :value do
|
20
|
+
type :string
|
21
|
+
default 'This is the default value!'
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
shell do
|
26
|
+
prompt 'shelldon> '
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
Shelldon.run(:test)
|
data/test_shell/simple_shell.rb
CHANGED
@@ -0,0 +1,12 @@
|
|
1
|
+
require 'shelldon'
|
2
|
+
|
3
|
+
Shelldon.shell :example do
|
4
|
+
command :test do
|
5
|
+
help "Run a test command to show some text. Optionally, add an arg."
|
6
|
+
usage "test"
|
7
|
+
examples ['test', 'test blah']
|
8
|
+
action { |arg = ''| puts "This is a test! #{arg}" }
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
Shelldon.run(:example)
|
data/test_shell/test_shell.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: shelldon
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.8
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Wesley Boynton
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-
|
11
|
+
date: 2016-09-24 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: getopt
|
@@ -91,6 +91,7 @@ extensions: []
|
|
91
91
|
extra_rdoc_files: []
|
92
92
|
files:
|
93
93
|
- ".gitignore"
|
94
|
+
- ".rbenv-gemsets"
|
94
95
|
- ".rubocop.yml"
|
95
96
|
- Gemfile
|
96
97
|
- LICENSE.txt
|
@@ -120,10 +121,15 @@ files:
|
|
120
121
|
- lib/file_management/yaml_manager.rb
|
121
122
|
- lib/helpers/confirmation.rb
|
122
123
|
- lib/helpers/timer.rb
|
124
|
+
- lib/index.rb
|
125
|
+
- lib/module/module.rb
|
126
|
+
- lib/module/module_factory.rb
|
127
|
+
- lib/module/module_index.rb
|
123
128
|
- lib/opts/opt_factory.rb
|
124
129
|
- lib/opts/opts.rb
|
125
130
|
- lib/shell/shell.rb
|
126
131
|
- lib/shell/shell_factory.rb
|
132
|
+
- lib/shell/shell_factory_index.rb
|
127
133
|
- lib/shell/shell_index.rb
|
128
134
|
- lib/shelldon.rb
|
129
135
|
- lib/shelldon/version.rb
|
@@ -137,8 +143,10 @@ files:
|
|
137
143
|
- test_shell/dependency_test/dt_config.rb
|
138
144
|
- test_shell/dependency_test/dt_opts.rb
|
139
145
|
- test_shell/dependency_test/dt_runner.rb
|
146
|
+
- test_shell/dependency_test/test_module.rb
|
140
147
|
- test_shell/run.sh
|
141
148
|
- test_shell/simple_shell.rb
|
149
|
+
- test_shell/simplest_shell.rb
|
142
150
|
- test_shell/test_shell.rb
|
143
151
|
- test_shell/useful_commands.rb
|
144
152
|
homepage: https://github.com/wwboynton/shelldon
|
@@ -162,7 +170,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
162
170
|
version: '0'
|
163
171
|
requirements: []
|
164
172
|
rubyforge_project:
|
165
|
-
rubygems_version: 2.4.5
|
173
|
+
rubygems_version: 2.4.5.1
|
166
174
|
signing_key:
|
167
175
|
specification_version: 4
|
168
176
|
summary: An expressive DSL for building interactive command-line apps
|