cli-framework 0.0.1

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 (3) hide show
  1. checksums.yaml +7 -0
  2. data/bin/cli +1059 -0
  3. metadata +59 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: e378c6588d51d7390a41c7fd7c7984fe5708ab44
4
+ data.tar.gz: e78c30a2b5fc8f5fd69e1a1e85062a337f4fc15b
5
+ SHA512:
6
+ metadata.gz: 74fc1951add43ae050bd186e1f42dbc6af3d8b6b0d363b3a849e77a7aa7a88e201d4c22802eb1a5d4055deed23e42b6683fb3cd2554b7c0b2272d09db38ed5ce
7
+ data.tar.gz: 1fb29e9a371716a752e927040b2d799ca997df8e5612e18346aec8b258daa40612a34b1d899d7abef46a68e09f2b6beae8ae156a3ad69911b4b6714f60c403b4
data/bin/cli ADDED
@@ -0,0 +1,1059 @@
1
+ # puts here all gem that you will need for the command line
2
+ # require "xyz"
3
+ #
4
+ module CommandLineConfig
5
+ Name ||= "cli"
6
+ Version ||= "0.0.1"
7
+ Color ||= 'yellow'
8
+ Otherwise ||= "help"
9
+ BeforeInit ||= ['check.rb'] #execute scripts before initilatizing the cli
10
+ Special ||= [['-v','version'], ['-help','help']]
11
+ end
12
+
13
+
14
+
15
+ require "terminal-table"
16
+
17
+ module CommandLineUtils
18
+ extend self
19
+
20
+ @rendered = ""
21
+
22
+ KEYS = {
23
+ " " => "space",
24
+ "\t" => "tab", # or ctrl + I on mac
25
+ "\r" => "return",
26
+ "\n" => "linefeed", # or ctrl + J on mac
27
+ "\e" => "escape",
28
+ "\e[A" => "up",
29
+ "\e[B" => "down",
30
+ "\e[C" => "right",
31
+ "\e[D" => "left",
32
+ "\177" => "backspace",
33
+ "\003" => "ctrl-c", # ctrl + c
34
+ "\004" => "ctrl-d", # ctrl + d
35
+ }
36
+
37
+ # Read a character the user enters on console. This call is synchronous blocking.
38
+ # This is taken from: http://www.alecjacobson.com/weblog/?p=75
39
+ def read_char
40
+ begin
41
+ # save previous state of stty
42
+ old_state = `stty -g`
43
+ # disable echoing and enable raw (not having to press enter)
44
+ system "stty raw -echo"
45
+ c = STDIN.getc.chr
46
+ # gather next two characters of special keys
47
+ if(c=="\e")
48
+ extra_thread = Thread.new{
49
+ c = c + STDIN.getc.chr
50
+ c = c + STDIN.getc.chr
51
+ }
52
+ # wait just long enough for special keys to get swallowed
53
+ extra_thread.join(0.00001)
54
+ # kill thread so not-so-long special keys don't wait on getc
55
+ extra_thread.kill
56
+ end
57
+ rescue => ex
58
+ puts "#{ex.class}: #{ex.message}"
59
+ puts ex.backtrace
60
+ ensure
61
+ # restore previous state of stty
62
+ system "stty #{old_state}"
63
+ end
64
+ return c
65
+ end
66
+
67
+ # Read a keypress on console. Return the key name (e.g. "space", "a", "B")
68
+ # Params:
69
+ # +with_exit_codes+:: +Bool+ whether to throw Interrupts when the user presses
70
+ # ctrl-c and ctrl-d. (true by default)
71
+ def read_key with_exit_codes = true, return_char = false
72
+ char = read_char
73
+ if with_exit_codes and ( char == "\003" or char == "\004" )
74
+ self.update_line(0,"Process Interrupted"); print "\n"
75
+ exit
76
+ end
77
+ if return_char then char else char_to_raw char end
78
+ end
79
+
80
+ # Get each key the user presses and hand it one by one to the block. Do this
81
+ # as long as the block returns truthy
82
+ # Params:
83
+ # +&block+:: +Proc+ a block that receives a user key and returns truthy or falsy
84
+ def read_key_while_true return_char = false, &block
85
+ STDIN.noecho do
86
+ while true # ask for key and run block until it return false
87
+ @key = CommandLineUtils.read_key
88
+ not_a_command = @key =~ /[^[:print:]]/ # return 0 if it not a recoginzed command
89
+ unless not_a_command == 0 # don't run the block and reask for key if it is not an input or a special in KEYS hash
90
+ returned_value = block.( @key, return_char )
91
+ return if returned_value == false
92
+ else
93
+ true
94
+ end
95
+ end
96
+ end
97
+ end
98
+
99
+ # Get the console window size
100
+ # Returns: [width, height]
101
+ def winsize
102
+ STDIN.winsize
103
+ end
104
+
105
+
106
+ def hide_cursor_during # hides cursor during the execustion of providd block
107
+ print `tput civis` # hide the cursor
108
+ yield # run the provided block
109
+ print `tput cnorm` # finally show the cursor
110
+ end
111
+
112
+ def char_to_raw char
113
+ KEYS.fetch char, char
114
+ end
115
+
116
+ def carriage_return; "\r" end
117
+ def line_up; "\e[A" end
118
+ def clear_line; "\e[0K" end
119
+ def char_left; "\e[D" end
120
+ def char_right; "\e[C" end
121
+
122
+ # modified by me
123
+ @lineNumber = 0
124
+ def update_line returnNumber, line = "" #modifie a line, count from bottom to top
125
+ if returnNumber > @lineNumber
126
+ print "\r\033[#{returnNumber - @lineNumber}A"
127
+ elsif returnNumber < @lineNumber
128
+ print "\r\033[#{@lineNumber - returnNumber}B"
129
+ else
130
+ print "\r"
131
+ end
132
+ print "\033[K#{line}"
133
+ @lineNumber = returnNumber
134
+ end
135
+
136
+ @rendered_lines = []
137
+ def render_line line
138
+ @rendered_lines << line
139
+ puts line
140
+ end
141
+
142
+ def rendered_lines
143
+ @rendered_lines
144
+ end
145
+
146
+ @question
147
+ def renderQuestion question,returnBool = false
148
+ @question = question
149
+ print question
150
+ print "\n" if returnBool
151
+ end
152
+
153
+ def answerQuestion question = @question, answer
154
+ down = @lineNumber
155
+ print "\r\033[B" * down
156
+ @lineNumber = 0
157
+ clear
158
+ clear 1
159
+ CommandLineUtils.update_line(0, "#{question} #{answer}")
160
+ print "\n"
161
+ end
162
+
163
+ # clear the console based on the last text rendered
164
+ def clear lineToClear = nil
165
+ # determine how many lines to move up
166
+
167
+ numberOfLines = lineToClear || @rendered_lines.length
168
+ # jump back to the first position and clear the line
169
+ print carriage_return + ( line_up + clear_line ) * numberOfLines + clear_line
170
+ @rendered_lines = []
171
+ end
172
+
173
+
174
+ end
175
+
176
+
177
+ class String #extend String class in order to add coloration capabilitise
178
+ # colorization
179
+ def colorize(color_code)
180
+ "\e[#{color_code}m#{self}\e[0m"
181
+ end
182
+
183
+ def bold
184
+ colorize(1)
185
+ end
186
+
187
+ def color colorName
188
+ colorize(1) #make it bold first
189
+ case colorName
190
+ when "red"
191
+ colorize(1).colorize(31)
192
+ when "blue"
193
+ colorize(1).colorize(34)
194
+ when "yellow"
195
+ colorize(1).colorize(33)
196
+ when "green"
197
+ colorize(1).colorize(32)
198
+ when "cyan"
199
+ colorize(1).colorize(36)
200
+ when "pink"
201
+ colorize(1).colorize(35)
202
+ when "white"
203
+ colorize(1).colorize(37)
204
+ when "normal"
205
+ colorize(0)
206
+ end
207
+ end
208
+ end
209
+
210
+ class ScreenUtils
211
+
212
+ def self.newline(line = "", return_line = false)
213
+ puts ""
214
+ end
215
+
216
+ def self.removeline(lineNumber = 0)
217
+ lineNumber.times { print "\r" }
218
+ print ""
219
+ end
220
+
221
+ def self.read_char
222
+ begin
223
+ # save previous state of stty
224
+ old_state = `stty -g`
225
+ # disable echoing and enable raw (not having to press enter)
226
+ system "stty raw -echo"
227
+ c = STDIN.getc.chr
228
+ # gather next two characters of special keys
229
+ if(c=="\e")
230
+ extra_thread = Thread.new{
231
+ c = c + STDIN.getc.chr
232
+ c = c + STDIN.getc.chr
233
+ }
234
+ # wait just long enough for special keys to get swallowed
235
+ extra_thread.join(0.00001)
236
+ # kill thread so not-so-long special keys don't wait on getc
237
+ extra_thread.kill
238
+ end
239
+ rescue => ex
240
+ puts "#{ex.class}: #{ex.message}"
241
+ puts ex.backtrace
242
+ ensure
243
+ # restore previous state of stty
244
+ system "stty #{old_state}"
245
+ end
246
+ return c
247
+ end
248
+
249
+ end
250
+
251
+ module Input
252
+ extend self
253
+
254
+ def ask params = { question: "select from options below ...", default: "", suggestion: "" }
255
+ @question = params[:question].bold
256
+ @dialogue = params[:dialogue]
257
+ @type = params[:type] # can be 'confirm' - 'password'
258
+ @defaultColor = params[:color] || CommandLineConfig::Color || "white"
259
+
260
+ @dialogue_msg = params[:dialogue] || ""
261
+ @dialogue_msg = @dialogue_msg.color(@defaultColor)
262
+ @yesColor = params[:yes_color]; @noColor = params[:no_color]
263
+ @defaultAnswer = params[:default];
264
+
265
+ @answer = @defaultAnswer
266
+
267
+ @suggestion = params[:suggestion]
268
+ # CommandLineUtils.hide_cursor_during do # hide the cursor while block is executed
269
+ @line = ["#{@dialogue_msg + @question}", " ", @answer]
270
+ @password = ""; @cursor_position = @answer.length
271
+ render_line true
272
+ if @type == "confirm"
273
+ # @answer
274
+ CommandLineUtils.hide_cursor_during do # hide the cursor while block is executed
275
+ CommandLineUtils.read_key_while_true do |key|
276
+ if key == "return" || key == "Y" || key == "y" || key == "t" || key == "T"
277
+ confirm true
278
+ false
279
+ elsif key == "n" || key == "N" || key == "backspace" || key == "f" || key == "F"
280
+ confirm false
281
+ false
282
+ end
283
+ end
284
+ end
285
+ else
286
+ @keyed = false ;
287
+ CommandLineUtils.read_key_while_true do |key|
288
+ if key == "return"
289
+ @keyed = true
290
+ answer
291
+ elsif key == "backspace"
292
+ @answer.clear unless @keyed
293
+ @cursor_position = 0 unless @keyed
294
+ @keyed = true
295
+ @answer.chop!
296
+ @cursor_position -= 1 unless @cursor_position == 0
297
+ update_line
298
+ elsif key == "space"
299
+ @answer.insert(@cursor_position, " ")
300
+ @keyed = true
301
+ @cursor_position += 1
302
+ update_line
303
+ elsif key == "left" && @cursor_position > 0
304
+
305
+ print "\033[1D"
306
+ @cursor_position -= 1
307
+
308
+ elsif key == "right"
309
+ unless @cursor_position == @answer.length
310
+ print "\033[1C"
311
+ @cursor_position += 1
312
+ end
313
+ else
314
+ @answer.insert(@cursor_position, key)
315
+ @cursor_position += key.length
316
+ @keyed = true
317
+ update_line
318
+ end
319
+ end
320
+ # end
321
+ end
322
+
323
+ yield(@answer) if block_given?
324
+ return @answer
325
+
326
+ end
327
+
328
+ def render_line stay
329
+ if @type == "password"
330
+ print "#{@line[0]+@line[1]}#{'*' * @line[2].length}"
331
+ else
332
+ print @line.join('')
333
+ end
334
+ print "\n"
335
+ update_line
336
+ end
337
+
338
+ def update_line
339
+ if @type == "password"
340
+ CommandLineUtils.update_line(1, "#{@line[0]+@line[1]}#{'*' * @line[2].length}")
341
+ else
342
+ CommandLineUtils.update_line(1, "#{@line.join('')}") #current
343
+ end
344
+ if @cursor_position
345
+ left = @answer.length - @cursor_position
346
+ print "\033[#{left}D" unless left == 0
347
+ end
348
+ end
349
+
350
+ def answer
351
+ if @type == "password"
352
+ CommandLineUtils.answerQuestion(@line[0] , ('*' * @line[2].length).color(@defaultColor))
353
+ else
354
+ CommandLineUtils.answerQuestion(@line[0] ,@line[2].color(@defaultColor))
355
+ end
356
+ return false
357
+ end
358
+
359
+ def confirm bool
360
+ if bool
361
+ @answer = true
362
+ CommandLineUtils.answerQuestion(@line[0] , "yes".color(@yesColor || @defaultColor))
363
+ else
364
+ @answer = false
365
+ CommandLineUtils.answerQuestion(@line[0] , "no".color(@noColor || @defaultColor))
366
+ end
367
+ end
368
+
369
+ end
370
+
371
+ module Choice
372
+ extend self
373
+
374
+ def ask params = { question: "select from options below ...", choices: [], default: 0 }
375
+ # inilialize global params of the list - set default values
376
+ unless params[:choices].length == 0 # dont launch the selection if no choices are provided
377
+ params[:multiple] = false unless params[:multiple] == true
378
+
379
+ @selector = "❱" # for unselected - on select - unselectable
380
+ @check_selector = ["⬡ ","⬢ "]
381
+ @selector = [" "," #{@selector} "]
382
+
383
+ @checkbox = params[:multiple]; if @checkbox && params[:indent]; @selector[1].chop!;end ;
384
+ @checked = @check_selector
385
+ @checked = ["",""] if !@checkbox
386
+ @question = params[:question]; @arrayOfChoice = params[:choices]
387
+ @defaultColor = params[:color] || CommandLineConfig::Color || "white"
388
+ ; @defaultChoiceNumber = params[:default]
389
+ @dialogue_msg = params[:dialogue] || ""
390
+ @dialogue_msg = @dialogue_msg.color(@defaultColor)
391
+
392
+ CommandLineUtils.hide_cursor_during do # hide the cursor while block is executed
393
+
394
+ choice_default_visual
395
+ @current_line_to_update = @reversedArrayOfChoices[@current_line - 1]
396
+
397
+ CommandLineUtils.read_key_while_true do |key|
398
+
399
+ if key == "up"
400
+
401
+ @previous_line = @current_line;
402
+ @current_line = 0 if @current_line >= @reversedArrayOfChoices.length # restart at bottom when "up" on top
403
+ @current_line_to_update = @reversedArrayOfChoices[@current_line]
404
+ @current_line += 1
405
+ update_lines
406
+
407
+
408
+ elsif key == "down"
409
+
410
+ @previous_line = @current_line
411
+ @current_line = @reversedArrayOfChoices.length + 1 if @current_line <= 1 # restart at top when "down" on bottom
412
+ @current_line -= 1;
413
+ @current_line_to_update = @reversedArrayOfChoices[@current_line - 1]
414
+ update_lines
415
+
416
+ elsif key == "space"
417
+
418
+ toggle_select if @checkbox
419
+
420
+ elsif key == "return"
421
+
422
+ answer
423
+
424
+ end
425
+
426
+ key != 'return' && @key != 'escape' && @key != 'backspace' # exit if it returns false
427
+ end
428
+ end
429
+ yield(@index, @choice) if block_given?
430
+ return @index
431
+ end
432
+ end
433
+
434
+ def choice_default_visual
435
+ CommandLineUtils.renderQuestion(@dialogue_msg + @question.bold, true); @lines = []
436
+ @arrayOfChoice.each.with_index do |line, index| # print the default selected choice | print layer
437
+ # inject default values
438
+ @arrayOfChoice[index][:selectable] = true unless line[:selectable] == false
439
+ @arrayOfChoice[index][:color] = @defaultColor unless line[:color]
440
+ @arrayOfChoice[index][:description] = "" unless line[:description]
441
+ @arrayOfChoice[index][:check] = false unless line[:check] # unless check is defaulted
442
+
443
+ # add default visual
444
+ # line template = ["selector", "check", "name", "description"]
445
+ line_to_print = [@selector[0], @checked[0], line[:name], line[:description]]
446
+
447
+ line_to_print[1] = @checked[1] if @checkbox && @arrayOfChoice[index][:check]
448
+ line_to_print[0] = @selector[1] if index == @defaultChoiceNumber
449
+
450
+ if index == @defaultChoiceNumber
451
+ CommandLineUtils.render_line "#{(line_to_print[0]+line_to_print[1]+line_to_print[2]).color(line[:color])}#{line_to_print[3]}"
452
+ elsif !line[:selectable]
453
+ CommandLineUtils.render_line "#{(line_to_print[0]+line_to_print[1]+line_to_print[2]).color('normal')}#{line_to_print[3]}"
454
+ else
455
+ CommandLineUtils.render_line "#{(line_to_print[0]+line_to_print[1]+line_to_print[2]).color('white')}#{line_to_print[3]}"
456
+ end
457
+
458
+ @lines << line_to_print
459
+
460
+ end
461
+ @lines.reverse!
462
+ @reversedArrayOfChoices = @arrayOfChoice.reverse
463
+ @current_line = @arrayOfChoice.length - @defaultChoiceNumber # select default line | compute layer
464
+ @previous_line = @current_line
465
+ end
466
+
467
+ def toggle_select
468
+ new_check_state = !@current_line_to_update[:check]
469
+ color = @current_line_to_update[:color]
470
+ @reversedArrayOfChoices[@current_line - 1][:check] = new_check_state
471
+ @lines[@current_line - 1][1] = (new_check_state ? @checked[1] : @checked[0])
472
+ line = @lines[@current_line - 1]
473
+ CommandLineUtils.update_line(@current_line, "#{(line[0]+line[1]+line[2]).color(color)}#{line[3]}" )#current
474
+ end
475
+
476
+ def update_lines
477
+ previous_line = @lines[@previous_line - 1];
478
+ previous_line[0] = @selector[0]
479
+ current_line = @lines[@current_line - 1];
480
+ current_line[0] = @selector[1]
481
+
482
+ CommandLineUtils.update_line(@current_line, "#{(current_line[0]+current_line[1]+current_line[2]).color(@reversedArrayOfChoices[@current_line - 1][:color])}#{current_line[3]}") #current
483
+ CommandLineUtils.update_line(@previous_line, "#{(previous_line[0]+previous_line[1]+previous_line[2]).color('white')}#{previous_line[3]}")
484
+ end
485
+
486
+ def answer
487
+ if @checkbox # :multiple implementation
488
+ @indexes = []; @choices = []; @answer = false
489
+ @arrayOfChoice.each.with_index { |choice, index| ; if choice[:check] == true
490
+ @indexes << index;
491
+ @choices << choice;
492
+ name = choice[:as] || choice[:name]
493
+ if @answer
494
+ @answer = "#{@answer} - #{name.color(choice[:color])}"
495
+ else
496
+ @answer = "#{name.color(choice[:color])}"
497
+ end
498
+ end
499
+ }
500
+ @answer = "-".color(@defaultColor) unless @answer
501
+ CommandLineUtils.answerQuestion(@answer)
502
+ @index = @indexes; @choice = @choices
503
+ else # normal
504
+ @index = @reversedArrayOfChoices.length - @current_line.to_i;
505
+ choices = @reversedArrayOfChoices.reverse
506
+ @choice = choices[@index];
507
+ @answer = @choice[:as] || @choice[:name]
508
+ CommandLineUtils.answerQuestion("#{@answer}".color(@choice[:color]))
509
+ end
510
+ end
511
+
512
+ end
513
+
514
+
515
+
516
+ class CommandLineInterface
517
+ attr_accessor :name, :version, :color
518
+
519
+ def initialize
520
+ @@cmds = []
521
+ # yield(self) if block_given?
522
+ @name = CommandLineConfig::Name
523
+ @version = CommandLineConfig::Version
524
+ @color = CommandLineConfig::Color || "blue"
525
+ @otherwise = CommandLineConfig::Otherwise || "help"
526
+ @commandInput = Inputs.new
527
+ @first_argument = Inputs.all[0].show if Inputs.all[0]
528
+
529
+
530
+
531
+ if @first_argument
532
+ ## detect special commands
533
+
534
+ redirect_special_cmds @first_argument
535
+
536
+ ## execute normally
537
+
538
+
539
+ @actionExecute = @first_argument.capitalize + "Action"
540
+ CommandAction.actions.each do |action| # compare each actions with the first command
541
+ if action.class.to_s == @actionExecute || action.alias == @first_argument
542
+ executeCommand action
543
+ end
544
+ end
545
+
546
+ ## if action not found
547
+
548
+ error
549
+ else
550
+ error
551
+ end
552
+
553
+
554
+ end
555
+
556
+ def error
557
+ @actionExecute = "ErrorAction"
558
+ CommandAction.actions.each do |action| # compare each actions with the first command
559
+ if action.class.to_s == @actionExecute
560
+ executeCommand action
561
+ end
562
+ end
563
+ end
564
+
565
+ def redirect_special_cmds firstArg
566
+ if CommandLineConfig::Special
567
+
568
+ CommandLineConfig::Special.each do |spcmd| #['-v --v', 'version']
569
+ special_commands = spcmd[0].split(' ')
570
+ special_commands.each do |special|
571
+ if special == firstArg
572
+ @actionExecute = spcmd[1].capitalize + "Action"
573
+ CommandAction.actions.each do |action| # compare each actions with the first command
574
+ if action.class.to_s == @actionExecute || action.alias == firstArg
575
+ executeCommand action
576
+ end
577
+ end
578
+ end
579
+ end
580
+ end
581
+ end
582
+ end
583
+
584
+ def executeCommand action
585
+ inputs = Inputs.all;
586
+ arguments = make_argumentsObj action
587
+ options = make_optionsObj action;
588
+ namespaces = make_namespaceObj action
589
+ action.action inputs, arguments, options, namespaces
590
+ exit
591
+ end
592
+
593
+ def make_argumentsObj cmd # create parameters ['type','subtype'] => { 'type': params1, ... args: [rest of the shit]}
594
+ argumentsObj = {}
595
+ args = InputArgument.all
596
+ cmd.args.each do |param|
597
+ args.delete_at(0)
598
+ argumentsObj[param] = args[0]
599
+
600
+ end
601
+ argumentsObj['args'] = args
602
+ return argumentsObj
603
+ end
604
+
605
+ def make_optionsObj cmd # create { "global": true/false, "special": true/false}
606
+ optionsObj = {}
607
+ options = InputOption.all
608
+ cmd.options.each do |opt|
609
+ opt[0].split(' ').each do |sub|
610
+ options.each do |input|
611
+ optionsObj[opt[1]] = true if sub == input
612
+ end
613
+ end
614
+ optionsObj[opt[1]] = false unless optionsObj[opt[1]]
615
+ end
616
+ return optionsObj
617
+ end
618
+
619
+ def make_namespaceObj cmd # name:space foo:bar => {'name':'space', 'foo':'bar' }
620
+ namespaceObj = []
621
+ InputNamespace.all.each do |namespace|
622
+ namespaceObj << namespace.split(':')
623
+ end
624
+ return namespaceObj
625
+ end
626
+
627
+ def launch commandNameExec
628
+ @@cmds.each do |cmd|
629
+ executeCommand(cmd) if cmd.name == commandNameExec
630
+ end
631
+ end
632
+
633
+
634
+ def self.terminal commandString # call a subprocess that outputs
635
+ system commandString
636
+ end
637
+
638
+
639
+
640
+
641
+
642
+ end
643
+
644
+
645
+ class Inputs
646
+ @@inputs = []
647
+ def initialize
648
+
649
+ if ARGV[0] && ARGV[0].is_namespace? # unNamespace the first arg
650
+ namespaceEls = ARGV[0].split(':')
651
+ ARGV.delete_at(0)
652
+ namespaceEls.each.with_index do |el,index| ; ARGV.insert(0+index, el) ; end
653
+
654
+ end
655
+ ARGV.each.with_index do |arg, index|
656
+ if arg[0] == "-" #detect options
657
+ @@inputs << InputOption.new(index, arg)
658
+ elsif arg.split(':').length >= 2 #detect namespaces
659
+ @@inputs << InputNamespace.new(index, arg)
660
+ else
661
+ @@inputs << InputArgument.new(index, arg)
662
+ end
663
+
664
+ end
665
+ end
666
+
667
+ def self.all
668
+ return @@inputs
669
+ end
670
+ end
671
+
672
+ class InputClass
673
+ def next
674
+ nextIndex = @index + 1
675
+ return Inputs.all[nextIndex] if CommandInput.all[nextIndex]
676
+ end
677
+
678
+ def previous
679
+ prevIndex = @index - 1
680
+ return Inputs.all[prevIndex] if CommandInput.all[prevIndex]
681
+ end
682
+ end
683
+
684
+ class InputOption < InputClass
685
+ @@options = []
686
+ @option
687
+ def initialize index,arg
688
+ @@options << arg
689
+ @option = arg
690
+ @index = index
691
+ end
692
+
693
+ def show
694
+ return @option
695
+ end
696
+
697
+ def self.all
698
+ return @@options
699
+ end
700
+ end
701
+
702
+ class InputNamespace < InputClass
703
+ @@namespaces = []
704
+ @namespace
705
+ def initialize index,arg
706
+ @@namespaces << arg # => 'arg:space'
707
+ @namespace = arg
708
+ @index = index
709
+ end
710
+
711
+ def show
712
+ return @namespace
713
+ end
714
+
715
+ def self.all
716
+ return @@namespaces
717
+ end
718
+ end
719
+
720
+ class InputArgument < InputClass
721
+ @@arguments = []
722
+ @argument
723
+ def initialize index,arg
724
+ @@arguments << arg
725
+ @argument = arg
726
+ @index = index
727
+ end
728
+
729
+ def show
730
+ return @argument
731
+ end
732
+
733
+ def self.all
734
+ return @@arguments
735
+ end
736
+ end
737
+
738
+ class CommandAction
739
+ attr_accessor :description, :options, :args, :alias
740
+ @@actions = []
741
+
742
+ def initialize config
743
+ @description = config[:description]
744
+ @options = config[:options]
745
+ @args = config[:params]
746
+ @alias = config[:alias]
747
+
748
+ @@actions << self
749
+ end
750
+
751
+ def self.register config = Hash.new
752
+ config[:description] = "" unless config[:description]
753
+ config[:options] = [] unless config[:options]
754
+ config[:params] = [] unless config[:params]
755
+ config[:alias] = "" unless config[:alias]
756
+ self.new config
757
+ end
758
+
759
+ def self.actions
760
+ return @@actions
761
+ end
762
+
763
+ end
764
+ module CommandLine extend self
765
+ Action = CommandAction
766
+ end
767
+
768
+ module CommandFile extend self
769
+ Specification = self
770
+ def new; @spec = {};
771
+ yield(self)
772
+ print "\n"
773
+ print @spec
774
+ exit
775
+ end
776
+
777
+ def parameters params; @spec['parameters'] = params; end
778
+ def alias params; @spec['alias'] = params; end
779
+ def description params; @spec['description'] = params ; end
780
+ def option params; @spec['options'] = [] unless @spec['options']; @spec['options'] << params ; end
781
+ def name params; @spec['name'] = params; end
782
+ def execute params; @spec['execute'] = params; end
783
+ def exclude params; @spec['exclude'] = params; end
784
+ end
785
+
786
+ class String #extend String class in order to add coloration capabilitise
787
+ # colorization
788
+ def colorize(color_code)
789
+ "\e[#{color_code}m#{self}\e[0m"
790
+ end
791
+
792
+ def bold
793
+ colorize(1)
794
+ end
795
+
796
+ def color colorName
797
+ colorize(1) #make it bold first
798
+ case colorName
799
+ when "red"
800
+ colorize(1).colorize(31)
801
+ when "blue"
802
+ colorize(1).colorize(34)
803
+ when "yellow"
804
+ colorize(1).colorize(33)
805
+ when "green"
806
+ colorize(1).colorize(32)
807
+ when "cyan"
808
+ colorize(1).colorize(36)
809
+ when "pink"
810
+ colorize(1).colorize(35)
811
+ when "white"
812
+ colorize(1).colorize(37)
813
+ when "normal"
814
+ colorize(0)
815
+ end
816
+ end
817
+
818
+ def is_namespace?
819
+ if self.split(':').length >= 2
820
+ return true
821
+ else
822
+ return false
823
+ end
824
+ end
825
+
826
+ end
827
+
828
+ class ActionAction < CommandLine::Action; register description: "create or overwrite an action",
829
+ alias: 'a',
830
+ params: ['name']
831
+
832
+
833
+ def action inputs, arguments, options, namespaces
834
+ if arguments['name']
835
+ createAction arguments['name'],namespaces if validate arguments['name']
836
+ else
837
+ error
838
+ end
839
+ end
840
+
841
+ def error
842
+ puts 'a valid name has to be provided in order to create the action'
843
+ puts 'use "cli action <name>"'
844
+ end
845
+
846
+ def validate name
847
+ if name.length == 0 || name[/[a-zA-Z]+/] != name
848
+ error
849
+ return false
850
+ else
851
+ return true
852
+ end
853
+ end
854
+
855
+ def register namespaces
856
+ print namespaces
857
+ return " register"
858
+ end
859
+
860
+ def createAction name,namespaces
861
+ puts "creating #{name} action"
862
+ lines = [
863
+ "class #{name.capitalize}Action < CommandLine::Action",
864
+ " register",
865
+ " def action inputs, arguments, options, namespaces",
866
+ " ",
867
+ " end",
868
+ "end",
869
+ ]
870
+
871
+ File.open("lib/actions/#{name}.rb", 'a') do |f|
872
+ lines.each do |line|
873
+ f.print line, "\n"
874
+ end
875
+ end
876
+
877
+ end
878
+ end
879
+
880
+
881
+
882
+
883
+ class BuildAction < CommandLine::Action
884
+ register description: "build the cli"
885
+
886
+
887
+ # description: "this the description of build action"
888
+ # params: ["port"]
889
+ # options: [['-d -deploy','deploy'], ['-i','international']]
890
+
891
+ def action inputs, arguments, options, namespaces
892
+ puts "packing the cli .."
893
+ CommandLineInterface.terminal "rake install"
894
+ end
895
+ end
896
+
897
+
898
+
899
+
900
+ class ErrorAction < CommandLine::Action
901
+ register
902
+
903
+ def action inputs, arguments, options, namespaces
904
+ puts "\"#{inputs[0].show if inputs[0]}\" is not a valid #{CommandLineConfig::Name} Command"
905
+ end
906
+ end
907
+
908
+
909
+
910
+
911
+ class HelpAction < CommandLine::Action
912
+ register
913
+
914
+
915
+ def action inputs, arguments, options, namespaces
916
+ self.help
917
+ end
918
+
919
+ def help
920
+ rows = scanConfig # [{name:" ", "params":"", "description":"saljdn"} ]
921
+ puts "\n #{CommandLineConfig::Name} - #{CommandLineConfig::Version}"
922
+ table style: { :border_x => "", :border_y => "", :border_i => "" } do |row|
923
+ rows.each do |c|
924
+ name = c[:name]; next if name == 'help' || name == "version" || name == "error" || name.nil?
925
+ row.add [name.color(CommandLineConfig::Color) ,c[:params] ,c[:description]]
926
+ end
927
+ # row.separation
928
+ # rows.each do |c|
929
+ # name = c[:name]; if name == 'help' || name == "version"
930
+ # row.add [name ,c[:params] ,c[:description]]
931
+ # end
932
+ # end
933
+
934
+ end
935
+ print "\n"
936
+ #scanning for commandfiles in order to take configuration of each commandString
937
+ #scanning all commands to get thei config
938
+ #output a table
939
+ end
940
+
941
+ def scanConfig
942
+ rows = []
943
+ # cmd.configuration.call() #make config anvailable
944
+ CommandAction.actions.each do |cmd|
945
+ params = ""
946
+ cmd.args.each do |p|
947
+ params += "<#{p}> "
948
+ end
949
+
950
+ name = cmd.class.to_s.downcase.split('action')[0]
951
+ rows << { name: name , params: params, description: cmd.description }
952
+ end
953
+ return rows
954
+ end
955
+
956
+ def table params
957
+
958
+ table = Terminal::Table.new params do |row|
959
+ def row.add params; self.add_row params end
960
+ def row.separation; self.add_separator; end
961
+ yield(row) if block_given?
962
+ end
963
+ puts table
964
+ end
965
+ end
966
+
967
+ class NewAction < CommandLine::Action
968
+ register description: 'create a new cli',
969
+ params: ['name', 'color']
970
+ # options: [['-g --general', 'general']]
971
+
972
+
973
+
974
+ def action inputs, arguments, options, namespaces
975
+ unless arguments['name']
976
+ puts "A name for the cli has to be provided"
977
+ puts " cli new ... <- replace '...' with the name of your cli"
978
+ puts "Don't worry, you can change the name of your cli very easily after if you want so"
979
+ exit
980
+ end
981
+ msg = CommandLineInterface.terminal "git clone -b blank https://github.com/iliasbhal/cli-framework #{arguments['name']}"
982
+ if msg
983
+ # modify the configuration file so it matches the name
984
+ File.open("#{arguments['name']}/lib/configuration.rb", 'a') { |d| ;
985
+ d.truncate(0) # erase all the content of a file
986
+ d.print " module CommandLineConfig", "\n"
987
+ d.print " Name ||= '#{arguments['name']}'","\n"
988
+ d.print " Color ||= 'blue'", "\n"
989
+ d.print " Version ||= '0.0.0'","\n"
990
+ d.print " Else ||= help","\n"
991
+ d.print " Special ||= [['-v','version'], ['-help','help']]","\n"
992
+ d.print "end"
993
+ }
994
+ # enter the folder and modify git
995
+ puts "initilializing git ..."
996
+ Dir.chdir("#{arguments['name']}") do |path|
997
+ `git remote remove origin`
998
+ `git branch -m blank master`
999
+ `git add . && git commit -m "first commit"`
1000
+ `git reset && git init`
1001
+ end
1002
+ puts "done !"
1003
+ end
1004
+ end
1005
+ end
1006
+
1007
+
1008
+ class ServerAction < CommandLine::Action
1009
+ register description: "launch a server localy with power :)",
1010
+ params: ["port"],
1011
+ options: [['-d -deploy','deploy'], ['-i','international']]
1012
+
1013
+
1014
+ def action inputs, arguments, options, namespaces
1015
+ Input.ask question: "what is your name ?",
1016
+ dialogue: "[?] Serverless: ",
1017
+ default: 'john'
1018
+
1019
+ Input.ask question: "what is your name ?",
1020
+ dialogue: "[?] Serverless: ",
1021
+ type: 'password', # can be confirm / password or just nothing
1022
+ default: 'john'
1023
+
1024
+ Input.ask question: "what is your name ?",
1025
+ dialogue: "[?] Serverless: ",
1026
+ type: 'confirm', # YyTt FfNn
1027
+ default: 'Y/N'
1028
+
1029
+ Choice.ask question: 'select from below:', default: 0,
1030
+ dialogue: "[?] Serverless: ",
1031
+ multiple: true,
1032
+ choices: [
1033
+ { name: 'choice one', description: " # not a good choice :p",as: 'jehe'},
1034
+ { name: 'choice two'},
1035
+ { name: 'choice one', description: " # not a good choice :p"},
1036
+ { name: 'choice two'},
1037
+ { name: 'choice one', description: " # not a good choice :p"},
1038
+ { name: 'choice two'},
1039
+ { name: 'choice one', description: " # not a good choice :p"},
1040
+ { name: 'choice two'}
1041
+ ]
1042
+ end
1043
+ end
1044
+
1045
+ class VersionAction < CommandLine::Action
1046
+ register description: "return the version on the cli"
1047
+
1048
+
1049
+ def action inputs, arguments, options, namespaces
1050
+ print inputs, "\n"
1051
+ print arguments, "\n"
1052
+ print options, "\n"
1053
+ print namespaces, "\n"
1054
+ puts CommandLineConfig::Version
1055
+ end
1056
+ end
1057
+
1058
+
1059
+ CommandLineInterface.new
metadata ADDED
@@ -0,0 +1,59 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: cli-framework
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Ilias Bhallil
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2016-10-26 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: terminal-table
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ description: Framework for quickly building a Command line interface
28
+ email:
29
+ - ilias.bhal@gmail.com
30
+ executables:
31
+ - cli
32
+ extensions: []
33
+ extra_rdoc_files: []
34
+ files:
35
+ - bin/cli
36
+ homepage: http://iliasbhallil.github.com
37
+ licenses: []
38
+ metadata: {}
39
+ post_install_message:
40
+ rdoc_options: []
41
+ require_paths:
42
+ - lib
43
+ required_ruby_version: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ required_rubygems_version: !ruby/object:Gem::Requirement
49
+ requirements:
50
+ - - ">="
51
+ - !ruby/object:Gem::Version
52
+ version: '0'
53
+ requirements: []
54
+ rubyforge_project:
55
+ rubygems_version: 2.5.1
56
+ signing_key:
57
+ specification_version: 4
58
+ summary: ''
59
+ test_files: []