shell_shock 0.0.5 → 0.0.6
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 +7 -0
- data/.gitignore +2 -0
- data/.rubocop.yml +48 -0
- data/.tool-versions +1 -0
- data/Gemfile +12 -0
- data/Gemfile.lock +117 -0
- data/Rakefile +12 -0
- data/example/adventure.rb +37 -33
- data/example/file_system.rb +31 -27
- data/lib/shell_shock/command_spec.rb +10 -8
- data/lib/shell_shock/context.rb +18 -16
- data/lib/shell_shock/exit_command.rb +8 -6
- data/lib/shell_shock/help_command.rb +11 -8
- data/lib/shell_shock/logger.rb +8 -5
- data/shell_shock.gemspec +27 -0
- metadata +35 -94
- data/example/cat.rb +0 -66
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: a473df32bae252fade36508e5e0f9d3c33d0ddf54ee9c29470458fbb6c04d0e2
|
4
|
+
data.tar.gz: 15050e03f392c29fd8a68c5e06e7f2c55a8338cf71471442a28c3c806df4a088
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: a417ea53a0345722e9d095b39632f2e12a5a96553a82e35bbf82aeb9a331d232ff27f16dc866aaa7dcf83e28b15c452bac1722a298c75aa5436122ff32b9c5fb
|
7
|
+
data.tar.gz: 2a827992f1aa325bb18b62f6cc95fc454072e10603b2dd6e53eb0b9662f2f92966f91185811f104a360b41847cd18cefe10f772c28f2360197c1a6e0fe46ecec
|
data/.gitignore
ADDED
data/.rubocop.yml
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
require:
|
2
|
+
- rubocop-rspec
|
3
|
+
- rubocop-rake
|
4
|
+
|
5
|
+
AllCops:
|
6
|
+
TargetRubyVersion: 3.0
|
7
|
+
NewCops: enable
|
8
|
+
|
9
|
+
Style/StringLiterals:
|
10
|
+
Enabled: true
|
11
|
+
EnforcedStyle: double_quotes
|
12
|
+
|
13
|
+
Style/StringLiteralsInInterpolation:
|
14
|
+
Enabled: true
|
15
|
+
EnforcedStyle: double_quotes
|
16
|
+
|
17
|
+
Layout/LineLength:
|
18
|
+
Max: 120
|
19
|
+
|
20
|
+
Style/Documentation:
|
21
|
+
Enabled: false
|
22
|
+
|
23
|
+
Metrics/MethodLength:
|
24
|
+
Enabled: false
|
25
|
+
|
26
|
+
Metrics/BlockLength:
|
27
|
+
Enabled: false
|
28
|
+
|
29
|
+
Metrics/AbcSize:
|
30
|
+
Enabled: false
|
31
|
+
|
32
|
+
Metrics/PerceivedComplexity:
|
33
|
+
Enabled: false
|
34
|
+
|
35
|
+
Metrics/CyclomaticComplexity:
|
36
|
+
Enabled: false
|
37
|
+
|
38
|
+
RSpec/InstanceVariable:
|
39
|
+
Enabled: false
|
40
|
+
|
41
|
+
RSpec/ExampleLength:
|
42
|
+
Enabled: false
|
43
|
+
|
44
|
+
RSpec/VerifiedDoubles:
|
45
|
+
Enabled: false
|
46
|
+
|
47
|
+
RSpec/MultipleExpectations:
|
48
|
+
Enabled: false
|
data/.tool-versions
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
ruby 3.3.4
|
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,117 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
shell_shock (0.0.6)
|
5
|
+
|
6
|
+
GEM
|
7
|
+
remote: https://rubygems.org/
|
8
|
+
specs:
|
9
|
+
ast (2.4.2)
|
10
|
+
backport (1.2.0)
|
11
|
+
benchmark (0.3.0)
|
12
|
+
diff-lcs (1.5.1)
|
13
|
+
e2mmap (0.1.0)
|
14
|
+
jaro_winkler (1.6.0)
|
15
|
+
json (2.7.2)
|
16
|
+
kramdown (2.4.0)
|
17
|
+
rexml
|
18
|
+
kramdown-parser-gfm (1.1.0)
|
19
|
+
kramdown (~> 2.0)
|
20
|
+
language_server-protocol (3.17.0.3)
|
21
|
+
nokogiri (1.16.6-aarch64-linux)
|
22
|
+
racc (~> 1.4)
|
23
|
+
nokogiri (1.16.6-arm-linux)
|
24
|
+
racc (~> 1.4)
|
25
|
+
nokogiri (1.16.6-arm64-darwin)
|
26
|
+
racc (~> 1.4)
|
27
|
+
nokogiri (1.16.6-x86-linux)
|
28
|
+
racc (~> 1.4)
|
29
|
+
nokogiri (1.16.6-x86_64-darwin)
|
30
|
+
racc (~> 1.4)
|
31
|
+
nokogiri (1.16.6-x86_64-linux)
|
32
|
+
racc (~> 1.4)
|
33
|
+
parallel (1.25.1)
|
34
|
+
parser (3.3.4.0)
|
35
|
+
ast (~> 2.4.1)
|
36
|
+
racc
|
37
|
+
racc (1.8.0)
|
38
|
+
rainbow (3.1.1)
|
39
|
+
rake (13.2.1)
|
40
|
+
rbs (2.8.4)
|
41
|
+
regexp_parser (2.9.2)
|
42
|
+
reverse_markdown (2.1.1)
|
43
|
+
nokogiri
|
44
|
+
rexml (3.3.2)
|
45
|
+
strscan
|
46
|
+
rspec (3.13.0)
|
47
|
+
rspec-core (~> 3.13.0)
|
48
|
+
rspec-expectations (~> 3.13.0)
|
49
|
+
rspec-mocks (~> 3.13.0)
|
50
|
+
rspec-core (3.13.0)
|
51
|
+
rspec-support (~> 3.13.0)
|
52
|
+
rspec-expectations (3.13.1)
|
53
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
54
|
+
rspec-support (~> 3.13.0)
|
55
|
+
rspec-mocks (3.13.1)
|
56
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
57
|
+
rspec-support (~> 3.13.0)
|
58
|
+
rspec-support (3.13.1)
|
59
|
+
rubocop (1.65.0)
|
60
|
+
json (~> 2.3)
|
61
|
+
language_server-protocol (>= 3.17.0)
|
62
|
+
parallel (~> 1.10)
|
63
|
+
parser (>= 3.3.0.2)
|
64
|
+
rainbow (>= 2.2.2, < 4.0)
|
65
|
+
regexp_parser (>= 2.4, < 3.0)
|
66
|
+
rexml (>= 3.2.5, < 4.0)
|
67
|
+
rubocop-ast (>= 1.31.1, < 2.0)
|
68
|
+
ruby-progressbar (~> 1.7)
|
69
|
+
unicode-display_width (>= 2.4.0, < 3.0)
|
70
|
+
rubocop-ast (1.31.3)
|
71
|
+
parser (>= 3.3.1.0)
|
72
|
+
rubocop-rake (0.6.0)
|
73
|
+
rubocop (~> 1.0)
|
74
|
+
rubocop-rspec (3.0.3)
|
75
|
+
rubocop (~> 1.61)
|
76
|
+
ruby-progressbar (1.13.0)
|
77
|
+
solargraph (0.50.0)
|
78
|
+
backport (~> 1.2)
|
79
|
+
benchmark
|
80
|
+
bundler (~> 2.0)
|
81
|
+
diff-lcs (~> 1.4)
|
82
|
+
e2mmap
|
83
|
+
jaro_winkler (~> 1.5)
|
84
|
+
kramdown (~> 2.3)
|
85
|
+
kramdown-parser-gfm (~> 1.1)
|
86
|
+
parser (~> 3.0)
|
87
|
+
rbs (~> 2.0)
|
88
|
+
reverse_markdown (~> 2.0)
|
89
|
+
rubocop (~> 1.38)
|
90
|
+
thor (~> 1.0)
|
91
|
+
tilt (~> 2.0)
|
92
|
+
yard (~> 0.9, >= 0.9.24)
|
93
|
+
strscan (3.1.0)
|
94
|
+
thor (1.3.1)
|
95
|
+
tilt (2.4.0)
|
96
|
+
unicode-display_width (2.5.0)
|
97
|
+
yard (0.9.36)
|
98
|
+
|
99
|
+
PLATFORMS
|
100
|
+
aarch64-linux
|
101
|
+
arm-linux
|
102
|
+
arm64-darwin
|
103
|
+
x86-linux
|
104
|
+
x86_64-darwin
|
105
|
+
x86_64-linux
|
106
|
+
|
107
|
+
DEPENDENCIES
|
108
|
+
rake
|
109
|
+
rspec
|
110
|
+
rubocop
|
111
|
+
rubocop-rake
|
112
|
+
rubocop-rspec
|
113
|
+
shell_shock!
|
114
|
+
solargraph
|
115
|
+
|
116
|
+
BUNDLED WITH
|
117
|
+
2.5.11
|
data/Rakefile
ADDED
data/example/adventure.rb
CHANGED
@@ -1,21 +1,23 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
3
|
+
$LOAD_PATH << "#{File.dirname(__FILE__)}/../lib"
|
4
|
+
|
5
|
+
require "shell_shock/context"
|
4
6
|
|
5
7
|
class MoveCommand
|
6
8
|
attr_reader :usage, :help
|
7
9
|
|
8
|
-
def initialize
|
10
|
+
def initialize(room)
|
9
11
|
@room = room
|
10
|
-
@usage =
|
11
|
-
@help =
|
12
|
+
@usage = "<direction>"
|
13
|
+
@help = "moves to the adjoining room in the specified direction"
|
12
14
|
end
|
13
15
|
|
14
|
-
def completion
|
16
|
+
def completion(text)
|
15
17
|
@room.connections.keys.grep(/^#{text}/).sort
|
16
18
|
end
|
17
19
|
|
18
|
-
def execute
|
20
|
+
def execute(direction)
|
19
21
|
room = @room.connections[direction]
|
20
22
|
if room
|
21
23
|
AdventureContext.new(room).push
|
@@ -28,52 +30,54 @@ end
|
|
28
30
|
class AdventureContext
|
29
31
|
include ShellShock::Context
|
30
32
|
|
31
|
-
def initialize
|
33
|
+
def initialize(room)
|
32
34
|
puts room.description
|
33
35
|
@prompt = "#{room.name} > "
|
34
|
-
add_command MoveCommand.new(room),
|
36
|
+
add_command MoveCommand.new(room), "go"
|
35
37
|
end
|
36
38
|
end
|
37
39
|
|
38
40
|
class Room
|
39
41
|
attr_reader :name, :description, :connections
|
40
|
-
|
41
|
-
|
42
|
+
|
43
|
+
def initialize(name, description)
|
44
|
+
@name = name
|
45
|
+
@description = description
|
42
46
|
@connections = {}
|
43
47
|
end
|
44
48
|
|
45
|
-
def add
|
49
|
+
def add(direction, room)
|
46
50
|
@connections[direction] = room
|
47
51
|
end
|
48
52
|
end
|
49
53
|
|
50
|
-
START = Room.new
|
51
|
-
You have entered a clearing.
|
54
|
+
START = Room.new "clearing", <<~DESCRIPTION
|
55
|
+
You have entered a clearing.
|
52
56
|
|
53
|
-
A dead goat lies on the ground in front of you
|
54
|
-
|
57
|
+
A dead goat lies on the ground in front of you
|
58
|
+
DESCRIPTION
|
55
59
|
|
56
|
-
CAVE_ENTRANCE = Room.new
|
57
|
-
You have arrived at the entrance to a cave.
|
60
|
+
CAVE_ENTRANCE = Room.new "cave entrance", <<~DESCRIPTION
|
61
|
+
You have arrived at the entrance to a cave.
|
58
62
|
|
59
|
-
A foul smell is emitting from the cave. Some smoke
|
60
|
-
can be seen off off to the east.
|
61
|
-
|
63
|
+
A foul smell is emitting from the cave. Some smoke
|
64
|
+
can be seen off off to the east.
|
65
|
+
DESCRIPTION
|
62
66
|
|
63
|
-
CAMP_SITE = Room.new
|
64
|
-
You have arrived in a camp site.
|
67
|
+
CAMP_SITE = Room.new "camp site", <<~DESCRIPTION
|
68
|
+
You have arrived in a camp site.
|
65
69
|
|
66
|
-
There is a fire that has been recently put out.
|
67
|
-
|
70
|
+
There is a fire that has been recently put out.
|
71
|
+
DESCRIPTION
|
68
72
|
|
69
|
-
CAVE = Room.new
|
70
|
-
You have entered a dark cave.
|
73
|
+
CAVE = Room.new "cave", <<~DESCRIPTION
|
74
|
+
You have entered a dark cave.
|
71
75
|
|
72
|
-
A faint growling sound can be heard.
|
73
|
-
|
76
|
+
A faint growling sound can be heard.
|
77
|
+
DESCRIPTION
|
74
78
|
|
75
|
-
START.add
|
76
|
-
CAVE_ENTRANCE.add
|
77
|
-
CAVE_ENTRANCE.add
|
79
|
+
START.add "north", CAVE_ENTRANCE
|
80
|
+
CAVE_ENTRANCE.add "east", CAMP_SITE
|
81
|
+
CAVE_ENTRANCE.add "north", CAVE
|
78
82
|
|
79
|
-
AdventureContext.new(START).push
|
83
|
+
AdventureContext.new(START).push
|
data/example/file_system.rb
CHANGED
@@ -1,25 +1,27 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
require
|
3
|
+
$LOAD_PATH << "#{File.dirname(__FILE__)}/../lib"
|
4
|
+
|
5
|
+
require "shell_shock/context"
|
6
|
+
require "find"
|
7
|
+
require "pathname"
|
6
8
|
|
7
9
|
class Finder
|
8
10
|
attr_reader :files
|
9
11
|
|
10
|
-
def initialize
|
12
|
+
def initialize(path)
|
11
13
|
@path = path
|
12
14
|
end
|
13
15
|
|
14
|
-
def refresh
|
16
|
+
def refresh(pattern)
|
15
17
|
files = []
|
16
18
|
here = Pathname.new(File.expand_path(@path))
|
17
19
|
Find.find(File.expand_path(@path)) do |p|
|
18
|
-
if File.basename(p).start_with?(
|
20
|
+
if File.basename(p).start_with?(".")
|
19
21
|
Find.prune
|
20
22
|
else
|
21
23
|
path = Pathname.new(p).relative_path_from(here).to_s
|
22
|
-
files << path if path.start_with?(pattern)
|
24
|
+
files << path if path.start_with?(pattern) && yield(p)
|
23
25
|
end
|
24
26
|
end
|
25
27
|
files
|
@@ -29,67 +31,69 @@ end
|
|
29
31
|
class CatFileCommand
|
30
32
|
include ShellShock::Logger
|
31
33
|
|
32
|
-
def initialize
|
34
|
+
def initialize(path)
|
33
35
|
@finder = Finder.new path
|
34
36
|
end
|
35
37
|
|
36
38
|
def usage
|
37
|
-
|
39
|
+
"<file name>"
|
38
40
|
end
|
39
41
|
|
40
42
|
def help
|
41
|
-
|
43
|
+
"displays the content of a file"
|
42
44
|
end
|
43
45
|
|
44
|
-
def completion
|
46
|
+
def completion(text)
|
45
47
|
log { "cat command completing \"#{text}\"" }
|
46
|
-
@finder.refresh(text) {|path| File.file? path }
|
48
|
+
@finder.refresh(text) { |path| File.file? path }
|
47
49
|
end
|
48
50
|
|
49
|
-
def execute
|
51
|
+
def execute(path = nil)
|
50
52
|
return unless path
|
51
|
-
|
53
|
+
|
54
|
+
File.open(path) { |f| f.each_with_index { |l, i| puts "#{i + 1}: #{l}" } }
|
52
55
|
end
|
53
56
|
end
|
54
57
|
|
55
58
|
class ChangeDirectoryCommand
|
56
59
|
include ShellShock::Logger
|
57
60
|
|
58
|
-
def initialize
|
61
|
+
def initialize(path)
|
59
62
|
@path = path
|
60
63
|
@finder = Finder.new path
|
61
64
|
end
|
62
65
|
|
63
66
|
def usage
|
64
|
-
|
67
|
+
"<directory name>"
|
65
68
|
end
|
66
69
|
|
67
70
|
def help
|
68
|
-
|
71
|
+
"switches to a new shell context in the specified directory"
|
69
72
|
end
|
70
73
|
|
71
|
-
def completion
|
74
|
+
def completion(text)
|
72
75
|
log { "cd command completing \"#{text}\"" }
|
73
|
-
@finder.refresh(text) {|path| path !=
|
76
|
+
@finder.refresh(text) { |path| path != "." and File.directory? path }
|
74
77
|
end
|
75
78
|
|
76
|
-
def execute
|
77
|
-
return unless text
|
79
|
+
def execute(text = nil)
|
80
|
+
return unless text
|
81
|
+
|
78
82
|
log { "pushing new shell in \"#{text}\"" }
|
79
|
-
DirectoryContext.new(@path
|
83
|
+
DirectoryContext.new("#{@path}/#{text}").push
|
80
84
|
end
|
81
85
|
end
|
82
86
|
|
83
87
|
class DirectoryContext
|
84
88
|
include ShellShock::Context
|
85
89
|
|
86
|
-
def initialize
|
90
|
+
def initialize(path)
|
87
91
|
@prompt_text = "#{path} > "
|
88
92
|
@commands = {
|
89
|
-
|
90
|
-
|
93
|
+
"cd" => ChangeDirectoryCommand.new(path),
|
94
|
+
"cat" => CatFileCommand.new(path)
|
91
95
|
}
|
92
96
|
end
|
93
97
|
end
|
94
98
|
|
95
|
-
DirectoryContext.new(
|
99
|
+
DirectoryContext.new(".").push
|
@@ -1,11 +1,13 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module ShellShock
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
4
|
+
module CommandSpec
|
5
|
+
def with_usage(text)
|
6
|
+
it("displays usage") { expect(@command.usage).to eq(text) }
|
7
|
+
end
|
6
8
|
|
7
|
-
|
8
|
-
|
9
|
-
end
|
9
|
+
def with_help(text)
|
10
|
+
it("displays help") { expect(@command.help).to eq(text) }
|
10
11
|
end
|
11
|
-
end
|
12
|
+
end
|
13
|
+
end
|
data/lib/shell_shock/context.rb
CHANGED
@@ -1,24 +1,26 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
require
|
4
|
-
require
|
5
|
-
require
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "rubygems"
|
4
|
+
require "readline"
|
5
|
+
require "shell_shock/exit_command"
|
6
|
+
require "shell_shock/help_command"
|
7
|
+
require "shell_shock/logger"
|
6
8
|
|
7
9
|
module ShellShock
|
8
10
|
module Context
|
9
11
|
include Logger
|
10
12
|
|
11
|
-
def head_tail
|
13
|
+
def head_tail(string)
|
12
14
|
if string
|
13
15
|
m = /[^ ]+/.match(string.strip)
|
14
16
|
return m[0], m.post_match.strip if m
|
15
17
|
end
|
16
|
-
|
18
|
+
["", ""]
|
17
19
|
end
|
18
20
|
|
19
21
|
def refresh
|
20
22
|
refresh_commands if respond_to?(:refresh_commands)
|
21
|
-
Readline.completer_word_break_characters =
|
23
|
+
Readline.completer_word_break_characters = ""
|
22
24
|
Readline.completion_proc = lambda do |string|
|
23
25
|
log { "trying completion for \"#{string}\"" }
|
24
26
|
first, rest = head_tail(string)
|
@@ -28,7 +30,7 @@ module ShellShock
|
|
28
30
|
if command
|
29
31
|
log { "matched #{first} command" }
|
30
32
|
if command.respond_to?(:completion)
|
31
|
-
completions = command.completion(rest).map {|c| "#{first} #{c}" }
|
33
|
+
completions = command.completion(rest).map { |c| "#{first} #{c}" }
|
32
34
|
else
|
33
35
|
log { "#{first} has no completion proc" }
|
34
36
|
completions = []
|
@@ -36,7 +38,7 @@ module ShellShock
|
|
36
38
|
end
|
37
39
|
end
|
38
40
|
|
39
|
-
completions ||= @commands.keys.grep(
|
41
|
+
completions ||= @commands.keys.grep(/^#{Regexp.escape(first)}/).sort.map { |c| "#{c} " }
|
40
42
|
log { "returning #{completions.inspect} completions" }
|
41
43
|
completions
|
42
44
|
end
|
@@ -52,13 +54,13 @@ module ShellShock
|
|
52
54
|
|
53
55
|
def add_command command, *aliases
|
54
56
|
@commands ||= {}
|
55
|
-
aliases.each {|a| @commands[a] = command}
|
57
|
+
aliases.each { |a| @commands[a] = command }
|
56
58
|
end
|
57
59
|
|
58
60
|
def push
|
59
|
-
@prompt ||=
|
60
|
-
add_command HelpCommand.new(@commands),
|
61
|
-
add_command ExitCommand.new(self),
|
61
|
+
@prompt ||= " > "
|
62
|
+
add_command HelpCommand.new(@commands), "help"
|
63
|
+
add_command ExitCommand.new(self), "exit"
|
62
64
|
begin
|
63
65
|
until abort?
|
64
66
|
refresh
|
@@ -76,9 +78,9 @@ module ShellShock
|
|
76
78
|
end
|
77
79
|
puts
|
78
80
|
end
|
79
|
-
rescue Interrupt
|
81
|
+
rescue Interrupt
|
80
82
|
puts
|
81
83
|
end
|
82
84
|
end
|
83
85
|
end
|
84
|
-
end
|
86
|
+
end
|
@@ -1,15 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module ShellShock
|
2
4
|
class ExitCommand
|
3
5
|
attr_reader :help, :usage
|
4
6
|
|
5
|
-
def initialize
|
7
|
+
def initialize(context)
|
6
8
|
@context = context
|
7
|
-
@usage =
|
8
|
-
@help =
|
9
|
+
@usage = ""
|
10
|
+
@help = "exits the current context"
|
9
11
|
end
|
10
12
|
|
11
|
-
def execute
|
13
|
+
def execute(_ignore)
|
12
14
|
@context.abort!
|
13
15
|
end
|
14
|
-
end
|
15
|
-
end
|
16
|
+
end
|
17
|
+
end
|
@@ -1,28 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module ShellShock
|
2
4
|
class HelpCommand
|
3
5
|
attr_reader :help, :usage
|
4
6
|
|
5
|
-
def initialize
|
7
|
+
def initialize(commands)
|
6
8
|
@commands = commands
|
7
|
-
@usage =
|
8
|
-
@help =
|
9
|
+
@usage = "<command name>"
|
10
|
+
@help = "displays the help information for a command"
|
9
11
|
end
|
10
12
|
|
11
|
-
def completion
|
13
|
+
def completion(text)
|
12
14
|
@commands.keys.grep(/^#{Regexp.escape(text)}/).sort
|
13
15
|
end
|
14
16
|
|
15
|
-
def execute
|
17
|
+
def execute(command)
|
16
18
|
command.empty? ? display_help_for_commands : display_help_for_command(command)
|
17
19
|
end
|
18
20
|
|
19
21
|
def display_help_for_commands
|
20
22
|
return if @commands.keys.empty?
|
21
|
-
|
23
|
+
|
24
|
+
puts "Available commands:"
|
22
25
|
@commands.keys.sort.each { |command| puts command }
|
23
26
|
end
|
24
27
|
|
25
|
-
def display_help_for_command
|
28
|
+
def display_help_for_command(command_name)
|
26
29
|
command = @commands[command_name]
|
27
30
|
if command
|
28
31
|
puts "Command \"#{command_name}\""
|
@@ -33,4 +36,4 @@ module ShellShock
|
|
33
36
|
end
|
34
37
|
end
|
35
38
|
end
|
36
|
-
end
|
39
|
+
end
|
data/lib/shell_shock/logger.rb
CHANGED
@@ -1,11 +1,14 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module ShellShock
|
2
|
-
|
3
|
-
def log
|
4
|
-
return unless ENV[
|
5
|
-
|
4
|
+
module Logger
|
5
|
+
def log(message = nil)
|
6
|
+
return unless ENV["LOG_PATH"]
|
7
|
+
|
8
|
+
File.open(ENV.fetch("LOG_PATH", nil), "a") do |file|
|
6
9
|
file.puts message if message
|
7
10
|
file.puts yield if block_given?
|
8
11
|
end
|
9
12
|
end
|
10
13
|
end
|
11
|
-
end
|
14
|
+
end
|
data/shell_shock.gemspec
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
Gem::Specification.new do |spec|
|
4
|
+
spec.name = "shell_shock"
|
5
|
+
spec.version = "0.0.6"
|
6
|
+
spec.summary = "library for creating simple shell applications using readline"
|
7
|
+
spec.description = <<~DESCRIPTION
|
8
|
+
This is just some code extracted from a few command line gems i've created (shh and cardigan).
|
9
|
+
|
10
|
+
I wanted to move the shared functionality (related to creating a shell with readline) to a seperate gem.'
|
11
|
+
DESCRIPTION
|
12
|
+
|
13
|
+
spec.authors << "Mark Ryall"
|
14
|
+
spec.email = "mark@ryall.name"
|
15
|
+
spec.homepage = "http://github.com/markryall/shell_shock"
|
16
|
+
spec.required_ruby_version = Gem::Requirement.new(">= 3.0")
|
17
|
+
|
18
|
+
spec.metadata["homepage_uri"] = spec.homepage
|
19
|
+
|
20
|
+
spec.files = Dir.chdir(File.expand_path(__dir__)) do
|
21
|
+
`git ls-files -z`.split("\x0").reject { |f| f.match(%r{\A(?:test|spec|features)/}) }
|
22
|
+
end
|
23
|
+
spec.bindir = "exe"
|
24
|
+
spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
|
25
|
+
spec.require_paths = ["lib"]
|
26
|
+
spec.metadata["rubygems_mfa_required"] = "true"
|
27
|
+
end
|
metadata
CHANGED
@@ -1,121 +1,62 @@
|
|
1
|
-
--- !ruby/object:Gem::Specification
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
2
|
name: shell_shock
|
3
|
-
version: !ruby/object:Gem::Version
|
4
|
-
|
5
|
-
segments:
|
6
|
-
- 0
|
7
|
-
- 0
|
8
|
-
- 5
|
9
|
-
version: 0.0.5
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.6
|
10
5
|
platform: ruby
|
11
|
-
authors:
|
6
|
+
authors:
|
12
7
|
- Mark Ryall
|
13
|
-
autorequire:
|
14
|
-
bindir:
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
15
10
|
cert_chain: []
|
16
|
-
|
17
|
-
|
18
|
-
default_executable:
|
19
|
-
dependencies:
|
20
|
-
- !ruby/object:Gem::Dependency
|
21
|
-
name: rake
|
22
|
-
prerelease: false
|
23
|
-
requirement: &id001 !ruby/object:Gem::Requirement
|
24
|
-
none: false
|
25
|
-
requirements:
|
26
|
-
- - ~>
|
27
|
-
- !ruby/object:Gem::Version
|
28
|
-
segments:
|
29
|
-
- 0
|
30
|
-
- 8
|
31
|
-
- 7
|
32
|
-
version: 0.8.7
|
33
|
-
type: :development
|
34
|
-
version_requirements: *id001
|
35
|
-
- !ruby/object:Gem::Dependency
|
36
|
-
name: gemesis
|
37
|
-
prerelease: false
|
38
|
-
requirement: &id002 !ruby/object:Gem::Requirement
|
39
|
-
none: false
|
40
|
-
requirements:
|
41
|
-
- - ~>
|
42
|
-
- !ruby/object:Gem::Version
|
43
|
-
segments:
|
44
|
-
- 0
|
45
|
-
- 0
|
46
|
-
- 4
|
47
|
-
version: 0.0.4
|
48
|
-
type: :development
|
49
|
-
version_requirements: *id002
|
50
|
-
- !ruby/object:Gem::Dependency
|
51
|
-
name: rspec
|
52
|
-
prerelease: false
|
53
|
-
requirement: &id003 !ruby/object:Gem::Requirement
|
54
|
-
none: false
|
55
|
-
requirements:
|
56
|
-
- - ~>
|
57
|
-
- !ruby/object:Gem::Version
|
58
|
-
segments:
|
59
|
-
- 2
|
60
|
-
- 4
|
61
|
-
- 0
|
62
|
-
version: 2.4.0
|
63
|
-
type: :development
|
64
|
-
version_requirements: *id003
|
11
|
+
date: 2024-07-20 00:00:00.000000000 Z
|
12
|
+
dependencies: []
|
65
13
|
description: |
|
66
14
|
This is just some code extracted from a few command line gems i've created (shh and cardigan).
|
67
|
-
|
68
|
-
I wanted to move the shared functionality (related to creating a shell with readline) to a seperate gem.'
|
69
15
|
|
16
|
+
I wanted to move the shared functionality (related to creating a shell with readline) to a seperate gem.'
|
70
17
|
email: mark@ryall.name
|
71
18
|
executables: []
|
72
|
-
|
73
19
|
extensions: []
|
74
|
-
|
75
20
|
extra_rdoc_files: []
|
76
|
-
|
77
|
-
|
21
|
+
files:
|
22
|
+
- ".gitignore"
|
23
|
+
- ".rubocop.yml"
|
24
|
+
- ".tool-versions"
|
25
|
+
- Gemfile
|
26
|
+
- Gemfile.lock
|
27
|
+
- MIT-LICENSE
|
28
|
+
- README.rdoc
|
29
|
+
- Rakefile
|
78
30
|
- example/adventure.rb
|
79
|
-
- example/cat.rb
|
80
31
|
- example/file_system.rb
|
81
32
|
- lib/shell_shock/command_spec.rb
|
82
33
|
- lib/shell_shock/context.rb
|
83
34
|
- lib/shell_shock/exit_command.rb
|
84
35
|
- lib/shell_shock/help_command.rb
|
85
36
|
- lib/shell_shock/logger.rb
|
86
|
-
-
|
87
|
-
- MIT-LICENSE
|
88
|
-
has_rdoc: true
|
37
|
+
- shell_shock.gemspec
|
89
38
|
homepage: http://github.com/markryall/shell_shock
|
90
39
|
licenses: []
|
91
|
-
|
92
|
-
|
40
|
+
metadata:
|
41
|
+
homepage_uri: http://github.com/markryall/shell_shock
|
42
|
+
rubygems_mfa_required: 'true'
|
43
|
+
post_install_message:
|
93
44
|
rdoc_options: []
|
94
|
-
|
95
|
-
require_paths:
|
45
|
+
require_paths:
|
96
46
|
- lib
|
97
|
-
required_ruby_version: !ruby/object:Gem::Requirement
|
98
|
-
|
99
|
-
requirements:
|
47
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
48
|
+
requirements:
|
100
49
|
- - ">="
|
101
|
-
- !ruby/object:Gem::Version
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
required_rubygems_version: !ruby/object:Gem::Requirement
|
106
|
-
none: false
|
107
|
-
requirements:
|
50
|
+
- !ruby/object:Gem::Version
|
51
|
+
version: '3.0'
|
52
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
53
|
+
requirements:
|
108
54
|
- - ">="
|
109
|
-
- !ruby/object:Gem::Version
|
110
|
-
|
111
|
-
- 0
|
112
|
-
version: "0"
|
55
|
+
- !ruby/object:Gem::Version
|
56
|
+
version: '0'
|
113
57
|
requirements: []
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
signing_key:
|
118
|
-
specification_version: 3
|
58
|
+
rubygems_version: 3.5.11
|
59
|
+
signing_key:
|
60
|
+
specification_version: 4
|
119
61
|
summary: library for creating simple shell applications using readline
|
120
62
|
test_files: []
|
121
|
-
|
data/example/cat.rb
DELETED
@@ -1,66 +0,0 @@
|
|
1
|
-
require 'shell_shock/context'
|
2
|
-
|
3
|
-
class Prompt
|
4
|
-
def say text=nil
|
5
|
-
puts text ? text : ''
|
6
|
-
end
|
7
|
-
end
|
8
|
-
|
9
|
-
class CatFileCommand
|
10
|
-
def initialize path
|
11
|
-
@path = path
|
12
|
-
end
|
13
|
-
|
14
|
-
def usage
|
15
|
-
'<file name>'
|
16
|
-
end
|
17
|
-
|
18
|
-
def help
|
19
|
-
'displays the content of a file'
|
20
|
-
end
|
21
|
-
|
22
|
-
def completion text
|
23
|
-
Dir.glob("#{@path}/#{text}*").select {|f| File.file?(f) }
|
24
|
-
end
|
25
|
-
|
26
|
-
def execute path
|
27
|
-
File.open(path) {|f| f.each_with_index {|l,i| puts "#{i+1}: #{l}" } }
|
28
|
-
end
|
29
|
-
end
|
30
|
-
|
31
|
-
class ChangeDirectoryCommand
|
32
|
-
def initialize path
|
33
|
-
@path = path
|
34
|
-
end
|
35
|
-
|
36
|
-
def usage
|
37
|
-
'<directory name>'
|
38
|
-
end
|
39
|
-
|
40
|
-
def help
|
41
|
-
'switches to a new shell context in the specified directory'
|
42
|
-
end
|
43
|
-
|
44
|
-
def completion text
|
45
|
-
Dir.glob("#{@path}/#{text}*").select {|f| File.directory?(f) }
|
46
|
-
end
|
47
|
-
|
48
|
-
def execute text
|
49
|
-
DirectoryContext.new(text).push
|
50
|
-
end
|
51
|
-
end
|
52
|
-
|
53
|
-
class DirectoryContext
|
54
|
-
include ShellShock::Context
|
55
|
-
|
56
|
-
def initialize path
|
57
|
-
@io = Prompt.new
|
58
|
-
@prompt_text = "#{path} > "
|
59
|
-
@commands = {
|
60
|
-
'cd' => ChangeDirectoryCommand.new(path),
|
61
|
-
'cat' => CatFileCommand.new(path)
|
62
|
-
}
|
63
|
-
end
|
64
|
-
end
|
65
|
-
|
66
|
-
DirectoryContext.new('.').push
|