Ruby ==== (March 2016) Ruby is an interpreted language. Statements end at the end of the line (like Python). The line continuation character is a backslash. Everything is an object. Ruby files are named like "my_file.rb". ## Utilities ## The Ruby REPL is `ibr`. The command line documentation utility is `ri`: % ri Float % ri String.chop The package manager is `gem`. ## Comments ## # This is a single-line comment. foo = "bar" # A comment after a statement =begin ************************************************ This is a much longer multi-line comment that is delineated by the '=begin' and '=end' directives (?) before and after this comment. (The splats are purely decorative.) ************************************************ =end ## Literals ## Simple math: 1 + 3 # => 4 2 * 2 # => 4 3 ** 2 # => 9 (exponential) 5 % 2 # => 1 (remainer) Large numbers can be writting with underscore speparator (just for visual comfort): 1_999_999 == 1999999 String concatenation looks like: "foo" + "bar" # => "foobar" Interpolating a variable in a string looks like: "Hello, #{name}. How are you?" You can do stuff with strings: "hello".capitalize # => "Hello" "hello".reverse # => "olleh" "hello".next # => "hellp" "hello".upcase # => "HELLO" "HELLO".downcase # => "hello" "HellO".swapcase # => "hELLo" "hello".length # => 5 "hello".empty? # => false "hello".include? "hell" # => true "hello".chop # => "hell" "hello".reverse.reverse # => "hello" Type coersion (converting between classes) can be accomplished like this: 3.to_s # => "3" (integer to string) "3".to_i # => 3 (string to integer) 3.14.to_i # => 3 (float to integer) 3.to_f # => 3.0 (integer to float) ## Variables ## Use snake_case for variable and method names (and file/directory names): my_foo = "Bar" new_my_foo += "Baz" # => "BarBaz" All caps constants: PI = 3.14159265 Global variables begin with a dollar sign: $global_variable = "foo" Symbols start with a colon. :a_symbol Using symbols in an array of hashes: widgets = [ {:color => 'red', :weight => 3}, {:color => 'blue', :weight => 22}, {:color => 'green', :weight => 11}, ] widgets.sort_by { |w| w[:color]}.each do |w| puts "The weight is #{w[:weight]} pounds." end Arrays: foo = ["foo", "bar", "baz", "bat"] foo[0] # => "foo" Arrays can contain mixed classes of objects: bar = ["fred", 3, foo] Some array methods: foo.push('baz') foo.length # => 4 foo.sort foo.reverse foo.delete(3) # Deletes all array element == 3. foo + ["nerf"] # => ["foo", "bar", "baz", "bat", "nerf"] foo - ["bar"] # => ["foo", "baz", "bat", "nerf"] Populate an array: my_array = [] for i in 0..99 do my_array[i] = 1 end Hashes: zoo = { "tiger" => "Mamal", "turtle" => "Reptile", "beetle" => "Insect" } Add one hash element: zoo["whale"] = "Mamal" Iterate through hases like: zoo.each do |key, value| puts key + " : " + value end Hash methods: zoo.each_pair # Same as zoo.each zoo.each_key zoo.each_value Use CamelCase for classes and modules: class MyClass ... end ## Loops ## Do loop: # Prints "foo" three times i = 3 i.times do # i can be a literal, like '3.times do' puts "foo" end While loop: i = 0 while i < 10 puts "Count: " + i.to_s i += 1 # Ruby doesn't have a ++ increment or -- decrement operator. end Iterators: colors = ["red", "blue", "green", "indigo"] colors.each do |color| puts "The color is: " + color end also: colors.length.times do |i| puts "Color: " colors[i] end also: colors.sort.each do |color| puts "Color: " color end Iterate through hases like: zoo.each do |key, value| puts key + " : " + value end ## Conditionals ## if foo == "bar" x = 1 elsif foo == "baz" x = 2 else x = 0 end ## Functions ## Function with no arguments: def doSomething puts "Something" end doSomething # => "Something" Function with arguments: def doSomethingSpecific(thing, my_default = true) if my_default puts thing end end doSomethingSpecific("Pizza") # => "Pizza" Yield: def marines yield("missle turret") yield("bunker") end marines do |m| puts "Unit: " + m end Also: def players yield("Jay", "LaBelle") yield("Jake", "Kallie") end players do |first, last| puts first + " " + last end ## Classes ## Variables scopes vis-a-vis classes and objects: - a_local_variable, normal/function scoped - @an_instance_variable, object instance scoped - @@a_class_variable, available to all instances of the class - $a_global_varable, available everywhere Define classes like: class Animal attr_reader :species # Make @species readable from outside object attr_writer :species # Make @species writable outside object # attr_accessor makes the object value both readable and writable def initialize(species) @species = species # The @ denotes a object variable. end end Instantiate an object from a class: myAnimal = Animal.new("tiger") Play with the object: myAnimal.species # => "tiger" myAnimal.species = "rabbit" Another class: class Vehicle attr_accessor :wheels, :topSpeed, :passengerCapacity def initialize @wheels = @topSpeed = @passengerCapacity = "" end define to_s "Vehicle with " + @wheels + " wheels " \ + "and a top speed of " + @topSpeed \ + " and a " + @passengerCapacity + " passenger capacity.\n" end end Custom object iterators: class Garage def each @vehicles.each {|v| yield v} end def eachTopSpeed @vehicles.each {|v| yield v.toSpeed} end end Public and private object methods: class SomeClass def method1 # default to public ... end private # subsequent methods are private. def method2 # private method ... end def method3 # private method ... end public # Set back to public. def method4 # public method ... end end Inheritance: class Motorcycle < Vehicle def initialize(wheels, topSpeed, passengerCapacity, sidecar) super(wheels, topSpeed, passengerCapacity) @sidecar = sidecar end def to_s super + "Sidecar: " + @sidecar end end Exceptions begin statements which may raise exceptions. rescue [exception class names] statements when an exception occurred. rescue [exception class names] statements when an exception occurred. ensure statements that will always run end The last exception is stored in the $! variable (and its type can be determined using $!.type). ## Modules ## You can just use require to include one Ruby file in another. If the other file is a module, though, it provide a protected namespace. module Foo BAR = 3 def Foo.narf # stuff... end end Module used like: require "Foo" x = Foo::narf Note that modules also provide mixin/superclass/multiple-inheritance functionality. ## Tools ## `irb` is the REPL. `pry` is an alternative, though not installed by default. `gem` is the package manager. % gem search ^imap % gem search ^easy_imap$ --details % gem install easy_imap % gem list % gem uninstall easy_imap `ri` is the documentation viewer. % ri rand `rake` is a gem that's like `make` for Ruby. Ruby doesn't seem to have a straight equivalent of Python's virtualenv, but we can get a similar effect by setting some environment variable in activate.sh and deactivate.sh scripts for a project. activate.sh: export OLD_GEMHOME="$GEM_HOME" export GEM_HOME="$PWD/gems" export OLD_GEM_PATH="$GEM_PATH" export GEM_PATH="" export OLD_PATH="$PATH" export PATH="$GEM_HOME/bin:$PATH" deactivate.sh: export GEM_HOME="$OLD_GEM_HOME" unset OLD_GEM_HOME export GEM_PATH="$OLD_GEM_PATH" unset OLD_GEM_PATH export PATH="$OLD_PATH" unset OLD_PATH ## Miscellaneous ## Random: 1 + rand(6) # Random number between 1 and 6 Serialize and de-serialize objects: require 'yaml' x = [1, 2, 3, 4] # Serialize to yaml object: serialized = x.to_yaml # De-searialize from yaml object: de-serialized = YAML.load(serialized) # Serialize to a file: File.open('/path/to/file.yaml', 'w') { |f| f.write(YAML.dump(x)) } # De-serialize from a file: y = YAML.load(File.read('/path/to/file.yaml')) Sqlite: require 'sqlite3' db = SQLite3::Database.new 'mydata.db' # ... or open() for an existing database. db.execute 'CREATE TABLE foo (a, b, c)' db.execute "INSERT INTO foo VALUES ('gold', 'coin', 7)" x = [ ['black', 'cube', 5], ['yellow', 'tire', 8], ['red', 'castle', 4] ] query = db.prepare "INSERT INTO foo (a, b, c) VALUES (?, ?, ?)" x.each do |a| query.execute(a[0], a[1], a[2]) end ## Links ## - http://poignant.guide/ - http://ruby-doc.org/ - https://www.ruby-toolbox.com - http://ruby-doc.com/docs/ProgrammingRuby/ - http://www.rubyist.net/~slagell/ruby/index.html - https://github.com/bbatsov/ruby-style-guide