Module: Linebook::Os::Posix

Includes:
Utilities
Included in:
Linux
Defined in:
lib/linebook/os/posix.rb,
lib/linebook/os/posix/variable.rb,
lib/linebook/os/posix/utilities.rb

Overview

Defines POSIX-compliant functionality, based on the IEEE 1003.1-2008 standard . See the online documentation for:

In addition, the Shell Hater’s Handbook provides a nice index of the relevant information.

Defined Under Namespace

Modules: Utilities Classes: Variable

Instance Method Summary collapse

Methods included from Utilities

#_basename, #_cat, #_cd, #_chgrp, #_chmod, #_chown, #_cmp, #_comm, #_cp, #_cut, #_date, #_directory?, #_dirname, #_echo, #_executable?, #_exists?, #_expand, #_export, #_file?, #_fold, #_grep, #_has_content?, #_head, #_id, #_link?, #_ln, #_ls, #_mkdir, #_mv, #_paste, #_pathchk, #_pwd, #_read, #_readable?, #_rm, #_rmdir, #_sed, #_set, #_sort, #_split, #_tail, #_touch, #_tr, #_tsort, #_uname, #_unexpand, #_uniq, #_unset, #_wc, #_writable?, #basename, #cat, #cd, #chgrp, #chmod, #chown, #cmp, #comm, #cp, #cut, #date, #directory?, #dirname, #echo, #executable?, #exists?, #expand, #export, #file?, #fold, #grep, #has_content?, #head, #id, #link?, #ln, #ls, #mkdir, #mv, #paste, #pathchk, #pwd, #read, #readable?, #rm, #rmdir, #sed, #set, #sort, #split, #tail, #touch, #tr, #tsort, #uname, #unexpand, #uniq, #unset, #wc, #writable?

Instance Method Details

#_append(*args, &block) ⇒ Object

:nodoc:



171
172
173
174
175
# File 'lib/linebook/os/posix.rb', line 171

def _append(*args, &block) # :nodoc:
  str = capture_str { append(*args, &block) }
  str.strip!
  str
end

#_break_(*args, &block) ⇒ Object

:nodoc:



187
188
189
190
191
# File 'lib/linebook/os/posix.rb', line 187

def _break_(*args, &block) # :nodoc:
  str = capture_str { break_(*args, &block) }
  str.strip!
  str
end

#_check_status(*args, &block) ⇒ Object

:nodoc:



207
208
209
210
211
# File 'lib/linebook/os/posix.rb', line 207

def _check_status(*args, &block) # :nodoc:
  str = capture_str { check_status(*args, &block) }
  str.strip!
  str
end

#_check_status_function(*args, &block) ⇒ Object

:nodoc:



230
231
232
233
234
# File 'lib/linebook/os/posix.rb', line 230

def _check_status_function(*args, &block) # :nodoc:
  str = capture_str { check_status_function(*args, &block) }
  str.strip!
  str
end

#_comment(*args, &block) ⇒ Object

:nodoc:



245
246
247
248
249
# File 'lib/linebook/os/posix.rb', line 245

def _comment(*args, &block) # :nodoc:
  str = capture_str { comment(*args, &block) }
  str.strip!
  str
end

#_continue_(*args, &block) ⇒ Object

:nodoc:



261
262
263
264
265
# File 'lib/linebook/os/posix.rb', line 261

def _continue_(*args, &block) # :nodoc:
  str = capture_str { continue_(*args, &block) }
  str.strip!
  str
end

#_elif_(*args, &block) ⇒ Object

:nodoc:



285
286
287
288
289
# File 'lib/linebook/os/posix.rb', line 285

def _elif_(*args, &block) # :nodoc:
  str = capture_str { elif_(*args, &block) }
  str.strip!
  str
end

#_else_(*args, &block) ⇒ Object

:nodoc:



307
308
309
310
311
# File 'lib/linebook/os/posix.rb', line 307

def _else_(*args, &block) # :nodoc:
  str = capture_str { else_(*args, &block) }
  str.strip!
  str
end

#_execute(*args, &block) ⇒ Object

:nodoc:



330
331
332
333
334
# File 'lib/linebook/os/posix.rb', line 330

def _execute(*args, &block) # :nodoc:
  str = capture_str { execute(*args, &block) }
  str.strip!
  str
end

#_exit_(*args, &block) ⇒ Object

:nodoc:



354
355
356
357
358
# File 'lib/linebook/os/posix.rb', line 354

