cli-framework 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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: []