Module: Kernel

Defined in:
lib/cocos.rb,
lib/cocos/find_file.rb

Instance Method Summary collapse

Instance Method Details

#_escape_csv(value) ⇒ Object



375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
# File 'lib/cocos.rb', line 375

def _escape_csv(value)
  ## auto-convert to string or let code fail on nil or such?
  ##  or use value.to_str - why? why not?
  value = value.to_s

   ## note - double double quotes (") for now only
   ##  check
   ##    -  escape newline (lf) as \n or keep it literal - why? why not?
   ##            what about  \r carriage return (cr)
   ##
   ##  add value.match?(/\A\s|\s\z/) ||
   ##    to preserve leading/trailing spaces in value ???
   ##    e.g.   _a_ becomes "_a_" written out
   ##
   ##  quote empty strings or keep them empty
   ##   what about nil - for now empty string too
   ##    add nil_value option e.g. 'n/a' or such
   ##     and quote_empty true|false - why? why not?
  if value.include?(',')  ||
     value.include?('"')  ||
     value.include?("\n") ||
     value.include?("\r")
    '"' + value.gsub('"', '""') + '"'
  else
    value
  end
end

#download_blob(url) ⇒ Object

alias_method :read_bin, :read_blob



210
211
212
# File 'lib/cocos.rb', line 210

def download_blob( url )
   wget!( url ).blob
end

#download_csv(url, sep: nil) ⇒ Object

note - use explicit download for now



86
87
88
89
90
91
92
# File 'lib/cocos.rb', line 86

def download_csv( url, sep: nil )
  opts = {}
  opts[:sep] = sep  if sep

  parse_csv( download_text( url ),
              **opts )
end

#download_data(url) ⇒ Object



107
108
109
# File 'lib/cocos.rb', line 107

def download_data( url )
  parse_data( download_text( url ))
end

#download_ini(url) ⇒ Object Also known as: download_conf



172
173
174
# File 'lib/cocos.rb', line 172

def download_ini( url )
   parse_ini( download_text( url ))
end

#download_json(url) ⇒ Object



140
141
142
# File 'lib/cocos.rb', line 140

def download_json( url )
  parse_json( download_text( url ))
end

#download_lines(url, chomp: false) ⇒ Object



235
236
237
# File 'lib/cocos.rb', line 235

def download_lines( url, chomp: false )
  parse_lines( download_text( url ), chomp: chomp )
end

#download_tab(url) ⇒ Object



121
122
123
# File 'lib/cocos.rb', line 121

def download_tab( url )
  parse_tab( download_text( url ))
end

#download_text(url) ⇒ Object Also known as: download_txt



193
194
195
# File 'lib/cocos.rb', line 193

def download_text( url )
  wget!( url ).text
end

#download_yaml(url) ⇒ Object Also known as: download_yml



154
155
156
# File 'lib/cocos.rb', line 154

def download_yaml( url )
   parse_yaml( download_text( url ))
end

#find_dir(name, path: []) ⇒ Object



55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
# File 'lib/cocos/find_file.rb', line 55

def find_dir( name, path: [] )
    dirpath = File.expand_path( name )
    return dirpath   if Dir.exist?( dirpath )

##  note - if name starts with / or \ assume it's absolute!!
##    do NOT search!!!
##     note - search still works for
##               ./austria  or ../austria or such
##
##  todo/check/fix-fix-fix
##     is there a File.absolute? or such method for reuse??
##
##  todo/fix-fix-fix add absolute check upstream to find_file too!!!
   ## return nil    if name.start_with?( %r{[/\\]} )
   ##  note - Pathname#absolute? is basically !Pathname#relative? !!!
      return nil    if Pathname.new(name).absolute?

    path.each do |basedir|
        ## todo/check -  always make sure basedir is an absolute/expanded path - why? why not?
        dirpath = File.expand_path( name, basedir )
        return dirpath   if Dir.exist?( dirpath )
    end

    nil   ## return nil if not found
end

#find_file(name, path:) ⇒ Object

note - always expand path for now and return absolute path!

note - do NOT search path if name passed in is absolute!!!


36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
# File 'lib/cocos/find_file.rb', line 36

def find_file( name, path: )
    filepath = File.expand_path( name )
    return filepath   if File.file?( filepath )