def _exit_(*args, &block) # :nodoc:
  str = capture_str { exit_(*args, &block) }
  str.strip!
  str
end

#_from(*args, &block) ⇒ Object

:nodoc:



366
367
368
369
370
# File 'lib/linebook/os/posix.rb', line 366

def _from(*args, &block) # :nodoc:
  str = capture_str { from(*args, &block) }
  str.strip!
  str
end

#_heredoc(*args, &block) ⇒ Object

:nodoc:



403
404
405
406
407
# File 'lib/linebook/os/posix.rb', line 403

def _heredoc(*args, &block) # :nodoc:
  str = capture_str { heredoc(*args, &block) }
  str.strip!
  str
end

#_if_(*args, &block) ⇒ Object

:nodoc:



426
427
428
429
430
# File 'lib/linebook/os/posix.rb', line 426

def _if_(*args, &block) # :nodoc:
  str = capture_str { if_(*args, &block) }
  str.strip!
  str
end

#_redirect(*args, &block) ⇒ Object

:nodoc:



443
444
445
446
447
# File 'lib/linebook/os/posix.rb', line 443

def _redirect(*args, &block) # :nodoc:
  str = capture_str { redirect(*args, &block) }
  str.strip!
  str
end

#_return_(*args, &block) ⇒ Object

:nodoc:



467
468
469
470
471
# File 'lib/linebook/os/posix.rb', line 467

def _return_(*args, &block) # :nodoc:
  str = capture_str { return_(*args, &block) }
  str.strip!
  str
end

#_section(*args, &block) ⇒ Object

:nodoc:



486
487
488
489
490
# File 'lib/linebook/os/posix.rb', line 486

def _section(*args, &block) # :nodoc:
  str = capture_str { section(*args, &block) }
  str.strip!
  str
end

#_to(*args, &block) ⇒ Object

:nodoc:



498
499
500
501
502
# File 'lib/linebook/os/posix.rb', line 498

def _to(*args, &block) # :nodoc:
  str = capture_str { to(*args, &block) }
  str.strip!
  str
end

#_unless_(*args, &block) ⇒ Object

:nodoc:



510
511
512
513
514
# File 'lib/linebook/os/posix.rb', line 510

def _unless_(*args, &block) # :nodoc:
  str = capture_str { unless_(*args, &block) }
  str.strip!
  str
end

#_until_(*args, &block) ⇒ Object

:nodoc:



533
534
535
536
537
# File 'lib/linebook/os/posix.rb', line 533

def _until_(*args, &block) # :nodoc:
  str = capture_str { until_(*args, &block) }
  str.strip!
  str
end

#_variable(*args, &block) ⇒ Object

:nodoc:



550
551
552
553
554
# File 'lib/linebook/os/posix.rb', line 550

def _variable(*args, &block) # :nodoc:
  str = capture_str { variable(*args, &block) }
  str.strip!
  str
end

#_while_(*args, &block) ⇒ Object

:nodoc:



573
574
575
576
577
# File 'lib/linebook/os/posix.rb', line 573

def _while_(*args, &block) # :nodoc:
  str = capture_str { while_(*args, &block) }
  str.strip!
  str
end

#append(path = nil) ⇒ Object

Adds a redirect to append stdout to a file.



166
167
168
169
# File 'lib/linebook/os/posix.rb', line 166

def append(path=nil)
  redirect(nil, path || '/dev/null', '>>')
  chain_proxy
end

#break_Object

Exit from for, while, or until loop. [Spec]



179
180
181
182
183
184
185
# File 'lib/linebook/os/posix.rb', line 179

def break_()
  #  break
  #  
  write "break\n"

  chain_proxy
end

#check_status(expect_status = 0, fail_status = '$?') ⇒ Object

Adds a check that ensures the last exit status is as indicated. Note that no check will be added unless check_status_function is added beforehand.



195
196
197
198
199
200
201
202
203
204
205
# File 'lib/linebook/os/posix.rb', line 195

def check_status(expect_status=0, fail_status='$?')
  #  <% if function?('check_status') %>
  #  check_status <%= expect_status %> $? <%= fail_status %> $LINENO
  #  
  #  <% end %>
  if function?('check_status') 
  write "check_status "; write(( expect_status ).to_s); write " $? "; write(( fail_status ).to_s); write " $LINENO\n"
  write "\n"
  end 
  chain_proxy
end

#check_status_functionObject

Defines the check status function.



214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
# File 'lib/linebook/os/posix.rb', line 214

