Skip to content

Latest commit

 

History

History
510 lines (309 loc) · 10.9 KB

RUBY.md

File metadata and controls

510 lines (309 loc) · 10.9 KB

All About Ruby

  • Use two spaces per indent. Never use tabs for indent.

  • Anything following a # in the code is a comment.

  • Ruby also supports multiline comments delimited by =begin and =end, but # comments are more commonly used.

  • Use lowercase_words_separated_by_underscores for methods, arguments, and variables, including instance variables.

  • Use CamelCase for class names.

  • Use ALL_UPPERCASE for constants.

  • If you are defining—or calling—a method with no parameters, leave the parentheses off.

  # Defining
  def words
    @content.split
  end

  # Calling
  words
  • Generally leave off paranthesis for conditional statements.
  if words.size < 100
    puts 'The document is not very long.'
  end
  • If your block consists of a single statement, fold the whole statement into a single line and delimit the block with braces.
  10.times { |n| puts "The number is #{n}" }
  • For a multistatement block, spread the block out over a number of lines, and use the do/end form.
  10.times do |n|
    puts "The number is #{n}"
    puts "Twice the number is #{n*2}"
  end
  • Getting used to 'unless' might take some time.
  def title=( new_title )
    # if not this then do that
    if not new_title.blank?
      @title = new_title
    end
  end

  def title=( new_title )
    # do this unless that.
    unless new_title.blank?
      @title = new_title
    end
  end
  • 'while' & 'until' works similar to how 'if' & 'unless' work.
  while ! document.is_printed?
    document.print_next_page
  end

  # keeps going until its conditional part becomes true. 
  until document.printed?
    document.print_next_page
  end
  • Single line 'if', 'unless', 'while' & 'until'
  @title = new_title unless new_title.blank?

  @title = new_title if new_title.changed?

  document.print_next_page while document.pages_available?

  document.print_next_page until document.printed?
  • for actually calls the each function internally.
  for font in fonts do
    puts font
  end

  # Use this instead
  fonts.each do |font|
    puts font
  end

  Note: 'for' does not introduce a new scope, while 'each' does.
  • 'case' statement in Ruby
  author = case title
    when 'War And Peace' then 'Tolstoy'
    when 'Romeo And Juliet' then 'Shakespeare'
  end

  # 'case' uses '===' operator for comparison.
  # Classes also use '===' operator for comparison,
  # which makes below snippet quite handy.
  case doc
  when Document
    puts "It's a document!"
  when String
    puts "It's a string!"
  else
    puts "Don't know what it is!"
  • Understanding false in ruby.
  # Only false & nil are treated as false. Everything else is true.

  - 0 is true, as it is neither false or nil.

  - String "false" is also true.
  • Assign variable is if does not exist
  @name = '' unless @name

  # Better way is
  @name ||= ''          	# name  = name || ''

  # This is same as
  count += 10  				# count = count + 1

  Note: 

  ||= will assign value if the varialbe is false. Avoid using ||= for assigning boolean values to avoid false/nil disasters.
  • Ways to create an array of strings without spaces.
  # Contains a lot of ' & ,
  words = [ 'how', 'you', 'doing', '!' ]

  # Easier way is
  words = %w{ how you doing ! }
  • Ways to create an hash of strings without spaces.
  # all are valid ways of creating a hash

  freq = { "I" => 1, "don't" => 1, "like" => 1, "spam" => 963 }

  book_info = { :first_name => 'Russ', :last_name => 'Olsen' }

  book_info = { first_name: 'Russ', last_name: 'Olsen' }
  • Arguments of a method can be omitted if defaults are specified.
  def load_font(name, size = 10, new_size = 12)
    puts "name = #{name} & size = #{size} & new_size = #{new_size}"
  end

  # Both are valid calls to the above method
  load_font('Times')              # name = Times & size = 10 & new_size = 12
  load_font('Times',14)           # name = Times & size = 14 & new_size = 12

  Note: Using above technique there is no way to call the method to default value for 2nd argument and specifying the 3rd argument. load_font('Times',nil,14) will take size = nil.

  # Alternative way to handle it would be.
  def load_font(name,size = nil, new_size = nil)
    size     ||= 10
    new_size ||= 12
    
    puts "name = #{name} & size = #{size} & new_size = #{new_size}"
  end

  load_font('Times',nil,14)       # name = Times & size = 10 & new_size = 14
  • Arbitary number of arguments in ruby.
  def echo_all( *args )
    args.each { |arg| puts arg }
  end

  # Expects minimum of 2 arguments. All arguments betweer
  # the first and the last go to middle_args.
  def echo_at_least_two( first_arg, *middle_args, last_arg )
	puts "The first argument is #{first_arg}"
	middle_args.each { |arg| puts "A middle argument is #{arg}" }
	puts "The last argument is #{last_arg}"
  end
  • Arbitary arguments can make method calls simpler in some cases.
  def add_authors( names )
    @author += " #{names.join(' ')}"
  end

  add_authors( [ 'Strunk', 'White' ] )

  # If we use arbitary arguments

  def add_authors( *names )
    @author += " #{names.join(' ')}"
  end

  add_authors( 'Strunk', 'White' )
  • Hash arguments
  def load_font( specification_hash )
    # Load a font according to specification_hash[:name] etc.
  end	

  load_font( { :name => 'times roman', :size => 12 })

  # Can also be called by ommiting the { }, if hash argument comes last.

  load_font( :name => 'times roman', :size => 12 )
  • Running through a collection
  # Array

  words = %w{ how you doing }
  words.each { |word| puts word }

  # Hash

  student =  { name: 'raj', age: 21, class: 9 }

  # If only one argument is passed to the block, it will be an 
  # array of length 2 => [ key, value]
  student.each { |entry| pp entry }	 [:name, 'raj'] [:age, 21] [:class, 9]

  # 2 arguments works as below.
  student.each { |key,value| puts "#{key} => #{value}" }
  • Finding index of an entry in an array.
  word = 'how'
  index = words.find_index { |this_word| word == this_word }
  • Using 'map' to return everything that the block returned
  words = %w { How You Doing }

  words.map { |word| word.size }        # [3, 3, 5]

  words.map { |word| word.downcase }    # ['how', 'you', 'doing']

  • Using 'inject' to pass 2 arguments, first of it is the result returned by the block.
  numbers = [1, 2, 3, 4, 5]

  sum = numbers.inject(0) { |result,number| number + result }		# 15

  # Without passing the argument to inject, inject will skip block call for 1st element.
  sum = numbers.inject { |result,number| number + result }		# 15
  • 'hash' is ordered.
  demo_hash = { :first => "how", :second => "you", :third => "doing" }   # [:first,:second,:third]

  # Order is the same even after below statement.
  demo_hash[:first] = "How"												 # [:first,:second,:third]

  # Order is preserved if we add a element to hash. New element goes to the end.
  demo_hash[:fourth] = "!"												 # [:first,:second,:third,:fourth]
  • Be careful when using collections. If you modify the collection from withing the block, you might get some unexpected results.

  • Different types of string literals.

