rbcli 0.1.7 → 0.1.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/Gemfile.lock +3 -1
- data/README.md +50 -6
- data/exe/rbcli +81 -32
- data/lib/rbcli/configuration/config.rb +6 -6
- data/lib/rbcli/configuration/configurate.rb +1 -1
- data/lib/rbcli/engine/load_project.rb +19 -0
- data/lib/rbcli/engine/parser.rb +2 -2
- data/lib/rbcli/logging/logging.rb +7 -4
- data/lib/rbcli/stateful_systems/state_storage.rb +4 -0
- data/lib/rbcli/version.rb +1 -1
- data/lib/rbcli-tool/erb_renderer.rb +43 -0
- data/lib/rbcli-tool/mdless_fix.rb +386 -0
- data/lib/rbcli-tool/project.rb +87 -0
- data/lib/rbcli-tool.rb +16 -0
- data/lib/rbcli.rb +11 -10
- data/rbcli.gemspec +1 -0
- data/skeletons/micro/executable +123 -0
- data/skeletons/mini/executable +241 -0
- data/skeletons/project/.gitignore +11 -0
- data/skeletons/project/.rbcli +0 -0
- data/skeletons/project/.rspec +3 -0
- data/skeletons/project/CODE_OF_CONDUCT.md +74 -0
- data/skeletons/project/Gemfile +6 -0
- data/skeletons/project/README.md +31 -0
- data/skeletons/project/Rakefile +6 -0
- data/skeletons/project/application/commands/command.rb +31 -0
- data/skeletons/project/application/commands/scripts/script.sh +23 -0
- data/skeletons/project/application/options.rb +30 -0
- data/skeletons/project/config/autoupdate.rb +32 -0
- data/skeletons/project/config/logging.rb +19 -0
- data/skeletons/project/config/storage.rb +34 -0
- data/skeletons/project/config/userspace.rb +28 -0
- data/skeletons/project/config/version.rb +3 -0
- data/skeletons/project/default_user_configs/user_defaults.yml +6 -0
- data/skeletons/project/exe/executable +54 -0
- data/skeletons/project/hooks/default_action.rb +16 -0
- data/skeletons/project/hooks/first_run.rb +16 -0
- data/skeletons/project/hooks/post_execution.rb +14 -0
- data/skeletons/project/hooks/pre_execution.rb +14 -0
- data/skeletons/project/spec/spec_helper.rb +14 -0
- data/skeletons/project/spec/untitled_spec.rb +9 -0
- data/skeletons/project/untitled.gemspec +40 -0
- metadata +47 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: eeb0aa5b07a4650d68356dabb3e0f185f7b54adaa8911902780ee66d079a1d83
|
4
|
+
data.tar.gz: 674ce261ee73a19d22667fbfc9906bddfcd1bda88b526939b171696089ef55d9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 20eee68c0d42e059fa1e767211941e4e998e7f7c8e9f6440356544a777fd5abc268215d1036b42be3170c1b090bc9d77b176c2ffc89ffa94850c31f888887b5d
|
7
|
+
data.tar.gz: 6272c53067831c7902f42be08532f82199cee8bbb8427bc9ca6c8e2028add6f81726cec0dd381bc056cf030ec067c7249ab406538b4b0fac81b6ba79f5cb2fa9
|
data/Gemfile.lock
CHANGED
@@ -1,11 +1,12 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
rbcli (0.1.
|
4
|
+
rbcli (0.1.8)
|
5
5
|
aws-sdk-dynamodb (~> 1.6)
|
6
6
|
colorize (~> 0.8)
|
7
7
|
deep_merge (~> 1.2)
|
8
8
|
macaddr (~> 1.7)
|
9
|
+
mdless (~> 0.0)
|
9
10
|
octokit (~> 4.9)
|
10
11
|
rufus-scheduler (~> 3.5)
|
11
12
|
|
@@ -37,6 +38,7 @@ GEM
|
|
37
38
|
jmespath (1.4.0)
|
38
39
|
macaddr (1.7.1)
|
39
40
|
systemu (~> 2.6.2)
|
41
|
+
mdless (0.0.10)
|
40
42
|
minitest (5.11.3)
|
41
43
|
multipart-post (2.0.0)
|
42
44
|
octokit (4.9.0)
|
data/README.md
CHANGED
@@ -26,6 +26,8 @@ Some of its key features include:
|
|
26
26
|
|
27
27
|
* __External Script Wrapping__: High-level wrapping for Bash scripts, or any other applcication you'd like to wrap into a command.
|
28
28
|
|
29
|
+
* __Project Structure and Generators__: Create a well-defined project directory structure which organizes your code and allows you to package and distribute your application as a Gem. Generators can also help speed up the process of creating new commands, scripts, and hooks!
|
30
|
+
|
29
31
|
|
30
32
|
## Installation
|
31
33
|
|
@@ -60,14 +62,16 @@ mytool show -l
|
|
60
62
|
Note that all options and parameters will have both a short and long version of the parameter available for use.
|
61
63
|
|
62
64
|
|
63
|
-
## Getting Started
|
65
|
+
## Getting Started (Lightweight)
|
66
|
+
|
67
|
+
For a lightweight skeleton that consists of a single file, use `rbcli init -t mini -n <projectname>`, or `rbcli init -t micro -n <projectname>` for an even more simplified one.
|
64
68
|
|
65
|
-
|
69
|
+
These lightweight skeletons allow creating single-file applications/scripts using RBCli. They consolidate all of the options in the standard project format into these sections:
|
66
70
|
|
67
71
|
* The configuration
|
68
72
|
* Storage subsystem configuration (optional)
|
69
73
|
* A command declaration
|
70
|
-
* The parse command
|
74
|
+
* The parse command
|
71
75
|
|
72
76
|
### Configuration
|
73
77
|
|
@@ -84,7 +88,7 @@ Rbcli::Configurate.me do
|
|
84
88
|
|
85
89
|
config_userfile '/etc/mytool/config.yml', merge_defaults: true, required: false # (Optional) Set location of user's config file. If merge_defaults=true, user settings override default settings, and if false, defaults are not loaded at all. If required=true, application will not run if file does not exist.
|
86
90
|
config_defaults 'defaults.yml' # (Optional, Multiple) Load a YAML file as part of the default config. This can be called multiple times, and the YAML files will be merged. User config is generated from these
|
87
|
-
config_default :myopt, description: 'Testing this',
|
91
|
+
config_default :myopt, description: 'Testing this', default: true # (Optional, Multiple) Specify an individual configuration parameter and set a default value. These will also be included in generated user config
|
88
92
|
|
89
93
|
option :name, 'Give me your name', type: :string, default: 'Foo', required: false, permitted: ['Jack', 'Jill'] # (Optional, Multiple) Add a global CLI parameter. Supported types are :string, :boolean, :integer, :float, :date, and :io. Can be called multiple times.
|
90
94
|
|
@@ -147,7 +151,7 @@ class Test < Rbcli::Command
|
|
147
151
|
parameter :force, 'Force testing', type: :boolean, default: false, required: false # (Optional, Multiple) Add a command-specific CLI parameter. Can be called multiple times
|
148
152
|
|
149
153
|
config_defaults 'defaults.yml' # (Optional, Multiple) Load a YAML file as part of the default config. This can be called multiple times, and the YAML files will be merged. User config is generated from these
|
150
|
-
config_default :myopt2, description: 'Testing this again',
|
154
|
+
config_default :myopt2, description: 'Testing this again', default: true # (Optional, Multiple) Specify an individual configuration parameter and set a default value. These will also be included in generated user config
|
151
155
|
|
152
156
|
extern path: 'env | grep "^__PARAMS\|^__ARGS\|^__GLOBAL\|^__CONFIG"', envvars: {MYVAR: 'some_value'} # (Required unless `action` defined) Runs a given application, with optional environment variables, when the user runs the command.
|
153
157
|
extern envvars: {MY_OTHER_VAR: 'another_value'} do |params, args, global_opts, config| # Alternate usage. Supplying a block instead of a path allows us to modify the command based on the arguments and configuration supplied by the user.
|
@@ -202,7 +206,7 @@ The defaults chain allows you to specify sane defaults for your CLI tool through
|
|
202
206
|
* DSL Statements
|
203
207
|
* In the DSL, you can specify options individually by providing a name, description, and default value
|
204
208
|
* This is good for simpler configuration, as the descriptions provided are written out as comments in the generated user config
|
205
|
-
* `config_default :name, description: '<description_text>',
|
209
|
+
* `config_default :name, description: '<description_text>', default: <default_value>` in the DSL
|
206
210
|
|
207
211
|
Users can generate configs by running `yourclitool -g`. This will generate a config file at the tool's default location specified in the DSL. A specific location can be used via the `-c` parameter. You can test how this works by running `examples/mytool -c test.yml -g`.
|
208
212
|
|
@@ -276,6 +280,8 @@ Hash native methods:
|
|
276
280
|
|
277
281
|
Additional methods:
|
278
282
|
|
283
|
+
* `commit`
|
284
|
+
* Every assignment to the top level of the hash will result in a write to disk (for example: `Rbcli.local_state[:yourkey] = 'foo'`). If you are manipulating nested hashes, you can trigger a save manually by calling `commit`.
|
279
285
|
* `clear`
|
280
286
|
* Resets the data back to an empty hash.
|
281
287
|
* `refresh`
|
@@ -481,6 +487,44 @@ class Test < Rbcli::Command
|
|
481
487
|
end
|
482
488
|
```
|
483
489
|
|
490
|
+
## Project Structure and Generators
|
491
|
+
|
492
|
+
RBCli supports using predefined project structure, helping to organize all of the options and commands that you may use. It also
|
493
|
+
|
494
|
+
Creating a new project skeleton is as easy as running `rbcli init -n <projectname>`. It will create a folder under the currect directory using the name specified, allowing you to create a command that can be easily packaged and distributed as a gem.
|
495
|
+
|
496
|
+
The folder structure is as follows:
|
497
|
+
|
498
|
+
```
|
499
|
+
<projectname>
|
500
|
+
|
|
501
|
+
|--- application
|
502
|
+
| |
|
503
|
+
| |--- commands
|
504
|
+
| |
|
505
|
+
| |---scripts
|
506
|
+
|
|
507
|
+
|--- config
|
508
|
+
|--- default_user_configs
|
509
|
+
|--- exe
|
510
|
+
|--- hooks
|
511
|
+
|--- spec
|
512
|
+
```
|
513
|
+
|
514
|
+
It is highly recommended to __not__ create files in these folders manually, and to use the RBCli generators instead:
|
515
|
+
|
516
|
+
```shell
|
517
|
+
rbcli command -n <name>
|
518
|
+
rbcli script -n <name>
|
519
|
+
rbcli userconf -n <name>
|
520
|
+
rbcli hook -t pre
|
521
|
+
rbcli hook -t post
|
522
|
+
rbcli hook -t default
|
523
|
+
rbcli hook -t runonce
|
524
|
+
```
|
525
|
+
|
526
|
+
That said, this readme will provide you with the information required to do things manually if you so desire. More details on generators later.
|
527
|
+
|
484
528
|
|
485
529
|
## Development
|
486
530
|
|
data/exe/rbcli
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
|
-
require 'rbcli'
|
3
|
+
require '../lib/rbcli'
|
4
4
|
|
5
5
|
Rbcli::Configurate.me do
|
6
6
|
scriptname __FILE__.split('/')[-1]
|
@@ -8,46 +8,95 @@ Rbcli::Configurate.me do
|
|
8
8
|
description 'RBCli initialization tool'
|
9
9
|
end
|
10
10
|
|
11
|
-
|
12
|
-
description 'Initialize a skeleton RBCli executable.'
|
13
|
-
usage 'This will generate a new file in the current folder'
|
14
|
-
parameter :filename, 'Name of file to generate', type: :string, required: true
|
11
|
+
require '../lib/rbcli-tool'
|
15
12
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
13
|
+
class Docs < Rbcli::Command
|
14
|
+
description 'Show Documentation (Beta)'
|
15
|
+
|
16
|
+
action do
|
17
|
+
readme = "#{File.dirname(__FILE__)}/../README.md"
|
18
|
+
begin
|
19
|
+
CLIMarkdown::Converter.new([readme])
|
20
|
+
rescue Errno::EPIPE
|
21
|
+
# Empty
|
22
|
+
end
|
20
23
|
end
|
21
24
|
end
|
22
25
|
|
23
|
-
class
|
24
|
-
description 'Initialize a skeleton
|
25
|
-
usage
|
26
|
-
|
26
|
+
class Init < Rbcli::Command
|
27
|
+
description 'Initialize a skeleton RBCli project.'
|
28
|
+
usage <<-EOF
|
29
|
+
This will generate a new project structure under the current directory. Use -t to specify the type:
|
30
|
+
|
31
|
+
|
32
|
+
Standard: A complete RBCli project structure. Recommended for most applications, it provides
|
33
|
+
a framework for organizing code and creating a gem to be installed/distributed.
|
34
|
+
|
35
|
+
Mini: A single-file RBCli project. All features are supported, but project structure is left to the developer.
|
36
|
+
Recommended for smaller applications, or for integrating RBCli into an existing application.
|
37
|
+
|
38
|
+
Micro: A single-file, minimal RBCli project. Similar to a mini project, but only the minimal required code is
|
39
|
+
generated. Recommended for rapid prototyping of scripts, for advanced users only.
|
40
|
+
EOF
|
41
|
+
|
42
|
+
parameter :name, 'Name of project to generate', type: :string, required: true
|
43
|
+
parameter :type, 'Specify project type', type: :string, permitted: %w(standard micro mini), default: 'standard'
|
44
|
+
parameter :description, 'A description of the project', type: :string, default: 'TODO: Description goes here'
|
27
45
|
|
28
46
|
action do |params, args, global_opts, config|
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
47
|
+
dest = "#{Dir.pwd}/#{params[:name]}"
|
48
|
+
|
49
|
+
# Prepare template vars
|
50
|
+
template_vars = {
|
51
|
+
cmdname: params[:name],
|
52
|
+
description: params[:description],
|
53
|
+
rbcli_version: Rbcli::VERSION
|
54
|
+
}
|
55
|
+
|
56
|
+
proj = RBCliTool::Project.new(dest, template_vars)
|
34
57
|
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
elsif template_vars
|
39
|
-
print "Generating file #{dest}..."
|
40
|
-
text = File.read src
|
41
|
-
template_vars.each do |k, v|
|
42
|
-
text.gsub! /{{\*\*#{k}\*\*}}/, v
|
58
|
+
if proj.exists?
|
59
|
+
RBCliTool.continue_confirmation "The project or file #{params[:name]} already exists; contents will be overwritten."
|
60
|
+
FileUtils.rm_rf dest
|
43
61
|
end
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
62
|
+
|
63
|
+
case params[:type]
|
64
|
+
when 'micro' # Micro: Single File, simplified
|
65
|
+
puts "\nInitialization Complete!\n" if proj.create_micro
|
66
|
+
|
67
|
+
when 'mini' # Mini: Single File
|
68
|
+
puts "\nInitialization Complete!\n" if proj.create_mini
|
69
|
+
|
70
|
+
else # Standard; full project structure
|
71
|
+
if proj.create
|
72
|
+
puts "\nInitialization Complete!\n"
|
73
|
+
else
|
74
|
+
puts "\nAn RBCli Project already exists in the current directory tree at: #{proj.exists?}. Aborting.\n"
|
75
|
+
end
|
76
|
+
|
77
|
+
end # END case params[:type]
|
78
|
+
|
50
79
|
end
|
51
80
|
end
|
52
81
|
|
82
|
+
class Command < Rbcli::Command
|
83
|
+
description 'Generate an Rbcli Command under the current project'
|
84
|
+
usage <<-EOF
|
85
|
+
This will generate a new project structure under the current directory. Use -t to specify the type:
|
86
|
+
|
87
|
+
|
88
|
+
Standard: A complete RBCli project structure. Recommended for most applications, it provides
|
89
|
+
a framework for organizing code and creating a gem to be installed/distributed.
|
90
|
+
|
91
|
+
Mini: A single-file RBCli project. All features are supported, but project structure is left to the developer.
|
92
|
+
Recommended for smaller applications, or for integrating RBCli into an existing application.
|
93
|
+
|
94
|
+
Micro: A single-file, minimal RBCli project. Similar to a mini project, but only the minimal required code is
|
95
|
+
generated. Recommended for rapid prototyping of scripts, for advanced users only.
|
96
|
+
EOF
|
97
|
+
|
98
|
+
parameter :name, 'Name of command to generate', type: :string, required: true
|
99
|
+
end
|
100
|
+
|
101
|
+
|
53
102
|
Rbcli.parse
|
@@ -45,7 +45,7 @@ module Rbcli::Config
|
|
45
45
|
@categorized_defaults = nil
|
46
46
|
@loaded = false
|
47
47
|
|
48
|
-
def self.set_userfile filename, merge_defaults:
|
48
|
+
def self.set_userfile filename, merge_defaults: true, required: false
|
49
49
|
@config_file = File.expand_path filename
|
50
50
|
@merge_defaults = merge_defaults
|
51
51
|
@userfile_required = required
|
@@ -67,11 +67,11 @@ module Rbcli::Config
|
|
67
67
|
@loaded = false
|
68
68
|
end
|
69
69
|
|
70
|
-
def self.add_default name, description: nil,
|
70
|
+
def self.add_default name, description: nil, default: nil
|
71
71
|
@config_individual_lines ||= []
|
72
|
-
text = "#{name.to_s}: #{
|
72
|
+
text = "#{name.to_s}: #{default}".ljust(30) + " # #{description}"
|
73
73
|
@config_individual_lines.push text unless @config_individual_lines.include? text
|
74
|
-
@config_defaults[name.to_sym] =
|
74
|
+
@config_defaults[name.to_sym] = default
|
75
75
|
@loaded = false
|
76
76
|
end
|
77
77
|
|
@@ -81,8 +81,8 @@ module Rbcli::Config
|
|
81
81
|
@config_text ||= ''
|
82
82
|
@config_text += "\n" unless @config_text.empty?
|
83
83
|
File.readlines(filename).each do |line|
|
84
|
-
if
|
85
|
-
@config_text << "\n
|
84
|
+
if line.start_with? '---' or line.start_with? '...'
|
85
|
+
@config_text << "\n" unless @config_text.empty?
|
86
86
|
else
|
87
87
|
@config_text << line unless @config_text.include? line
|
88
88
|
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Rbcli
|
2
|
+
def self.load_project
|
3
|
+
project_root = File.expand_path "#{File.dirname(caller[0].split(':')[0])}/../"
|
4
|
+
|
5
|
+
# We require all ruby files as-is
|
6
|
+
%w(config hooks application application/commands).each do |dir|
|
7
|
+
dirpath = "#{project_root}/#{dir}"
|
8
|
+
Dir.glob "#{dirpath}/*.rb" do |file|
|
9
|
+
require file
|
10
|
+
end if Dir.exists? dirpath
|
11
|
+
end
|
12
|
+
|
13
|
+
# We automatically pull in default user configs
|
14
|
+
configspath = "#{project_root}/default_user_configs"
|
15
|
+
Dir.glob "#{configspath}/*.{yml,yaml}" do |file|
|
16
|
+
Rbcli::Configurate.me {config_defaults file}
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
data/lib/rbcli/engine/parser.rb
CHANGED
@@ -28,8 +28,8 @@ Commands:
|
|
28
28
|
opt name.to_sym, opts[:description], type: opts[:type], default: opts[:default], required: opts[:required], permitted: opts[:permitted]
|
29
29
|
end
|
30
30
|
opt :json_output, 'Output result in machine-friendly JSON format', :type => :boolean, :default => false if data[:allow_json]
|
31
|
-
opt :config_file, 'Specify a config file manually', :type => :string, :default => data[:config_userfile]
|
32
|
-
opt :generate_config, 'Generate a new config file' #defaults to false
|
31
|
+
opt :config_file, 'Specify a config file manually', :type => :string, :default => data[:config_userfile] unless data[:config_userfile].nil?
|
32
|
+
opt :generate_config, 'Generate a new config file' unless data[:config_userfile].nil? #defaults to false
|
33
33
|
stop_on Rbcli::Command.commands.keys
|
34
34
|
end
|
35
35
|
|
@@ -29,12 +29,12 @@ module Rbcli::Logger
|
|
29
29
|
|
30
30
|
Rbcli::Config::add_categorized_defaults :logger, 'Log Settings', {
|
31
31
|
log_level: {
|
32
|
-
description: '0-5, or DEBUG < INFO < WARN < ERROR < FATAL < UNKNOWN',
|
33
|
-
value: @default_level ||
|
32
|
+
description: '0-5, or DEBUG < INFO < WARN < ERROR < FATAL < UNKNOWN. Set to null (~) to disable logging.',
|
33
|
+
value: @default_level || nil
|
34
34
|
},
|
35
35
|
log_target: {
|
36
|
-
description: 'STDOUT, STDERR, or a file path',
|
37
|
-
value: @default_target ||
|
36
|
+
description: 'STDOUT, STDERR, or a file path. Set to null (~) to disable logging.',
|
37
|
+
value: @default_target || nil
|
38
38
|
}
|
39
39
|
}
|
40
40
|
end
|
@@ -45,9 +45,12 @@ module Rbcli::Logger
|
|
45
45
|
target = STDOUT
|
46
46
|
elsif Rbcli::config[:logger][:log_target].downcase == 'stderr'
|
47
47
|
target = STDERR
|
48
|
+
elsif Rbcli::config[:logger][:log_target].nil?
|
49
|
+
target = '/dev/null'
|
48
50
|
else
|
49
51
|
target = Rbcli::config[:logger][:log_target]
|
50
52
|
end
|
53
|
+
target = '/dev/null' if Rbcli::config[:logger][:log_level].nil?
|
51
54
|
@logger = Logger.new(target)
|
52
55
|
@logger.level = Rbcli::config[:logger][:log_level]
|
53
56
|
|
data/lib/rbcli/version.rb
CHANGED
@@ -0,0 +1,43 @@
|
|
1
|
+
require 'erb'
|
2
|
+
|
3
|
+
module RBCliTool
|
4
|
+
class ERBRenderer
|
5
|
+
def initialize filename, varlist
|
6
|
+
@filename = filename
|
7
|
+
@vars = varlist
|
8
|
+
end
|
9
|
+
|
10
|
+
def render
|
11
|
+
ERB.new(File.read(@filename)).result(binding)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.cp_file src, dest, template_vars = nil
|
16
|
+
dest = "#{dest}#{src.split('/')[-1]}" if dest.end_with? '/'
|
17
|
+
if File.exists? dest
|
18
|
+
puts "File #{dest} already exists. Please delete it and try again."
|
19
|
+
else
|
20
|
+
print "Generating file " + dest + " ... "
|
21
|
+
|
22
|
+
if template_vars
|
23
|
+
renderer = ERBRenderer.new src, template_vars
|
24
|
+
File.open(dest, 'w') {|file| file.write renderer.render}
|
25
|
+
else
|
26
|
+
FileUtils.cp src, dest
|
27
|
+
end
|
28
|
+
|
29
|
+
FileUtils.rm_f "#{File.dirname(dest)}/.keep" if File.exists? "#{File.dirname(dest)}/.keep"
|
30
|
+
puts "Done!"
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def self.continue_confirmation text
|
35
|
+
puts text
|
36
|
+
print "Continue? (Y/n): "
|
37
|
+
input = gets
|
38
|
+
unless input[0].downcase == 'y'
|
39
|
+
puts "\n Aborting..."
|
40
|
+
exit 0
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|