Reference Notes of a Ruby Newcomer

Caution: there may be errors.


---------------------------------------------
stuff after => is return value 
(e.g., printed by interactive interpreter irb)

#!/usr/bin/ruby		# begins file

# begins comment

=begin
	these lines are
	ignored by interpreter
=end

__END__
	all subsequent lines ignored

---------------------------------------------
"then" is not required except in expression-type "if":

x = if a>0 then b else c end

---------------------------------------------
"do" is required for "loop", and must be 
on same line as loop -- "loop do"

"do" is required for iterators like 

list.each do |x|
  print "#{x} "
end

list.each_index do |x|
  print "#{list[x]} "
end

n=list.size
n.times do |i|
  print "#{list[i]} "
end

n=list.size-1
0.upto(n) do |i|
  print "#{list[i]} "
end

"do" is not required for "while" or "until"

---------------------------------------------
When in doubt, try it out. 

The interpreter is always right.

If you can think it, it's already in Ruby.

  -- msb

---------------------------------------------
if expr
elsif expr
else
end

---------------------------------------------
while expr
	...
end

---------------------------------------------
until expr
	...
end

---------------------------------------------
loop do		# loops forever, "do" is required
	...
end

---------------------------------------------
for var in list
	...
end

list can be a range of integers

n=list.size-1
for
  i in 0..n do
  print "#{list[i]} "
end

---------------------------------------------
break -- breaks out of loop

next -- immediately goes to next iteration (e.g., continue)

retry -- restart entire loop, including condition or list
		Only for "for" or iterator, not "while" or "until".

redo -- redoes current cycle of loop without reevaluating
		condition or getting next item

The redo keyword is the generalized form of retry for loops. 
It works for while and until loops just as retry works for 
iterators. -- The Ruby Way  Seems to contradict previous def.

---------------------------------------------
case "This is a character string."
  when "some value"
    puts "Branch 1"
  when "some other value"
    puts "Branch 2"
  when /char/
    puts "Branch 3"
  else
    puts "Branch 4"
end

prints "Branch 3"

---------------------------------------------
method (function) definition
one arg with default value
puts (string out) call with method string arg inserted
	and capitalized by calling string method

def h(name = "World")
	puts "Hello #{name.capitalize}!"
end

in call of method, parens around args are optional
	unless req'd to avoid confusion

---------------------------------------------
class definition
@xxx is an instance variable

class Greeter
  def initialize(name = "World")
    @name = name
  end
  def say_hi
    puts "Hi #{@name}!"
  end
  def say_bye
    puts "Bye #{@name}, come back soon."
  end
end

---------------------------------------------
object creation and call

g = Greeter.new("Pat")
g.say_hi

Hi Pat!

g.say_bye

Bye Pat, come back soon.

---------------------------------------------
get methods that object responds to

Greeter.instance_methods
=> ["method", "send", "object_id", "singleton_methods",
    "__send__", "equal?", "taint", "frozen?",
    "instance_variable_get", "kind_of?", "to_a",
    "instance_eval", "type", "protected_methods", "extend",
    "eql?", "display", "instance_variable_set", "hash",
    "is_a?", "to_s", "class", "tainted?", "private_methods",
    "untaint", "say_hi", "id", "inspect", "==", "===",
    "clone", "public_methods", "respond_to?", "freeze",
    "say_bye", "__id__", "=~", "methods", "nil?", "dup",
    "instance_variables", "instance_of?"]

get methods defined specifically for object

Greeter.instance_methods(false)
=> ["say_bye", "say_hi"]

---------------------------------------------
test which methods object responds to

g.respond_to?("name")
=> false

g.respond_to?("say_hi")
=> true

g.respond_to?("to_s")
=> true

---------------------------------------------
to view or change instance variables

class Greeter
  attr_accessor :name
end

you can open a class up again and modify it. 
The changes will be present in any new objects you create 
and available in existing objects of that class. 

g = Greeter.new("Andy")

g.respond_to?("name")
=> true

g.respond_to?("name=")
=> true

g.say_hi
Hi Andy!

g.name="Betty"
=> "Betty"

g.name
=> "Betty"

g.say_hi
Hi Betty!

Using attr_accessor defined two new methods -- 
name to get the value, and name= to set it.

---------------------------------------------
test if variable is nil

if @names.nil?
	...

---------------------------------------------
test if variable is a list

if @names.respond_to?("each")
    # @names is a list of some kind, iterate!