def check_status_function()
  function('check_status', nil) do |expected, actual, error, message|
    message.default = '?'
    
    if_ actual.ne(expected) do
      writeln %{echo [#{actual}] #{program_name}:#{message}}
      exit_ error
    end
    
    else_ do
      return_ actual
    end
  end
  chain_proxy
end

#command_str(command, *args) ⇒ Object

Formats a command line command. Arguments are quoted. If the last arg is a hash, then it will be formatted into options using format_options and prepended to args.



54
55
56
57
58
59
60
61
62
# File 'lib/linebook/os/posix.rb', line 54

def command_str(command, *args)
  opts = args.last.kind_of?(Hash) ? args.pop : {}
  args.compact!
  args.collect! {|arg| option_quote(arg.to_s) }
  
  args = options_str(opts) + args
  args.unshift(command)
  args.join(' ')
end

#comment(str) ⇒ Object

Writes a comment.



237
238
239
240
241
242
243
# File 'lib/linebook/os/posix.rb', line 237

def comment(str)
  #  # <%= str %>
  #  
  write "# "; write(( str ).to_s); write "\n"

  chain_proxy
end

#continue_Object

Continue for, while, or until loop. [Spec]



253
254
255
256
257
258
259
# File 'lib/linebook/os/posix.rb', line 253

def continue_()
  #  continue
  #  
  write "continue\n"

  chain_proxy
end

#elif_(expression) ⇒ Object

Chains to if_ to make an else-if statement.



268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
# File 'lib/linebook/os/posix.rb', line 268

def elif_(expression)
  unless match = rewrite(/(\s+)(fi\s*)/)
    raise "elif_ used outside of if_ statement"
  end
  #  <%= match[1] %>
  #  elif <%= expression %>
  #  then
  #  <% indent { yield } %>
  #  <%= match[2] %>
  write(( match[1] ).to_s)
  write "elif "; write(( expression ).to_s); write "\n"
  write "then\n"
  indent { yield } 
  write(( match[2] ).to_s)
  chain_proxy
end

#else_Object

Chains to if_ or unless_ to make an else statement.



292
293
294
295
296
297
298
299
300
301
302
303
304
305
# File 'lib/linebook/os/posix.rb', line 292

def else_()
  unless match = rewrite(/(\s+)(fi\s*)/)
    raise "else_ used outside of if_ statement"
  end
  #  <%= match[1] %>
  #  else
  #  <% indent { yield } %>
  #  <%= match[2] %>
  write(( match[1] ).to_s)
  write "else\n"
  indent { yield } 
  write(( match[2] ).to_s)
  chain_proxy
end

#execute(command, *args) ⇒ Object

Executes a command and checks the output status. Quotes all non-option args that aren’t already quoted. Accepts a trailing hash which will be transformed into command line options.



316
317
318
319
320
321
322
323
324
325
326
327
328
# File 'lib/linebook/os/posix.rb', line 316

def execute(command, *args)
  if chain?
    rewrite(trailer)
    write ' | '
  end
  #  <%= command_str(command, *args) %>
  #  
  #  <% check_status %>
  write(( command_str(command, *args) ).to_s)
  write "\n"
  check_status 
  chain_proxy
end

#exit_(status = nil) ⇒ Object

Cause the shell to exit. [Spec]



338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
# File 'lib/linebook/os/posix.rb', line 338

def exit_(status=nil)
  #  <% if status.nil? %>
  #  exit
  #  <% else %>
  #  exit <%= status %>
  #  <% end %>
  #  
  if status.nil? 
  write "exit\n"
  else 
  write "exit "; write(( status ).to_s); write "\n"
  end 

  chain_proxy
end

#from(path) ⇒ Object

Assigns stdin to the file.



361
362
363
364
# File 'lib/linebook/os/posix.rb', line 361

def from(path)
  redirect(nil, path, '<')
  chain_proxy
end

#function(name, method_name = name) ⇒ Object

Defines a function from the block. The block content is indented and cleaned up some to make a nice function definition.



111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
# File 'lib/linebook/os/posix.rb', line 111

def function(name, method_name=name)
  str = capture_str { indent { yield(*signature(Proc.new.arity)) } }
  function = %{#{name}() {\n#{str.chomp("\n")}\n}}
  
  if function?(name)
    unless functions[name] == function
      raise "function already defined: #{name.inspect}"
    end
  else
    functions[name] = function
    
    if method_name
      instance_eval %{
        def self.#{method_name}(*args)
          execute '#{method_name}', *args
          chain_proxy
        end
      }
    end
  end
  
  writeln function
  name
end

#function?(name) ⇒ Boolean

Returns true if a function with the given name is defined.

Returns:

  • (Boolean)


137
138
139
# File 'lib/linebook/os/posix.rb', line 137

def function?(name)
  functions.has_key?(name)
end

#functionsObject

A hash of functions defined for self.



105
106
107
# File 'lib/linebook/os/posix.rb', line 105

def functions
  @functions ||= {}
end

#heredoc(options = {}) ⇒ Object

Makes a heredoc statement surrounding the contents of the block. Options:

delimiter   the delimiter used, by default HEREDOC_n where n increments
outdent     add '-' before the delimiter
quote       quotes the delimiter


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/linebook/os/posix.rb', line 377

def heredoc(options={})
  tail = chain? ? rewrite(trailer) {|m| write ' '; m[1].lstrip } : nil
  
  unless options.kind_of?(Hash)
    options = {:delimiter => options}
  end
  
  delimiter = options[:delimiter] || begin
    @heredoc_count ||= -1
    "HEREDOC_#{@heredoc_count += 1}"
  end
  #  <<<%= options[:outdent] ? '-' : ' '%><%= options[:quote] ? "\"#{delimiter}\"" : delimiter %><% outdent(" # :#{delimiter}:") do %>
  #  <% yield %>
  #  <%= delimiter %><% end %>
  #  
  #  <%= tail %>
  #  
  write "<<"; write(( options[:outdent] ? '-' : ' ').to_s); write(( options[:quote] ? "\"#{delimiter}\"" : delimiter ).to_s);  outdent(" # :#{delimiter}:") do ; write "\n"
  yield 
  write(( delimiter ).to_s);  end 
  write "\n"
  write(( tail ).to_s)

  chain_proxy
end

#if_(expression) ⇒ Object

Executes the block when the expression evaluates to zero.



410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
# File 'lib/linebook/os/posix.rb', line 410

def if_(expression)
  #  if <%= expression %>
  #  then
  #  <% indent { yield } %>
  #  fi
  #  
  #  
  write "if "; write(( expression ).to_s); write "\n"
  write "then\n"
  indent { yield } 
  write "fi\n"
  write "\n"

  chain_proxy
end

#option?(str) ⇒ Boolean

Returns true if the str is an option (ie it begins with - or +).

Returns:

  • (Boolean)


46
47
48
49
# File 'lib/linebook/os/posix.rb', line 46

def option?(str)
  c = str[0]
  c == ?- || c == ?+
end

#option_quote(str) ⇒ Object

Encloses the arg in quotes unless the arg is an option or already quoted (see option? and quoted?).



41
42
43
# File 'lib/linebook/os/posix.rb', line 41

def option_quote(str)
  option?(str) ? str : quote(str)
end

#options_str(opts) ⇒ Object

Formats a hash key-value string into command line options using the following heuristics:

  • Prepend ‘–’ to mulit-char keys and ‘-’ to single-char keys (unless they already start with ‘-’).

  • For true values return the ‘–key’

  • For false/nil values return nothing

  • For all other values, quote (unless already quoted) and return ‘–key

"value"'

In addition, key formatting is performed on non-string keys (typically symbols) such that underscores are converted to dashes, ie :some_key => ‘some-key’. Note that options are sorted, such that short options appear after long options, and so should ‘win’ given typical option processing.



78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
# File 'lib/linebook/os/posix.rb', line 78

def options_str(opts)
  options = []
  
  opts.each do |(key, value)|
    unless key.kind_of?(String)
      key = key.to_s.gsub('_', '-')
    end
    
    unless key[0] == ?-
      prefix = key.length == 1 ? '-' : '--'
      key = "#{prefix}#{key}"
    end
    
    case value
    when true
      options << key
    when false, nil
      next
    else
      options << "#{key} #{quote(value.to_s)}"
    end
  end
  
  options.sort
end

#program_nameObject

Returns “$0”, the program name.



25
26
27
# File 'lib/linebook/os/posix.rb', line 25

def program_name
  Variable.new(0)
end

#quote(str) ⇒ Object

Encloses the arg in quotes, unless already quoted (see quoted?).



30
31
32
# File 'lib/linebook/os/posix.rb', line 30

def quote(str)
  quoted?(str) ? str : "\"#{str}\""
end

#quoted?(str) ⇒ Boolean

Returns true if the str is quoted (either by quotes or apostrophes).

Returns:

  • (Boolean)


35
36
37
# File 'lib/linebook/os/posix.rb', line 35

def quoted?(str)
  str =~ /\A".*"\z/ || str =~ /\A'.*'\z/ ? true : false
end

#redirect(source, target, redirection = '>') ⇒ Object

Makes a redirect statement.



433
434
435
436
437
438
439
440
441
# File 'lib/linebook/os/posix.rb', line 433

def redirect(source, target, redirection='>')
  source = source.nil? || source.kind_of?(Fixnum) ? source : "#{source} "
  target = target.nil? || target.kind_of?(Fixnum) ? "&#{target}" : " #{target}"
  
  match = chain? ? rewrite(trailer) : nil
  write " #{source}#{redirection}#{target}"
  write match[1] if match
  chain_proxy
end

#return_(status = nil) ⇒ Object

Return from a function. [Spec]



451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
# File 'lib/linebook/os/posix.rb', line 451

def return_(status=nil)
  #  <% if status.nil? %>
  #  return
  #  <% else %>
  #  return <%= status %>
  #  <% end %>
  #  
  if status.nil? 
  write "return\n"
  else 
  write "return "; write(( status ).to_s); write "\n"
  end 

  chain_proxy
end

#section(name = "") ⇒ Object

Write a comment to delimit sections. The comment takes the format:

#### name ###


476
477
478
479
480
481
482
483
484
# File 'lib/linebook/os/posix.rb', line 476

def section(name="")
  n = (78 - name.length)/2
  str = "-" * n
  #  #<%= str %><%= name %><%= str %><%= "-" if name.length % 2 == 1 %>
  #  
  write "#"; write(( str ).to_s); write(( name ).to_s); write(( str ).to_s); write(( "-" if name.length % 2 == 1 ).to_s); write "\n"

  chain_proxy
end

#signature(arity) ⇒ Object

Returns an array of positional variables for use as inputs to a function block. Splat blocks are supported; the splat expression behaves like $*.



143
144
145
146
147
148
149
150
151
152
153
154
155
# File 'lib/linebook/os/posix.rb', line 143

def signature(arity)
  variables = Array.new(arity.abs) {|i| var(i+1) }
  
  if arity < 0
    # This works for defaults...
    # $(shift 1; echo ${*:-NONE})
    # You can't do this:
    # ${$(shift 1; echo $*):-NONE}
    variables[-1] = "$(shift #{arity.abs - 1}; echo $*)"
  end
  
  variables
end

#to(path = nil) ⇒ Object

Adds a redirect of stdout to a file.



493
494
495
496
# File 'lib/linebook/os/posix.rb', line 493

def to(path=nil)
  redirect(nil, path || '/dev/null')
  chain_proxy
end

#trailerObject



161
162
163
# File 'lib/linebook/os/posix.rb', line 161

def trailer
  /(\s*(?:\ncheck_status.*?\n\s*)?)\z/
end

#unless_(expression) ⇒ Object

Executes the block when the expression evaluates to a non-zero value.



505
506
507
508
# File 'lib/linebook/os/posix.rb', line 505

def unless_(expression)
  if_("! #{expression}") { yield }
  chain_proxy
end

#until_(expression) ⇒ Object

Executes the block until the expression evaluates to zero.



517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
# File 'lib/linebook/os/posix.rb', line 517

def until_(expression)
  #  until <%= expression %>
  #  do
  #  <% indent { yield } %>
  #  done
  #  
  #  
  write "until "; write(( expression ).to_s); write "\n"
  write "do\n"
  indent { yield } 
  write "done\n"
  write "\n"

  chain_proxy
end

#var(name) ⇒ Object



157
158
159
# File 'lib/linebook/os/posix.rb', line 157

def var(name)
  Variable.new(name)
end

#variable(key, value) ⇒ Object

Set a variable.



540
541
542
543
544
545
546
547
548
# File 'lib/linebook/os/posix.rb', line 540

def variable(key, value)
  #  <%= key %>=<%= quote(value) %>
  #  
  #  
  write(( key ).to_s); write "="; write(( quote(value) ).to_s)
  write "\n"

  chain_proxy
end

#while_(expression) ⇒ Object

Executes the block while the expression evaluates to zero.



557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
# File 'lib/linebook/os/posix.rb', line 557

def while_(expression)
  #  while <%= expression %>
  #  do
  #  <% indent { yield } %>
  #  done
  #  
  #  
  write "while "; write(( expression ).to_s); write "\n"
  write "do\n"
  indent { yield } 
  write "done\n"
  write "\n"

  chain_proxy
end