clir 0.22.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,127 @@
1
+ class File
2
+
3
+ # @return +nline+ last lines of +path+ file without loading the
4
+ # whole content.
5
+ #
6
+ def self.tail(path, nlines)
7
+ file = open(path, "r")
8
+ buff = 512
9
+ line_count = 0
10
+ # nlines += 1 # to get the last one
11
+ file.seek(0, IO::SEEK_END)
12
+
13
+ offset = file.pos # start at the end
14
+
15
+ while nlines > line_count && offset > 0
16
+ to_read = if (offset - buff) < 0
17
+ offset
18
+ else
19
+ buff
20
+ end
21
+
22
+ file.seek(offset - to_read)
23
+ data = file.read(to_read)
24
+
25
+ data.reverse.each_char do |c|
26
+ if line_count > nlines
27
+ offset += 1
28
+ break
29
+ end
30
+ offset -= 1
31
+ if c == "\n"
32
+ line_count += 1
33
+ end
34
+ end
35
+ end
36
+
37
+ file.seek(offset)
38
+ data = file.read.strip
39
+ ensure
40
+ file.close
41
+ end
42
+
43
+ # def self.readlines_backward(path, &block)
44
+ # #
45
+ # # Si le fichier n'est pas trop gros, on le lit à l'envers
46
+ # # en le chargeant.
47
+ # #
48
+ # if File.size(File.new(path)) < ( 1 << 16 )
49
+ # self.readlines(path).reverse.each do |line|
50
+ # yield line
51
+ # end
52
+ # return
53
+ # end
54
+
55
+ # #
56
+ # # Pour un gros fichier
57
+ # #
58
+
59
+ # # TODO ON POURRAIT METTRE UN BUFFER MOINS GRAND POUR NE PAS
60
+ # # AVOIR DE TROP NOMBREUSES LIGNES EN MÊME TEMPS
61
+ # tail_buf_length = 1 << 16 # 65000 et quelques
62
+ # file = File.new(path)
63
+
64
+ # file.seek(-tail_buf_length,IO::SEEK_END)
65
+ # out = ""
66
+ # count = 0
67
+ # while count <= n # TODO C'EST CETTE BOUCLE QU'IL FAUT DÉVELOPPER JUSQU'EN HAUT
68
+ # buf = file.read( tail_buf_length )
69
+ # count += buf.count("\n")
70
+ # out += buf
71
+ # # 2 * since the pointer is a the end , of the previous iteration
72
+ # file.seek(2 * -tail_buf_length,IO::SEEK_CUR)
73
+ # end
74
+ # # TODO : IL FAUT S'Y PRENDRE MIEUX QUE ÇA POUR TOUT LIRE
75
+ # # CAR MAINTENANT +n+ N'EST PLUS LE NOMBRE DE LIGNES DONNÉES EN
76
+ # # ARGUMENT DE LA MÉTHODE tail ORIGINALE
77
+ # out.split("\n")[-n..-1].each do |line|
78
+ # yield line
79
+ # end
80
+ # end
81
+
82
+ # @return les +n+ dernières lignes d'un fichier
83
+ def tail_lines(n)
84
+ return [] if n < 1
85
+ if File.size(self) < ( 1 << 16 )
86
+ tail_buf_length = File.size(self)
87
+ return self.readlines.reverse[0..n-1]
88
+ else
89
+ tail_buf_length = 1 << 16
90
+ end
91
+ self.seek(-tail_buf_length,IO::SEEK_END)
92
+ out = ""
93
+ count = 0
94
+ while count <= n
95
+ buf = self.read( tail_buf_length )
96
+ count += buf.count("\n")
97
+ out += buf
98
+ # 2 * since the pointer is a the end , of the previous iteration
99
+ self.seek(2 * -tail_buf_length,IO::SEEK_CUR)
100
+ end
101
+ return out.split("\n")[-n..-1]
102
+ end
103
+
104
+
105
+
106
+ # @return [String] the affix's file, i.e. the name without the
107
+ # extension.
108
+ #
109
+ # @example
110
+ # File.affix("myfile.ext") => "myfile"
111
+ # File.affix("pth/to/myfile.ext") => "myfile"
112
+ def self.affix(path)
113
+ File.basename(path,File.extname(path))
114
+ end
115
+
116
+ ##
117
+ # Add +code+ to file at +fpath+
118
+ #
119
+ def self.append(fpath, code)
120
+ begin
121
+ open(fpath,'a') { |f| f.write(code) }
122
+ rescue ENOENT
123
+ raise "Folder #{File.dirname(fpath)} doesn't exist. Unable to write #{fpath} file."
124
+ end
125
+ end
126
+
127
+ end
@@ -0,0 +1,43 @@
1
+ class Integer
2
+
3
+ # @return TRUE if self is inside +ary+ or has key self
4
+ # @param ary {Range|Array|Hash}
5
+ def in?(ary)
6
+ case ary
7
+ when Array, Range
8
+ ary.include?(self)
9
+ when Hash
10
+ ary.key?(self)
11
+ else
12
+ raise "Integer#in? waits for a Array, an Hash or a Range. Given: #{ary.class}."
13
+ end
14
+ end
15
+
16
+ def semaine
17
+ self * 7 * 3600 * 24
18
+ end
19
+ alias :semaines :semaine
20
+ alias :week :semaine
21
+ alias :weeks :semaine
22
+
23
+ # For 4.jours / 4.days
24
+ def jour
25
+ self * 3600 * 24
26
+ end
27
+ alias :jours :jour
28
+ alias :day :jour
29
+ alias :days :jour
30
+
31
+ def heure
32
+ self * 3600
33
+ end
34
+ alias :heures :heure
35
+ alias :hour :heure
36
+ alias :hours :heure
37
+
38
+ def minute
39
+ self * 60
40
+ end
41
+ alias :minutes :minute
42
+
43
+ end
@@ -0,0 +1,231 @@
1
+ # encoding: UTF-8
2
+ =begin
3
+
4
+ Pour simplifier l'affichage de table à la console.
5
+
6
+ @usage
7
+
8
+ t = Labelizor.new(<params>)
9
+
10
+ t.w "<label>", "<valeur>", <options>
11
+ ...
12
+
13
+ t.display # puts
14
+
15
+ NOTES
16
+ =====
17
+ Il y a des options très pratiques comme la propriété :if qui
18
+ permet de n'écrire la ligne que si la condition est vraie. Ça
19
+ permet de ne pas avoir d'identation dans la définition de la
20
+ table.
21
+ Au lieu de :
22
+
23
+ t.w "Mon label", "Ma valeur"
24
+ if cest_vrai
25
+ t.w "Autre label", "Autre valeur"
26
+ end
27
+
28
+ … on utilisera :
29
+
30
+ t.w "Mon label", "Ma valeur"
31
+ t.w "Autre label", "Autre valeur", if:cest_vrai
32
+
33
+ =end
34
+
35
+ class Labelizor
36
+ attr_reader :lines
37
+ attr_reader :config
38
+ #
39
+ # @param params {Hash|Nil}
40
+ # :titre Le titre à donné au tableau
41
+ # :titre_color Couleur à appliquer (bleu par défaut)
42
+ # :separator le sépateur, en général une espace mais peut être
43
+ # aussi un point
44
+ # :delimitor_size {Integer} La longueur par défaut d'une
45
+ # ligne délimitant les données.
46
+ # On peut définir la longueur d'une ligne à la
47
+ # volée avec le 2e paramètres : t.w(:delimitor, 20)
48
+ # :delimitor_char {String} Caractère utilisé pour le délimiteur
49
+ # Par défaut, un signe '='
50
+ # :gutter {Integer} La largeur de la gouttière (4 par défaut)
51
+ # :indentation {Integer} Nombre d'espace en indentation (2 par
52
+ # defaut)
53
+ # :selectable {Boolean} Si true, l'instance rajoute des numéros
54
+ # à chaque item et permet à la fin d'en choisir
55
+ # un : value = Labelizor#display
56
+ #
57
+ def initialize(params = nil)
58
+ defaultize_config(params)
59
+ reset
60
+ end
61
+ def defaultize_config(config)
62
+ @config = config || {}
63
+ @config.key?(:gutter) || @config.merge!(gutter: 4)
64
+ @config.key?(:indentation) || @config.merge!(indentation: 2)
65
+ @config.key?(:separator) || @config.merge!(separator: ' ')
66
+ @config.key?(:delimitor_size) || @config.merge!(delimitor_size: nil)
67
+ @config.key?(:delimitor_char) || @config.merge!(delimitor_char: '=')
68
+ @config.key?(:title_delimitor) || @config.merge!(title_delimitor: '*')
69
+ @config.key?(:delimitor_color) || @config.merge!(delimitor_color: nil)
70
+ @config.key?(:titre_color) || @config.merge!(titre_color: :bleu)
71
+ end
72
+ #
73
+ # Pour écrire dans la table
74
+ #
75
+ # @param label {String}
76
+ # Le label. Certaines valeurs spéciales peuvent être utilisées
77
+ # comme :delimitor (la longueur sera celle définie en second
78
+ # argument ou celle définie par défaut)
79
+ # @param value {Any}
80
+ # La valeur à afficher à droite du label.
81
+ # @param params {Hash}
82
+ # Les paramètres à appliquer. C'est là que la méthode prend
83
+ # tout son sens.
84
+ # Les valeurs définies peuvent être :
85
+ # :color {Symbol} La méthode de couleur (p.e. :vert)
86
+ # :if On n'affiche la ligne que si la valeur est true
87
+ #
88
+ def w(label, value = nil, params = nil)
89
+ params ||= {}
90
+ return if params.key?(:if) && !params[:if]
91
+ #
92
+ # Traitement de valeur de +label+ spéciales
93
+ #
94
+ case label
95
+ when :titre, :title
96
+ value = "\n#{value}\n#{'-'*value.length}"
97
+ add_line [:titre, value, params]
98
+ when :delimitor
99
+ params.merge!(color: delimitor_color) unless params.key?(:color)
100
+ add_line([:delimitor, value, params])
101
+ else
102
+ add_line([label || '', value || '', params])
103
+ end
104
+ end
105
+ alias :<< :w
106
+
107
+ def reset
108
+ @label_width = nil
109
+ @lines = [] # pour se servir encore de l'instance
110
+ @indent = nil
111
+ @values = [] # pour selectable
112
+ end
113
+
114
+ def add_line(dline)
115
+ #
116
+ # Si c'est une table "sélectionnable", il faut ajouter des
117
+ # index pour choisir la valeur
118
+ #
119
+ if selectable?
120
+ @values << dline[1].freeze
121
+ dline[0] = "#{@values.count.to_s.rjust(3)}. #{dline[0]}"
122
+ end
123
+ #
124
+ # Ajout de la ligne
125
+ #
126
+ @lines << dline
127
+ end
128
+ #
129
+ # Méthode pour afficher la table
130
+ def display
131
+ puts "\n"
132
+ #
133
+ # Écriture du titre (if any)
134
+ #
135
+ if @config[:titre]
136
+ sep = @config[:title_delimitor] * (@config[:titre].length + 2)
137
+ titre = ("#{indent + sep}\n#{indent + ' ' + @config[:titre]}\n#{indent + sep}")
138
+ titre = titre.send(@config[:titre_color]) unless config[:titre_color].nil?
139
+ puts titre
140
+ end
141
+ puts "\n"
142
+ #
143
+ # Écriture des lignes
144
+ #
145
+ lines.each do |lab, val, params|
146
+ case lab
147
+ when :titre then lab, val = [val,'']
148
+ when :delimitor
149
+ lab = delimitor_char * delimitor_size(val)
150
+ val = nil
151
+ else
152
+ lab = "#{lab} ".ljust(label_width - 2, config[:separator])
153
+ end
154
+ str = lab + ' ' + formate_value(val, params)
155
+ str = str.send(params[:color]) if params[:color]
156
+ idt = indent(params)
157
+ str = idt + str.split("\n").join("\n#{idt}")
158
+ puts str
159
+ end
160
+ puts "\n\n"
161
+ if selectable?
162
+ wait_for_item_chosen
163
+ end
164
+ reset
165
+ end
166
+ alias :flush :display
167
+
168
+ def wait_for_item_chosen
169
+ choix = nil
170
+ nombre_choix = @values.count
171
+ puts "\n"
172
+ while choix.nil?
173
+ STDOUT.write("\rMémoriser : ")
174
+ choix = STDIN.getch.to_i
175
+ if choix > 0 && choix <= nombre_choix
176
+ break
177
+ else
178
+ STDOUT.write "\r #{choix} n'est pas compris entre 1 et #{nombre_choix}.".rouge
179
+ choix = nil
180
+ end
181
+ end
182
+ STDOUT.write("\r"+' '*80)
183
+ clip @values[choix.to_i - 1]
184
+ puts "\n\n"
185
+ end
186
+
187
+ def delimitor_color
188
+ @delimitor_color ||= config[:delimitor_color]
189
+ end
190
+ def delimitor_size(value = nil)
191
+ return value unless value.nil?
192
+ @delimitor_size ||= config[:delimitor_size] || (label_width - 1)
193
+ end
194
+ def delimitor_char
195
+ @delimitor_char || config[:delimitor_char]
196
+ end
197
+
198
+ def indent(params = {})
199
+ @indent ||= ' ' * config[:indentation]
200
+ case params[:indent]
201
+ when 0 then ''
202
+ when nil then @indent
203
+ when Integer then @indent + ' ' * params[:indent]
204
+ when String then @indent + params[:indent]
205
+ end
206
+ end
207
+ #
208
+ # Formater la valeur en fonction des paramètres
209
+ #
210
+ def formate_value(val, params)
211
+ return '' if val.nil?
212
+ val = €(val) if params[:euros]
213
+ val = formate_date(val) if params[:date]
214
+ return val.to_s
215
+ end
216
+ #
217
+ # Calcul de la longueur du label
218
+ #
219
+ def label_width
220
+ @label_width ||= begin
221
+ maxw = 0; @lines.each do |dline|
222
+ labl = dline[0].length
223
+ maxw = labl if labl > maxw
224
+ end;maxw + config[:gutter]
225
+ end
226
+ end
227
+
228
+ def selectable?
229
+ :TRUE == @isselectable ||= true_or_false(@config[:selectable] == true)
230
+ end
231
+ end
@@ -0,0 +1,90 @@
1
+ module CLI
2
+ class Replayer
3
+ class << self
4
+
5
+ attr_reader :ison
6
+
7
+ ##
8
+ # When the command is not replayed (ie not '_'), CLI initialize
9
+ # the recordings of inputs
10
+ #
11
+ def init_for_recording
12
+ @inputs = []
13
+ end
14
+
15
+ ##
16
+ # @return true if replayer is running
17
+ # (note : it's running when CLI.main_command is '_')
18
+ #
19
+ def on?
20
+ :TRUE == ison
21
+ end
22
+
23
+ ##
24
+ # Start running replayer (with '_' main command)
25
+ def start
26
+ @ison = replayable? ? :TRUE : :FALSE
27
+ end
28
+
29
+ def get_input
30
+ @inputs.pop
31
+ end
32
+
33
+ ##
34
+ # Add a {Any} input value (a Hash, a string, an object, etc.)
35
+ def add_input(input)
36
+ @inputs << input
37
+ end
38
+
39
+ ##
40
+ # @return last inputs for the same command.
41
+ # Use 'get_input' to get the input in order with 'pop'
42
+ def inputs
43
+ @inputs ||= begin
44
+ replayable? || raise('Can’t load inputs values: this command is not replayable.')
45
+ data[:inputs].reverse
46
+ end
47
+ end
48
+
49
+ ##
50
+ # Save inputs at the end of the script
51
+ def save
52
+ table_replay = {
53
+ inputs: inputs,
54
+ data: CLI::get_command_line_data
55
+ }
56
+ File.write(last_command_file, Marshal.dump(table_replay))
57
+ end
58
+
59
+ def data
60
+ @data ||= begin
61
+ load.tap do |table|
62
+ CLI.set_command_line_data(table[:data])
63
+ end
64
+ end
65
+ end
66
+
67
+ def load
68
+ Marshal.load(last_command_file)
69
+ end
70
+
71
+ ##
72
+ # @return TRUE if there is a replayable command
73
+ # Note: it's a replayable command if it exists a
74
+ # '.<app>_lastcommand' file in current folder
75
+ def replayable?
76
+ File.exist?(last_command_file(CLI.command_name))
77
+ end
78
+
79
+ def last_command_file(command_name = nil)
80
+ command_name ||= CLI.command_name
81
+ File.join(commands_folder_path, command_name)
82
+ end
83
+
84
+ def commands_folder_path
85
+ @commands_folder_path ||= mkdir(File.join(ENV["HOME"] || ENV["USERPROFILE"],'.chir_last_commands'))
86
+ end
87
+
88
+ end #/<< self class Replayer
89
+ end #/class Replayer
90
+ end #/module CLI