clir 0.22.0

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.
@@ -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