---------------------------------------------
iterate over list using "each"

    @names.each do |name|
      puts "Hello #{name}!"
    end

---------------------------------------------
find which methods anything responds to -- 
119 of them for a list!

names = ["Albert", "Brenda", "Charles", "Dave", "Englebert"]

puts(names.methods)

---------------------------------------------
use "join" to print list with designated separator string

puts "Goodbye #{@names.join(", ")}.  Come back soon!"

---------------------------------------------
execute block of code only if file name is same as file name called 
to execute program (i.e., if file is "main").  The rest of the code
in the file can be, e.g., method or class definitions, which can be
used as a library even if the file is not "main".

if __FILE__ == $0
	...

---------------------------------------------
execute system command(s)

`date` = string output of cmd

%x{ls -alF} = string output of cmd

To put value of variable into cmd string, have to use #{}:

x = "poo"
s = %x{echo #{x}}.chomp
print("*", s, "*", "\n")

prints *poo*

To print to the screen via echo have to explictly redirect to /dev/tty:

%x{echo #{chnum} #{chname} #{day} #{date} #{time} #{ampm} > /dev/tty }

but then the %x{} thing itself returns an empty string.

This prints to tty and returns the full string that was printed:

s =	%x{echo #{chnum} #{chname} #{day} #{date} #{time} #{ampm} | tee /dev/tty }.chomp

$?.exitstatus is cmd exit code; $? also contains other info

---------------------------------------------
find the type of an object

n.class

---------------------------------------------
read a file

file = File.open("testfile, "r")

File.open("testfile") do |file|
  file.each_line {|line| puts "Got #{line.dump}" }
end

File.open("mary") do |file|
	file.each_line { |line| 
		puts("Got #{line.dump}")
	}
end

File.open("mary") do |file|
	file.each_line do |line| 
		puts("Got #{line.dump}")
	end
end

File.open("mary") do |file|
	file.each_line do |line| 
		puts("Got #{line}")
	end
end

File.open("mary") do |file|
	n = 1
	file.each_line do |line| 
		puts("#{n} #{line}")
		n = n + 1
	end
end

---------------------------------------------
write a file (with each line = the line of the input file reversed)

File.open($*[0], "r") do |file|
	File.open("goo", "w") do |outfile|
		n = 1
		file.each_line do |line| 
			puts("#{n} #{line.chomp!.reverse!}")
			outfile.puts("#{n} #{line}")
			n = n + 1
		end
	end
end

# do it the old way -- one nested level instead of three

infile  = File.open($*[0], "r")
outfile = File.open("hoo", "w") 
n = 1
while line = infile.gets
	puts("#{n} #{line.chomp!.reverse!}")
	outfile.puts("#{n} #{line}")
	n = n + 1
end

infile.close
outfile.close

---------------------------------------------
cmd-line args

$* is an array of strings, each a cmd-line arg

$*[0] is the first arg

$0 is the name of the main ruby file executed

output each line (numbered) of file named in cmd line

File.open($*[0]) do |file|
	n = 1
	file.each_line do |line| 
		puts("#{n} #{line}")
		n = n + 1
	end
end

---------------------------------------------
strings, substrings

"mark"[1,3] = "ark"
"mark"[1,1] = "a"
"mark"[1] = 97

"mark"[1..3] = "ark"

---------------------------------------------
char replacement/deletion within strings

str.sub(pattern, replacement)

replaces first occurrence of pattern in str by replacement

pattern can be a regexp -- /.../

for deletion, use '' for replacement

gsub replaces all occurrences

sub!, gsub! changes original string

---------------------------------------------
scanf -- dissect string into numeric or string components
		and load them into variables

require "scanf"

field1, field2, ... = str.scanf(formatString)

---------------------------------------------
splitting a string (may be a multi-line list) 
into an array of strings, at delimiter(s)

`ls -alF`.split("\n")[34]

---------------------------------------------
convert integer to byte in string

# make ch a one-byte string, 
# set it's byte to ascii code of A, B, ...
# print it as a string

time_ar.each_index do |i|
	ch = "x"; ch[0] = i + 65
	print(ch, ' ', time_ar[i], "\n")
end

---------------------------------------------
Remove first element of an array!

x="ABCDE"
x=x[1..(x.size - 1)]
puts(x)
puts(x[0..0])

prints
BCDE
B

x=x[1..999]  also works

---------------------------------------------