name = "Harshal"

# Single quote strings can only handle \' delimeter operations.
puts 'Hello \nworld\'s #{name}'  # Hello \nworld's #{name}

# Double quote strings can handle a lot of things
puts 'Hello \nworld\'s #{name}' 

Hello 
world's Harshal

# For strings with lots of ' & ", we have %q & %Q

# %q behaves as a single quote for computation
puts 'name = #{name}'		     # name = #{name}
puts %q{name = #{name}}		     # name = #{name}

# %Q behaves as a double quote for computation
puts "name = #{name}"		     # name = Harshal
puts %Q{name = #{name}}		     # name = Harshal

# %q & %Q can be used with other delimiters too.

%q { ... }
%q ( ... )
%q $ ... $

  • Multiline strings
  puts "a multi-line
  string with newline"

  puts %q{another multi-line
  string with new line}

  puts %Q{another multi-line string with \
  no newline}

  puts <<EOF
  This is the beginning of my here document.
  And this is the end.
  EOF

  • String manipulations
  chomp: Removes one trailing newline chars
  chop: Removes one char from end.
  "".chop  => ""
  "".chop! => nil

  "Hello".upcase   => HELLO
  "Hello".downcase => hello
  "Hello".swapcase => hELLO

  "It is warm warm outside".sub("warm","cold")  => "It is cold warm outside"
  "It is warm warm outside".gsub("warm","cold") => "It is cold cold outside"

  "how you doing".split => ["how", "you", "doing"]
  "1:2:3".split(':')    => ["1", "2", "3"]

  @author.each_char {|c| puts c}
  @author.each_byte { |b| puts b }
  @content.each_line { |line| puts line }
  • Regular Expressions
  regular expression in ruby is between / /

  . matches a single character

  [aeiou] will match any single lowercase vowel
  
  [0–9] will match exactly any decimal digit
  
  [a-z] will match any lowercase letter
  
  \d will match any digit, so that \d\d will match any two digit number
  
  \w, where the w stands for “word character,” will match any letter, number or the underscore.

  \s will match any white space character including the vanilla space, the tab, and the newline.

  AM|PM will match either AM or PM

  The (car|boat) is red - Will match both The car is red as well as The boat is red.

  * matches zero or more of the thing that came just before it.

  puts /\d\d:\d\d (AM|PM)/ =~ '10:24 PM' # 0

  puts /PM/ =~ '10:24 PM'  				 # 6

  puts "It matches!" if /AM/i =~ 'am'

  /\AOnce upon a time/ =~ "abc Once upon a time" 		   # nil : \A indicates search at start of string
  /\AOnce upon a time/ =~ "Once upon a time in Mumbai"     # 0
  /Once upon a time/ =~ "abc Once upon a time"   		   # 4
  /Once upon a time\z/ =~ "abc Once upon a time"   		   # 4 : \z indicates string ending with
  /Once upon a time\z/ =~ "Once upon a time abc"		   # nil

  ^. Circumflex character matches two things: beginning of string or beginning of any line within string.

  n $ matches the end of the string or the end of any line within the string,

  .* indicates any number of any characters. Matches anything.

  /.*/  : won't match beyond newline

  /.*/m : will match beyond newline

  ? : matches zero or one of the things that came
  • Symbols
	# Cannot be changed. Only one instance of a symbol is created. Ex. :all referenced from anywhere is the same :all instance.

	# When using strings as hash keys, if the string passed is changed, the string key in hash is preserved.
	# Which is why it makes sense to use symbols as hash keys.

	str = "hello"
	hsh = { str => "world" }
	str = "xyz"
	puts hsh["hello"] # world
  • Use map function to call another method on all the elements of an arrary.
> "hello,world,test".split(",").map(&:length)       # [5,5,4]

> ["Hello","World","Test"].map(&:length)	    # [5,5,4]