#####################################################
### USEFUL TRICKS ###################################
#####################################################
# Array.reduce will inject and initial value into a block and pass in each value in turn
# until all values in the array has been iterated i.e
([1] * 10).reduce(0) { |total, current_value| total + current_value } #= 10
# Inject does the same
([1] * 10).inject(0) { |total, current_value| total + current_value } #= 10
# However, if we simply require a sum of all values in the array, we can take advantage of
# Symbol#to_proc as follows:
([1] * 10).reduce(:+) #= 10 # For Ruby 1.8.7 : ([1] * 10).reduce(0, &:+)
([1] * 10).inject(:+) #= 10 # For Ruby 1.8.7 : ([1] * 10).inject(0, &:+)
# We can pass a block to Hash.new to define how values are added to the hash, i.e.
# The following will make a request to a url when it is added as a hash key and save the response
# body
require 'net/http'
http = Hash.new{|h,k| h[k] = Net::HTTP.get_response(URI(k)).body }
http['http://www.google.com'] # makes a request
http['http://www.google.com'] # returns cached value
# Proc.arity returns the number of arguments passed to a Proc, we can use this to distinguish how the
# Proc should be involked, i.e. if it has an argument, pass the current class as the first argument,
# otherwise, use instance_eval to call the procedure in the current scope i.e.
# In the following code we need access to the Person.full_name method, this is within
# the scope from which Document.generate is called so we need to pass document to
# the block as an argument
class Person
attr_accessor :first_name, :last_name
def initialize(f_name, l_name)
@first_name, @last_name = f_name, l_name
end
def full_name
"%s %s" % [first_name, last_name]
end
def save_full_name
Document.generate('full_name.txt') do |doc|
doc.prepend_lines = 'Name: '
full_name
end
end
end
class Document
attr_accessor :prepend_lines
def self.generate(file, *args, &block)
document = self.new(*args)
content = block.arity == 0 ? document.instance_eval(&block) : block.call(document)
document.write(file, content)
end
def write(name, content)
#File.open(name, 'r+') { |f| f.write(prepend_lines + content) }
puts prepend_lines.to_s + content.to_s
end
end
dave = Person.new('Dave', 'Loper')
dave.save_full_name
# However, if we don't need access to anything in the scope from which Document.generate is called
# we can use the no arguments (instance_eval) method
Document.generate('random.txt') do
self.prepend_lines = 'Random number between 1 and 1000: '
Random.rand(1..1000)
end
######################################################
### SHORTCUTS ########################################
######################################################
### See http://ruby.wikia.com/wiki/Special_variable ##
######################################################
# Ruby $: returns an array containing each load path Ruby will search when loading classes,
# it can be used along with the unshift method to prepend path onto the Ruby load path, like so:
$:.unshift activesupport_path
# Ruby $& returns the matched string from the last Regular Expression test, or nil if no RegEx has
# been matched
$& #= nil
/test/i =~ 'testing'
$& #= 'test'
# Ruby $` returns the portion of the string before a match is made, or nil if no RegEx has
# been matched
$` #= nil
/test/i =~ 'retesting'
$` #= 're'
# Ruby $' returns the portion of the string after a match is made, or nil if no RegEx has been matched
$' #= nil
/test/i =~ 'retesting'
$' #= 'ing'
# Ruby has an interesting array accessor on string, where if we are using a regular expression with
# capture, we can return matches with String[RegEx,matchNumber] i.e.
'testing'[/(te)(st)/,0] #= 'test' (matched portion)
'testing'[/(te)(st)/,1] #= 'te' (first match)
'testing'[/(te)(st)/,2] #= 'st' (second match)