Module: Kernel

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

Instance Method Summary collapse

Instance Method Details

#_escape_csv(value) ⇒ Object

quote values that incl. a comma

todo/fix - add more escape/quote checks - why? why not?
 check how other csv libs handle value generation

If a field contains

  • a comma (,)

  • a double quote (“)

  • a newline (rn)

then wrap the field in quotes
Inside quoted fields, double every double quote (" → "")


344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
# File 'lib/cocos.rb', line 344

def _escape_csv(value)
  ## auto-convert to string or let code fail on nil or such?
  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



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

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

#download_csv(url, sep: nil) ⇒ Object

note - use explicit download for now



71
72
73
74
75
76
77
# File 'lib/cocos.rb', line 71

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

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

#download_data(url) ⇒ Object



92
93
94
# File 'lib/cocos.rb', line 92

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

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



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

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

#download_json(url) ⇒ Object



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

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

#download_lines(url) ⇒ Object



213
214
215
# File 'lib/cocos.rb', line 213

def download_lines( url )
  parse_lines( download_text( url ))
end

#download_tab(url) ⇒ Object



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

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

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



175
176
177
# File 'lib/cocos.rb', line 175

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

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



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

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

#find_file(name, path:) ⇒ Object

todo/check - expand path and use File.realpath too?

or keep "simple" File.join ?


33
34
35
36
37
38
39
40
41
42
# File 'lib/cocos/find_file.rb', line 33

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

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

    nil   ## return nil if not found
end

#find_file!(name, path:) ⇒ Object

Raises:

  • (Errorno::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 Errorno::ENOENT, "file <#{name}> 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!


237
238
239
240
241
242
243
244
245
246
247
248
# File 'lib/cocos.rb', line 237

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



61
62
63
64
65
66
# File 'lib/cocos.rb', line 61

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

  CsvHash.parse( str, **opts )
end

#parse_data(str) ⇒ Object



88
89
90
# File 'lib/cocos.rb', line 88

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

#parse_env(str) ⇒ Object



223
224
225
# File 'lib/cocos.rb', line 223

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

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



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

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

#parse_json(str) ⇒ Object



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

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

#parse_lines(str) ⇒ Object



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

def parse_lines( str )
  str.lines
end

#parse_tab(str) ⇒ Object



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

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

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



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

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

#read_blob(path) ⇒ Object



184
185
186
187
188
# File 'lib/cocos.rb', line 184

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

#read_csv(path, sep: nil) ⇒ Object

todo: add symbolize options a la read_json? - why? why not?

add sep options


54
55
56
57
58
59
# File 'lib/cocos.rb', line 54

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


84
85
86
# File 'lib/cocos.rb', line 84

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

#read_env(path) ⇒ Object



219
220
221
# File 'lib/cocos.rb', line 219

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

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



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

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

#read_json(path) ⇒ Object

todo: add symbolize options ???



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

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

#read_lines(path) ⇒ 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


205
206
207
# File 'lib/cocos.rb', line 205

def read_lines( path )
  read_text( path ).lines
end

#read_tab(path) ⇒ Object



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

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

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



164
165
166
167
168
169
170
171
172
173
# File 'lib/cocos.rb', line 164

def read_text( path )
   ## todo/check: add universal newline mode or such?
   ##  e.g. will always convert all
   ##    newline variants (\n|\r|\n\r) to "universal" \n only
   ##
   ##  add r:bom  - why? why not?
    File.open( path, 'r:utf-8' ) 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?



127
128
129
# File 'lib/cocos.rb', line 127

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

#wget(url, **opts) ⇒ Object

world wide web (www) support



380
381
382
# File 'lib/cocos.rb', line 380

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)


385
386
387
388
389
390
391
392
# File 'lib/cocos.rb', line 385

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



271
272
273
274
275
276
277
278
279
280
281
282
# File 'lib/cocos.rb', line 271

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


308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
# File 'lib/cocos.rb', line 308

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

  File.open( path, 'w:utf-8' ) 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



256
257
258
259
260
261
262
263
264
265
266
267
268
# File 'lib/cocos.rb', line 256

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
  File.open( path, 'w:utf-8' ) do |f|
     f.write( JSON.pretty_generate( data ))
  end
end

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



287
288
289
290
291
292
293
294
295
296
297
298
# File 'lib/cocos.rb', line 287

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 )

  File.open( path, 'w:utf-8' ) do |f|
    f.write( text )
  end
end