##  note - if name starts with root / or c:\
##          assume it's absolute - handle by Pathname lib for now
##    do NOT search!!!
    return nil    if Pathname.new(name).absolute?

    path.each do |basedir|
        filepath = File.expand_path( name, basedir )
        return filepath   if File.file?( filepath )
    end

    nil   ## return nil if not found
end

#find_file!(name, path:) ⇒ Object

Raises:

  • (Errno::ENOENT)


18
19
20
21
22
# File 'lib/cocos/find_file.rb', line 18

def find_file!( name, path: )
    filepath = find_file( name, path: path )
    raise Errno::ENOENT, "file #{name.inspect} not found; looking in path #{path.inspect}"   if filepath.nil?
    filepath
end

#load_env(path = './.env') ⇒ Object

todo/check - change path to *paths=

                 and support more files - why? why not?

note - use File.file? instead of File.exist?
            will avoid matching directories!


260
261
262
263
264
265
266
267
268
269
270
271
# File 'lib/cocos.rb', line 260

def load_env( path='./.env' )
  if File.file?( path )
     puts "==> loading .env settings..."
     env = read_env( path )
     puts "    applying .env settings... (merging into ENV)"
     pp env
     ## note: will only add .env setting if NOT present in ENV!!!
     env.each do |k,v|
         ENV[k] ||= v
     end
  end
end

#parse_csv(str, sep: nil) ⇒ Object



76
77
78
79
80
81
# File 'lib/cocos.rb', line 76

def parse_csv( str, sep: nil )
  opts = {}
  opts[:sep] = sep  if sep

  CsvHash.parse( str, **opts )
end

#parse_data(str) ⇒ Object



103
104
105
# File 'lib/cocos.rb', line 103

def parse_data( str )
  Csv.parse( str )
end

#parse_env(str) ⇒ Object



246
247
248
# File 'lib/cocos.rb', line 246

def parse_env( str )
   EnvParser.load( str )
end

#parse_ini(str) ⇒ Object Also known as: parse_conf



168
169
170
# File 'lib/cocos.rb', line 168

def parse_ini( str )
  INI.load( str )
end

#parse_json(str) ⇒ Object



136
137
138
# File 'lib/cocos.rb', line 136

def parse_json( str )
  JSON.parse( str )
end

#parse_lines(str, chomp: false) ⇒ Object



231
232
233
# File 'lib/cocos.rb', line 231

def parse_lines( str, chomp: false )
  str.lines( chomp: chomp )
end

#parse_tab(str) ⇒ Object



117
118
119
# File 'lib/cocos.rb', line 117

def parse_tab( str )
  Tab.parse( str )
end

#parse_yaml(str) ⇒ Object Also known as: parse_yml



150
151
152
# File 'lib/cocos.rb', line 150

def parse_yaml( str )
  YAML.load( str )
end

#read_blob(path) ⇒ Object



202
203
204
205
206
# File 'lib/cocos.rb', line 202

def read_blob( path )
    File.open( path, 'rb' ) do |f|
        f.read
    end
end

#read_csv(path, sep: nil) ⇒ Object



69
70
71
72
73
74
# File 'lib/cocos.rb', line 69

def read_csv( path, sep: nil )
  opts = {}
  opts[:sep] = sep  if sep

  CsvHash.read( path, **opts )
end

#read_data(path) ⇒ Object

note: use read_data / parse_data

for alternate shortcut for read_csv / parse_csv w/ headers: false
     returning arrays of strings


99
100
101
# File 'lib/cocos.rb', line 99

def read_data( path )
  Csv.read( path )
end

#read_env(path) ⇒ Object



242
243
244
# File 'lib/cocos.rb', line 242

def read_env( path )
   parse_env( read_text( path ))
end

#read_ini(path) ⇒ Object Also known as: read_conf



164
165
166
# File 'lib/cocos.rb', line 164

def read_ini( path )
   parse_ini( read_text( path ))
end

#read_json(path) ⇒ Object

todo: add symbolize options ???



132
133
134
# File 'lib/cocos.rb', line 132

def read_json( path )
  parse_json( read_text( path ))
end

#read_lines(path, chomp: false) ⇒ Object

todo/check: remove n (orr or rn) from line

 ruby (by default) keeps the newline - follow tradition? why? why not?
 add/offer chomp: true/false option or such - why? why not?
  see String.lines in rdoc

yes, add chomp: true|false option
   note - default is chomp: false (keeping the trailing newline)


227
228
229
# File 'lib/cocos.rb', line 227

def read_lines( path, chomp: false )
  read_text( path ).lines( chomp: chomp )
end

#read_tab(path) ⇒ Object



113
114
115
# File 'lib/cocos.rb', line 113

def read_tab( path )
  Tab.read( path )
end

#read_text(path) ⇒ Object Also known as: read_txt



182
183
184
185
186
187
188
189
190
191
# File 'lib/cocos.rb', line 182

def read_text( path )
  ## note:
  ##  (i) :newline => :lf option
  #      Reads text natively; normalizes all incoming newlines to strict LF (\n)
  ##  (ii) 'bom|' flag
  ##   The 'bom|' flag instructs Ruby to drop the BOM bytes if they exist
    File.open( path, 'r:bom|utf-8', newline: :lf) do |f|
        f.read
    end
end

#read_yaml(path) ⇒ Object Also known as: read_yml

todo/check: use parse_safeyaml or such? (is default anyway?) - why? why not?



146
147
148
# File 'lib/cocos.rb', line 146

def read_yaml( path )
   parse_yaml( read_text( path ))
end

#wget(url, **opts) ⇒ Object



418
419
420
# File 'lib/cocos.rb', line 418

def wget( url, **opts )
  Webclient.get( url, **opts )
end

#wget!(url, **opts) ⇒ Object

add alias www_get or web_get - why? why not?

Raises:

  • (RuntimeError)


423
424
425
426
427
428
429
430
# File 'lib/cocos.rb', line 423

def wget!( url, **opts )
  res = Webclient.get( url, **opts )

  ##  check/todo - use a different exception/error - keep RuntimeError - why? why not?
  raise RuntimeError, "HTTP #{res.status.code} - #{res.status.message}"   if res.status.nok?

  res
end

#write_blob(path, blob) ⇒ Object



297
298
299
300
301
302
303
304
305
306
307
308
# File 'lib/cocos.rb', line 297

def write_blob( path, blob )
  ###
  ## todo/check:  check if data is Webclient.Response?
  ##   if yes use res.blob/body  - why? why not?

  dirname = File.dirname( path )
  FileUtils.mkdir_p( dirname )  unless Dir.exist?( dirname )

  File.open( path, 'wb' ) do |f|
    f.write( blob )
  end
end

#write_csv(path, recs, headers: nil) ⇒ Object

note:

for now write_csv expects array of string arrays
   does NOT support array of hashes for now


336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
# File 'lib/cocos.rb', line 336

def write_csv( path, recs, headers: nil )
  dirname = File.dirname( path )
  FileUtils.mkdir_p( dirname )  unless Dir.exist?( dirname )

  ## note: on windows ruby translates \n to \r\n
  ##          use newline option to use \n everywhere!!
  File.open( path, 'w:utf-8', newline: :lf) do |f|
    if headers     ## e.g. Date,Team 1,FT,HT,Team 2
      f.write( headers.map do |header|
                  _escape_csv( header )
                end.join(',') )
      f.write( "\n" )
    end

    recs.each do |values|
      buf =  values.map do |value|
               _escape_csv( value )
             end.join( ',' )

      f.write( buf )
      f.write( "\n" )
    end
  end
end

#write_json(path, data) ⇒ Object

add writers



280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
# File 'lib/cocos.rb', line 280

def write_json( path, data )
  ###
  ## todo/check:  check if data is Webclient.Response?
  ##   if yes use res.json  - why? why not?

  dirname = File.dirname( path )
  FileUtils.mkdir_p( dirname )  unless Dir.exist?( dirname )

  ## note: pretty print/reformat json
  ## note: on windows ruby translates \n to \r\n
  ##          use newline option to use \n everywhere!!
  File.open( path, 'w:utf-8', newline: :lf) do |f|
     f.write( JSON.pretty_generate( data ))
  end
end

#write_text(path, text) ⇒ Object Also known as: write_txt



313
314
315
316
317
318
319
320
321
322
323
324
325
326
# File 'lib/cocos.rb', line 313

def write_text( path, text )
  ###
  ## todo/check:  check if data is Webclient.Response?
  ##   if yes use res.text  - why? why not?

  dirname = File.dirname( path )
  FileUtils.mkdir_p( dirname )  unless Dir.exist?( dirname )

  ## note: on windows ruby translates \n to \r\n
  ##          use newline option to use \n everywhere!!
  File.open( path, 'w:utf-8', newline: :lf) do |f|
    f.write( text )
  end
end