├── tricks ├── README.md ├── source_code │ ├── Gemfile │ ├── data.rb │ ├── cycle.rb │ ├── variables_from_a_regex.rb │ ├── print_formatted_with_debug.rb │ ├── enable_garbage_collector_profiler.rb │ ├── lambda_your_own_syntax.rb │ ├── autovivification.rb │ ├── digits.rb │ ├── inject.rb │ ├── head_tail.rb │ ├── smalltalk_conditionals.rb │ ├── single_instance_running.rb │ ├── struct_without_assignment.rb │ ├── shortcut_variable_interpolation.rb │ ├── alphanumeric_incrementing.rb │ ├── enable_ruby_warnings.rb │ ├── super_magic_keyword.rb │ ├── fast_memoization_fibonacci.rb │ ├── unused_variable_format.rb │ ├── bubbling_up_thread_errors.rb │ ├── associative_arrays.rb │ ├── blocks_can_take_blocks.rb │ ├── zip.rb │ ├── case_on_ranges.rb │ ├── group_using_itself.rb │ ├── get_random_data.rb │ ├── ruby_debug_flag.rb │ ├── inspecting_the_source_with_script_lines.rb │ ├── fetch_data.rb │ ├── iterating_over_specific_types.rb │ ├── trigger_irb_as_needed.rb │ ├── tail_call.rb │ ├── super_magic_keyword3.rb │ ├── super_magic_keyword2.rb │ ├── add_uniq_value_to_array.rb │ ├── super_magic_keyword4.rb │ ├── super_magic_keyword5.rb │ ├── count_all_objects.rb │ ├── easiest_database_pstore.rb │ ├── easiest_database_pstore_yaml.rb │ ├── unfreeze_objects_with_fiddle.rb │ ├── splat_operator.rb │ ├── stab_operator.rb │ ├── Rakefile │ ├── at_exit_method.rb │ └── memoization.rb ├── people.yml ├── data.md ├── email.txt ├── cycle.md ├── variables-from-a-regex.md ├── print-formatted-with-debug.md ├── digits.md ├── autovivification.md ├── inject.md ├── lambda-your-own-syntax.md ├── enable-garbage-collector-profiler.md ├── head-tail.md ├── smalltalk-conditionals.md ├── single-instance-running.md ├── struct-without-assignment.md ├── enable-ruby-warnings.md ├── zip.md ├── alphanumeric-incrementing.md ├── super-magic-keyword.md ├── shortcut-variable-interpolation.md ├── associative-arrays.md ├── unused-variable-format.md ├── fast-memoization-fibonacci.md ├── bubbling-up-thread-errors.md ├── blocks-can-take-blocks.md ├── case-on-ranges.md ├── fetch-data.md ├── ruby-debug-flag.md ├── ruby_can_even_explain_it_to_you.txt ├── iterating-over-specific-types.md ├── tail-call.md ├── inspecting-the-source-with-script-lines.md ├── tricks.md ├── get-random-data.md ├── trigger-irb-as-needed.md ├── super-magic-keyword3.md ├── super-magic-keyword2.md ├── super-magic-keyword4.md ├── count-all-objects.md ├── super-magic-keyword5.md ├── add_uniq_value_to_array.md ├── easiest-database-pstore.md ├── easiest-database-pstore-yaml.md ├── unfreeze-objects-with-fiddle.md ├── splat-operator.md ├── introspecting_block_parameters.md ├── stab-operator.md ├── at-exit-method.md ├── memoization.md └── SUMMARY.md ├── .gitignore ├── best_practices.md ├── refactorings.md ├── idiomatic_ruby ├── use_times.md ├── multiple_assignment.md ├── array_of_strings_symbols.md ├── each_vs_map.md ├── use_symbol_to_proc.md ├── array_sample.md ├── collect_vs_select.md ├── options_hash_with_defaults.md ├── combine_elements_in_collection.md ├── conditional_assignment.md └── implicit_return.md ├── idiomatic_ruby.md ├── refactorings ├── conditionals_when_object_is_nil.md └── case_with_hashes.md ├── best_practices └── using_exception_e.md ├── CODE_OF_CONDUCT.md ├── tricks.md ├── README.md └── SUMMARY.md /tricks/README.md: -------------------------------------------------------------------------------- 1 | # Tricks 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.lock 2 | *.pstore 3 | .DS_Store 4 | .idea 5 | _book/ 6 | -------------------------------------------------------------------------------- /tricks/source_code/Gemfile: -------------------------------------------------------------------------------- 1 | source "https://rubygems.org" 2 | 3 | gem "rake" 4 | -------------------------------------------------------------------------------- /tricks/source_code/data.rb: -------------------------------------------------------------------------------- 1 | puts DATA.read 2 | 3 | __END__ 4 | Hey oh! 5 | Hey oh! 6 | -------------------------------------------------------------------------------- /tricks/people.yml: -------------------------------------------------------------------------------- 1 | --- 2 | people1: Someone 3 | money1: 400 4 | people2: Someone2 5 | money2: 300 6 | -------------------------------------------------------------------------------- /best_practices.md: -------------------------------------------------------------------------------- 1 | # Best Practices 2 | 3 | * [rescue => Exception e](best_practices/using_exception_e.md) 4 | -------------------------------------------------------------------------------- /tricks/source_code/cycle.rb: -------------------------------------------------------------------------------- 1 | ring = %w[one two three].cycle 2 | 3 | p ring.take(5) 4 | 5 | # Result: 6 | # ["one", "two", "three", "one", "two"] 7 | -------------------------------------------------------------------------------- /tricks/source_code/variables_from_a_regex.rb: -------------------------------------------------------------------------------- 1 | if /\A(?\w+),\s*(?\w+)\z/ =~ "Franze, Jr" 2 | puts "#{first} #{last}" 3 | end 4 | 5 | # Result: 6 | # Franze Jr 7 | -------------------------------------------------------------------------------- /tricks/data.md: -------------------------------------------------------------------------------- 1 | ### Data 2 | 3 | ```ruby 4 | puts DATA.read 5 | 6 | __END__ 7 | Hey oh! 8 | Hey oh! 9 | 10 | ``` 11 | 12 | [View Source](source_code/data.rb) 13 | 14 | -------------------------------------------------------------------------------- /tricks/source_code/print_formatted_with_debug.rb: -------------------------------------------------------------------------------- 1 | def debug(name, content) 2 | p "%s: %p" % [name, content] 3 | end 4 | 5 | debug "Num", 42 6 | 7 | # Result: 8 | # "Num: 42" 9 | -------------------------------------------------------------------------------- /tricks/source_code/enable_garbage_collector_profiler.rb: -------------------------------------------------------------------------------- 1 | GC::Profiler.enable 2 | 3 | 10.times do 4 | array = Array.new(1_000_000) { |i| i.to_s } 5 | end 6 | 7 | puts GC::Profiler.result 8 | -------------------------------------------------------------------------------- /refactorings.md: -------------------------------------------------------------------------------- 1 | # Refactorings 2 | 3 | * [Conditionals when object is nil](refactorings/conditionals_when_object_is_nil.md) 4 | * [Switch case with Hashes](refactorings/case_with_hashes.md) 5 | -------------------------------------------------------------------------------- /tricks/source_code/lambda_your_own_syntax.rb: -------------------------------------------------------------------------------- 1 | # encoding UTF-8 2 | 3 | module Kernel 4 | alias_method :λ, :lambda 5 | end 6 | 7 | l = λ { p :called } 8 | l.call 9 | 10 | # Result: 11 | # :called 12 | -------------------------------------------------------------------------------- /tricks/source_code/autovivification.rb: -------------------------------------------------------------------------------- 1 | deep = Hash.new { |hash,key| hash[key] = Hash.new(&hash.default_proc) } 2 | 3 | 4 | deep[:a][:b][:c][:d] = 42 5 | p deep 6 | 7 | # Result: 8 | # {:a=>{:b=>{:c=>{:d=>42}}}} 9 | -------------------------------------------------------------------------------- /tricks/email.txt: -------------------------------------------------------------------------------- 1 | # This is just a simple example on how you can run a ruby code 2 | # This is a text file. ./ruby email.txt will run this. 3 | #! /usr/bin/env ruby -w 4 | 5 | puts "This is one email" 6 | 7 | __END__ 8 | -------------------------------------------------------------------------------- /tricks/source_code/digits.rb: -------------------------------------------------------------------------------- 1 | awesome_number = 12345 2 | 3 | p awesome_number.to_s.chars.map(&:to_i).reverse 4 | 5 | # Result: 6 | # [5, 4, 3, 2, 1] 7 | 8 | p awesome_number.digits 9 | 10 | # Result: 11 | # [5, 4, 3, 2, 1] 12 | -------------------------------------------------------------------------------- /tricks/cycle.md: -------------------------------------------------------------------------------- 1 | ### Cycle 2 | 3 | ```ruby 4 | ring = %w[one two three].cycle 5 | 6 | p ring.take(5) 7 | 8 | # Result: 9 | # ["one", "two", "three", "one", "two"] 10 | 11 | ``` 12 | 13 | [View Source](source_code/cycle.rb) 14 | 15 | -------------------------------------------------------------------------------- /tricks/source_code/inject.rb: -------------------------------------------------------------------------------- 1 | p (1..10).inject{ |r,e| p [r,e]; r*2} 2 | 3 | 4 | # Result: 5 | # [1, 2] 6 | # [2, 3] 7 | # [4, 4] 8 | # [8, 5] 9 | # [16, 6] 10 | # [32, 7] 11 | # [64, 8] 12 | # [128, 9] 13 | # [256, 10] 14 | # 512 15 | -------------------------------------------------------------------------------- /tricks/source_code/head_tail.rb: -------------------------------------------------------------------------------- 1 | def my_reduce(array) 2 | head, *tail = array 3 | return (tail.empty? ? head : (head + my_reduce(tail))) 4 | end 5 | 6 | # triangular number example 7 | n = 100 8 | my_reduce((1..n).to_a) == (n*(n+1))/2 #=> True 9 | -------------------------------------------------------------------------------- /tricks/source_code/smalltalk_conditionals.rb: -------------------------------------------------------------------------------- 1 | def true.-(a, &b); a[] end 2 | def false.-(a, &b); b[] end 3 | 4 | puts (1 == 1).--> { :ok } { :different } 5 | puts (4 == 2).--> { :ok } { :different } 6 | 7 | # Result: 8 | # # ok 9 | # # different 10 | -------------------------------------------------------------------------------- /tricks/source_code/single_instance_running.rb: -------------------------------------------------------------------------------- 1 | DATA.flock(File::LOCK_EX | File::LOCK_NB) or abort 'Already running' 2 | 3 | trap('INT', 'EXIT') 4 | puts 'Running...' 5 | loop do 6 | sleep 7 | end 8 | 9 | __END__ 10 | DO NOT DELETE: used for locking 11 | -------------------------------------------------------------------------------- /idiomatic_ruby/use_times.md: -------------------------------------------------------------------------------- 1 | ## Use Fixnum#times 2 | 3 | **Rather than** 4 | ```ruby 5 | for i in 1..10 6 | puts "My iteration #{i}" 7 | end 8 | ``` 9 | 10 | **Use** 11 | ```ruby 12 | 10.times do |i| 13 | puts "My iteration #{i + 1}" 14 | end 15 | ``` 16 | -------------------------------------------------------------------------------- /tricks/source_code/struct_without_assignment.rb: -------------------------------------------------------------------------------- 1 | Struct.new("Name", :first, :last) do 2 | def full 3 | "#{first} #{last}" 4 | end 5 | end 6 | 7 | franzejr = Struct::Name.new("Franze", "Jr") 8 | p franzejr.full 9 | 10 | # Result: 11 | # "Franze Jr" 12 | -------------------------------------------------------------------------------- /idiomatic_ruby/multiple_assignment.md: -------------------------------------------------------------------------------- 1 | ## Multiple Assignment 2 | 3 | **A simple example** 4 | 5 | ```ruby 6 | def some_method 7 | [x, y, z] 8 | end 9 | 10 | x, y, z = some_method 11 | ``` 12 | 13 | **Swap values** 14 | 15 | ```ruby 16 | x, y = y, x 17 | ``` 18 | -------------------------------------------------------------------------------- /tricks/source_code/shortcut_variable_interpolation.rb: -------------------------------------------------------------------------------- 1 | @instance = :instance 2 | @@class = :class 3 | $global = :global 4 | 5 | p "#@instance, #@@class, and #$global variables don't need braces" 6 | 7 | # Result: 8 | # "instance, class, and global variables don't need braces" 9 | -------------------------------------------------------------------------------- /tricks/source_code/alphanumeric_incrementing.rb: -------------------------------------------------------------------------------- 1 | "1".next 2 | #=> "2" 3 | 4 | "a".next 5 | #=> "b" 6 | 7 | "1a".next 8 | #=> "1b" 9 | 10 | "1z".next 11 | #=> "2a" 12 | 13 | "1aa".next 14 | #=> "1ab" 15 | 16 | "1az".next 17 | #=> "1ba" 18 | 19 | "1aaz".next 20 | #=> "1aba" 21 | -------------------------------------------------------------------------------- /tricks/source_code/enable_ruby_warnings.rb: -------------------------------------------------------------------------------- 1 | $VERBOSE = true 2 | 3 | class WarnMe 4 | def var 5 | @var || 42 6 | end 7 | end 8 | 9 | 10 | p WarnMe.new.var 11 | 12 | 13 | # Result: 14 | # ./enable_ruby_warnings.rb:5: warning: instance variable @var not initialized 15 | # 42 16 | -------------------------------------------------------------------------------- /tricks/variables-from-a-regex.md: -------------------------------------------------------------------------------- 1 | ### Variables from a regex 2 | 3 | ```ruby 4 | if /\A(?\w+),\s*(?\w+)\z/ =~ "Franze, Jr" 5 | puts "#{first} #{last}" 6 | end 7 | 8 | # Result: 9 | # Franze Jr 10 | 11 | ``` 12 | 13 | [View Source](source_code/variables_from_a_regex.rb) 14 | 15 | -------------------------------------------------------------------------------- /tricks/source_code/super_magic_keyword.rb: -------------------------------------------------------------------------------- 1 | class Parent 2 | def show_args(*args) 3 | p args 4 | end 5 | end 6 | 7 | class Child < Parent 8 | def show_args(a,b,c) 9 | super(a,b,c) 10 | end 11 | end 12 | 13 | Child.new.show_args(:a, :b, :c) 14 | 15 | # Result: 16 | # [:a, :b, :c] 17 | -------------------------------------------------------------------------------- /tricks/source_code/fast_memoization_fibonacci.rb: -------------------------------------------------------------------------------- 1 | fibonacci = Hash.new{ |numbers,index| 2 | numbers[index] = fibonacci[index - 2] + fibonacci[index - 1] 3 | }.update(0 => 0, 1 => 1) 4 | 5 | 6 | p fibonacci[300] 7 | 8 | # Result: 9 | # 222232244629420445529739893461909967206666939096499764990979600 10 | -------------------------------------------------------------------------------- /tricks/source_code/unused_variable_format.rb: -------------------------------------------------------------------------------- 1 | [ 2 | ['Someone', 41, 'another field'], 3 | ['Someone2', 42, 'another field2'], 4 | ['Someone3', 43, 'another field3'] 5 | ].each do |name,_,_| 6 | p name 7 | end 8 | 9 | # Result: 10 | # "Someone" 11 | # "Someone2" 12 | # "Someone3" 13 | -------------------------------------------------------------------------------- /tricks/print-formatted-with-debug.md: -------------------------------------------------------------------------------- 1 | ### Print formatted with debug 2 | 3 | ```ruby 4 | def debug(name, content) 5 | p "%s: %p" % [name, content] 6 | end 7 | 8 | debug "Num", 42 9 | 10 | # Result: 11 | # "Num: 42" 12 | 13 | ``` 14 | 15 | [View Source](source_code/print_formatted_with_debug.rb) 16 | 17 | -------------------------------------------------------------------------------- /tricks/source_code/bubbling_up_thread_errors.rb: -------------------------------------------------------------------------------- 1 | Thread.abort_on_exception = true 2 | 3 | Thread.new do 4 | fail 'Ops, we cannot continue' 5 | end 6 | 7 | loop do 8 | sleep 9 | end 10 | 11 | # Result: 12 | # ./bubbling_up_thread_errors.rb:4:in `block in
': Ops, we cannot continue (RuntimeError) 13 | -------------------------------------------------------------------------------- /tricks/digits.md: -------------------------------------------------------------------------------- 1 | ### Integer#digits 2 | 3 | ```ruby 4 | awesome_number = 12345 5 | 6 | p awesome_number.to_s.chars.map(&:to_i).reverse 7 | 8 | # Result: 9 | # [5, 4, 3, 2, 1] 10 | 11 | p awesome_number.digits 12 | 13 | # Result: 14 | # [5, 4, 3, 2, 1] 15 | ``` 16 | 17 | [View Source](source_code/digits.rb) 18 | -------------------------------------------------------------------------------- /tricks/source_code/associative_arrays.rb: -------------------------------------------------------------------------------- 1 | aa = [ %w[Someone 1], 2 | %w[Bla 2]] 3 | 4 | p aa.assoc("Someone") 5 | p aa.assoc("Bla") 6 | 7 | # Result: 8 | # ["Someone", "1"] 9 | # ["Bla", "2"] 10 | 11 | p aa.rassoc("1") 12 | p aa.rassoc("2") 13 | 14 | # Result: 15 | # ["Someone", "1"] 16 | # ["Bla", "2"] 17 | -------------------------------------------------------------------------------- /tricks/source_code/blocks_can_take_blocks.rb: -------------------------------------------------------------------------------- 1 | var = :var 2 | object = Object.new 3 | 4 | object.define_singleton_method(:show_var_and_block) do |&block| 5 | p [var, block] 6 | end 7 | 8 | object.show_var_and_block { :block } 9 | 10 | # Result: 11 | # [:var, #] 12 | -------------------------------------------------------------------------------- /tricks/source_code/zip.rb: -------------------------------------------------------------------------------- 1 | letters = "a".."d" 2 | numbers = 1..3 3 | 4 | letters.zip(numbers) do |letter, number| 5 | p(letter: letter, number: number) 6 | end 7 | 8 | # Result: 9 | # {:letter=>"a", :number=>1} 10 | # {:letter=>"b", :number=>2} 11 | # {:letter=>"c", :number=>3} 12 | # {:letter=>"d", :number=>nil} 13 | -------------------------------------------------------------------------------- /tricks/autovivification.md: -------------------------------------------------------------------------------- 1 | ### Autovivification 2 | 3 | ```ruby 4 | deep = Hash.new { |hash,key| hash[key] = Hash.new(&hash.default_proc) } 5 | 6 | 7 | deep[:a][:b][:c][:d] = 42 8 | p deep 9 | 10 | # Result: 11 | # {:a=>{:b=>{:c=>{:d=>42}}}} 12 | 13 | ``` 14 | 15 | [View Source](source_code/autovivification.rb) 16 | 17 | -------------------------------------------------------------------------------- /tricks/inject.md: -------------------------------------------------------------------------------- 1 | ### Inject 2 | 3 | ```ruby 4 | p (1..10).inject{ |r,e| p [r,e]; r*2} 5 | 6 | 7 | # Result: 8 | # [1, 2] 9 | # [2, 3] 10 | # [4, 4] 11 | # [8, 5] 12 | # [16, 6] 13 | # [32, 7] 14 | # [64, 8] 15 | # [128, 9] 16 | # [256, 10] 17 | # 512 18 | 19 | ``` 20 | 21 | [View Source](source_code/inject.rb) 22 | 23 | -------------------------------------------------------------------------------- /tricks/lambda-your-own-syntax.md: -------------------------------------------------------------------------------- 1 | ### Lambda your own syntax 2 | 3 | ```ruby 4 | # encoding UTF-8 5 | 6 | module Kernel 7 | alias_method :λ, :lambda 8 | end 9 | 10 | l = λ { p :called } 11 | l.call 12 | 13 | # Result: 14 | # :called 15 | 16 | ``` 17 | 18 | [View Source](source_code/lambda_your_own_syntax.rb) 19 | 20 | -------------------------------------------------------------------------------- /tricks/enable-garbage-collector-profiler.md: -------------------------------------------------------------------------------- 1 | ### Enable garbage collector profiler 2 | 3 | ```ruby 4 | GC::Profiler.enable 5 | 6 | 10.times do 7 | array = Array.new(1_000_000) { |i| i.to_s } 8 | end 9 | 10 | puts GC::Profiler.result 11 | 12 | ``` 13 | 14 | [View Source](source_code/enable_garbage_collector_profiler.rb) 15 | 16 | -------------------------------------------------------------------------------- /tricks/source_code/case_on_ranges.rb: -------------------------------------------------------------------------------- 1 | age = rand(1..100) 2 | p age 3 | 4 | case age 5 | when -Float::INFINITY..20 6 | p 'You are too young' 7 | when 21..64 8 | p 'You are at the right age' 9 | when 65..Float::INFINITY 10 | p 'You are too old' 11 | end 12 | 13 | # Result: 14 | # 55 15 | # "You are at the right age" 16 | -------------------------------------------------------------------------------- /tricks/source_code/group_using_itself.rb: -------------------------------------------------------------------------------- 1 | 2 | ## Using the Itself method in Ruby 2.2 3 | ## we can group elements from one array 4 | ## Reference: http://ruby-doc.org/core-2.2.0/Object.html#method-i-itself 5 | 6 | [2, 3, 3, 1, 2, 3, 3, 1, 1, 2].group_by(&:itself) 7 | 8 | # Result: 9 | # {2=>[2, 2, 2], 3=>[3, 3, 3, 3], 1=>[1, 1, 1]} 10 | -------------------------------------------------------------------------------- /idiomatic_ruby/array_of_strings_symbols.md: -------------------------------------------------------------------------------- 1 | ## Array of Strings or Symbols 2 | 3 | **Array of Strings** 4 | 5 | ```ruby 6 | %w(Michael Jonh Mary Stuart) 7 | => ["Michael", "Jonh", "Mary", "Stuart"] 8 | ``` 9 | 10 | **Array of Symbols** 11 | 12 | ```ruby 13 | %i(Michael Jonh Mary Stuart) 14 | => [:Michael, :Jonh, :Mary, :Stuart] 15 | ``` 16 | -------------------------------------------------------------------------------- /tricks/source_code/get_random_data.rb: -------------------------------------------------------------------------------- 1 | require 'securerandom' 2 | 3 | p SecureRandom.random_number 4 | p SecureRandom.random_number(100) 5 | p 6 | p SecureRandom.hex(20) 7 | p SecureRandom.base64(20) 8 | 9 | # Result: 10 | # 0.7851536586163714 11 | # 46 12 | # "3efb674fbc2ba390856c15489652e75e8afff6d1" 13 | # "yFv0WzugzFC6/D71teVe1Y5r1kU=" 14 | -------------------------------------------------------------------------------- /tricks/head-tail.md: -------------------------------------------------------------------------------- 1 | ### Head tail 2 | 3 | ```ruby 4 | def my_reduce(array) 5 | head, *tail = array 6 | return (tail.empty? ? head : (head + my_reduce(tail))) 7 | end 8 | 9 | # triangular number example 10 | n = 100 11 | my_reduce((1..n).to_a) == (n*(n+1))/2 #=> True 12 | 13 | ``` 14 | 15 | [View Source](source_code/head_tail.rb) 16 | 17 | -------------------------------------------------------------------------------- /tricks/source_code/ruby_debug_flag.rb: -------------------------------------------------------------------------------- 1 | def var 2 | @var || 40 3 | end 4 | 5 | if $DEBUG 6 | p "var is %p" % var 7 | end 8 | 9 | p var + 2 10 | 11 | # Result: 12 | # ruby_debug_flag.rb:2: warning: instance variable @var not initialized 13 | # "var is 40" 14 | # ruby_debug_flag.rb:2: warning: instance variable @var not initialized 15 | # 42 16 | -------------------------------------------------------------------------------- /idiomatic_ruby/each_vs_map.md: -------------------------------------------------------------------------------- 1 | ## Each vs map 2 | 3 | Let the following each: 4 | 5 | ```ruby 6 | user_ids = [] 7 | users.each { |user| user_ids << user.id } 8 | ``` 9 | 10 | It can be simplified to: 11 | 12 | ```ruby 13 | user_ids = users.map { |user| user.id } 14 | ``` 15 | 16 | or even: 17 | 18 | ```ruby 19 | user_ids = users.map(&:id) 20 | ``` 21 | -------------------------------------------------------------------------------- /tricks/source_code/inspecting_the_source_with_script_lines.rb: -------------------------------------------------------------------------------- 1 | SCRIPT_LINES__ = { } 2 | 3 | #require_relative = 'better_be_well_formed_code' 4 | require_relative = 'better_be_well_formed_code_with_a_line_size_greather_than_80_it_is_not_good' 5 | 6 | if SCRIPT_LINES__.values.flatten.any? { |line| line.size > 80} 7 | abort 'Clean up your code first!' 8 | end 9 | -------------------------------------------------------------------------------- /tricks/source_code/fetch_data.rb: -------------------------------------------------------------------------------- 1 | params = {var: 42} 2 | 3 | p params.fetch(:var) 4 | p params.fetch(:missing, 42) 5 | p params.fetch(:missing) { 40 + 2 } 6 | 7 | params.fetch(:missing) 8 | 9 | 10 | # Result: 11 | # 42 12 | # 42 13 | # 42 14 | # ./fetch_data.rb:7:in `fetch': key not found: :missing (KeyError) 15 | # from ./fetch_data.rb:7:in `
' 16 | -------------------------------------------------------------------------------- /tricks/source_code/iterating_over_specific_types.rb: -------------------------------------------------------------------------------- 1 | ObjectSpace.each_object(String) do |object| 2 | p object 3 | end 4 | 5 | # Result: 6 | # "block in dependent_specs" 7 | # "block in dependent_specs" 8 | # "block (3 levels) in dependent_gems" 9 | # "block (3 levels) in dependent_gems" 10 | # ... (huge output suppressed) 11 | # "This rdoc is bundled with Ruby" 12 | -------------------------------------------------------------------------------- /tricks/smalltalk-conditionals.md: -------------------------------------------------------------------------------- 1 | ### Smalltalk conditionals 2 | 3 | ```ruby 4 | def true.-(a, &b); a[] end 5 | def false.-(a, &b); b[] end 6 | 7 | puts (1 == 1).--> { :ok } { :different } 8 | puts (4 == 2).--> { :ok } { :different } 9 | 10 | # Result: 11 | # # ok 12 | # # different 13 | 14 | ``` 15 | 16 | [View Source](source_code/smalltalk_conditionals.rb) 17 | 18 | -------------------------------------------------------------------------------- /tricks/single-instance-running.md: -------------------------------------------------------------------------------- 1 | ### Single instance running 2 | 3 | ```ruby 4 | DATA.flock(File::LOCK_EX | File::LOCK_NB) or abort 'Already running' 5 | 6 | trap('INT', 'EXIT') 7 | puts 'Running...' 8 | loop do 9 | sleep 10 | end 11 | 12 | __END__ 13 | DO NOT DELETE: used for locking 14 | 15 | ``` 16 | 17 | [View Source](source_code/single_instance_running.rb) 18 | 19 | -------------------------------------------------------------------------------- /idiomatic_ruby/use_symbol_to_proc.md: -------------------------------------------------------------------------------- 1 | ## Use Symbol to_proc 2 | 3 | The ``&`` calls ``to_proc``on the object, and passes it as a block to the method. 4 | The following calls are equivalent: 5 | 6 | ```ruby 7 | %w(john mary michael).map { |x| x.upcase } 8 | #=> ["JOHN", "MARY", "MICHAEL"] 9 | 10 | %w(john mary michael).map(&:upcase) 11 | #=> ["JOHN", "MARY", "MICHAEL"] 12 | ``` 13 | -------------------------------------------------------------------------------- /tricks/struct-without-assignment.md: -------------------------------------------------------------------------------- 1 | ### Struct without assignment 2 | 3 | ```ruby 4 | Struct.new("Name", :first, :last) do 5 | def full 6 | "#{first} #{last}" 7 | end 8 | end 9 | 10 | franzejr = Struct::Name.new("Franze", "Jr") 11 | p franzejr.full 12 | 13 | # Result: 14 | # "Franze Jr" 15 | 16 | ``` 17 | 18 | [View Source](source_code/struct_without_assignment.rb) 19 | 20 | -------------------------------------------------------------------------------- /tricks/source_code/trigger_irb_as_needed.rb: -------------------------------------------------------------------------------- 1 | require 'irb' 2 | 3 | def my_program_context 4 | @my_program_context ||= Struct.new(:value).new(40) 5 | end 6 | 7 | trap(:INT) do 8 | IRB.start 9 | trap(:INT, 'EXIT') 10 | end 11 | 12 | loop do 13 | p "Current value: #{my_program_context.value}" 14 | sleep 1 15 | end 16 | 17 | # Result: 18 | # "Current value: 40" 19 | # "Current value: 40" 20 | -------------------------------------------------------------------------------- /tricks/enable-ruby-warnings.md: -------------------------------------------------------------------------------- 1 | ### Enable ruby warnings 2 | 3 | ```ruby 4 | $VERBOSE = true 5 | 6 | class WarnMe 7 | def var 8 | @var || 42 9 | end 10 | end 11 | 12 | 13 | p WarnMe.new.var 14 | 15 | 16 | # Result: 17 | # ./enable_ruby_warnings.rb:5: warning: instance variable @var not initialized 18 | # 42 19 | 20 | ``` 21 | 22 | [View Source](source_code/enable_ruby_warnings.rb) 23 | 24 | -------------------------------------------------------------------------------- /tricks/source_code/tail_call.rb: -------------------------------------------------------------------------------- 1 | RubyVM::InstructionSequence.compile_option = { tailcall_optimization: true, 2 | trace_instruction: false } 3 | 4 | eval <"a", :number=>1} 13 | # {:letter=>"b", :number=>2} 14 | # {:letter=>"c", :number=>3} 15 | # {:letter=>"d", :number=>nil} 16 | 17 | ``` 18 | 19 | [View Source](source_code/zip.rb) 20 | 21 | -------------------------------------------------------------------------------- /tricks/alphanumeric-incrementing.md: -------------------------------------------------------------------------------- 1 | ### Alphanumeric incrementing 2 | 3 | ```ruby 4 | "1".next 5 | #=> "2" 6 | 7 | "a".next 8 | #=> "b" 9 | 10 | "1a".next 11 | #=> "1b" 12 | 13 | "1z".next 14 | #=> "2a" 15 | 16 | "1aa".next 17 | #=> "1ab" 18 | 19 | "1az".next 20 | #=> "1ba" 21 | 22 | "1aaz".next 23 | #=> "1aba" 24 | 25 | ``` 26 | 27 | [View Source](source_code/alphanumeric_incrementing.rb) 28 | 29 | -------------------------------------------------------------------------------- /tricks/source_code/super_magic_keyword3.rb: -------------------------------------------------------------------------------- 1 | class Parent 2 | def show_args(*args, &block) 3 | p [*args, block] 4 | end 5 | end 6 | 7 | class Child < Parent 8 | def show_args(a,b,c) 9 | # Call super without any params 10 | # making args an empty array [] 11 | super() 12 | end 13 | end 14 | 15 | #Nothing goes up 16 | Child.new.show_args(:a, :b, :c) 17 | 18 | # Result: 19 | # [nil] 20 | -------------------------------------------------------------------------------- /tricks/super-magic-keyword.md: -------------------------------------------------------------------------------- 1 | ### Super magic keyword 2 | 3 | ```ruby 4 | class Parent 5 | def show_args(*args) 6 | p args 7 | end 8 | end 9 | 10 | class Child < Parent 11 | def show_args(a,b,c) 12 | super(a,b,c) 13 | end 14 | end 15 | 16 | Child.new.show_args(:a, :b, :c) 17 | 18 | # Result: 19 | # [:a, :b, :c] 20 | 21 | ``` 22 | 23 | [View Source](source_code/super_magic_keyword.rb) 24 | 25 | -------------------------------------------------------------------------------- /tricks/shortcut-variable-interpolation.md: -------------------------------------------------------------------------------- 1 | ### Shortcut variable interpolation 2 | 3 | ```ruby 4 | @instance = :instance 5 | @@class = :class 6 | $global = :global 7 | 8 | p "#@instance, #@@class, and #$global variables don't need braces" 9 | 10 | # Result: 11 | # "instance, class, and global variables don't need braces" 12 | 13 | ``` 14 | 15 | [View Source](source_code/shortcut_variable_interpolation.rb) 16 | 17 | -------------------------------------------------------------------------------- /tricks/source_code/super_magic_keyword2.rb: -------------------------------------------------------------------------------- 1 | class Parent 2 | def show_args(*args, &block) 3 | p [*args, block] 4 | end 5 | end 6 | 7 | class Child < Parent 8 | def show_args(a,b,c) 9 | super 10 | end 11 | end 12 | 13 | #Everything goes up, including the block 14 | Child.new.show_args(:a, :b, :c) { :block } 15 | 16 | # Result: 17 | # [:a, :b, :c, #] 18 | -------------------------------------------------------------------------------- /idiomatic_ruby/array_sample.md: -------------------------------------------------------------------------------- 1 | ## Array Sample (enumerables) 2 | 3 | To get a random element from an Array, you can use the method sample, as follows: 4 | 5 | ```ruby 6 | [1, 2, 3][rand(3)] 7 | 8 | [1, 2, 3].shuffle.first 9 | 10 | [1, 2, 3].sample 11 | ``` 12 | 13 | ``sample`` is 15x faster than ``.shuffle.first`` 14 | 15 | Reference: 16 | http://work.stevegrossi.com/2014/10/25/writing-fast-and-idiomatic-ruby/ 17 | -------------------------------------------------------------------------------- /tricks/associative-arrays.md: -------------------------------------------------------------------------------- 1 | ### Associative arrays 2 | 3 | ```ruby 4 | aa = [ %w[Someone 1], 5 | %w[Bla 2]] 6 | 7 | p aa.assoc("Someone") 8 | p aa.assoc("Bla") 9 | 10 | # Result: 11 | # ["Someone", "1"] 12 | # ["Bla", "2"] 13 | 14 | p aa.rassoc("1") 15 | p aa.rassoc("2") 16 | 17 | # Result: 18 | # ["Someone", "1"] 19 | # ["Bla", "2"] 20 | 21 | ``` 22 | 23 | [View Source](source_code/associative_arrays.rb) 24 | 25 | -------------------------------------------------------------------------------- /tricks/unused-variable-format.md: -------------------------------------------------------------------------------- 1 | ### Unused variable format 2 | 3 | ```ruby 4 | [ 5 | ['Someone', 41, 'another field'], 6 | ['Someone2', 42, 'another field2'], 7 | ['Someone3', 43, 'another field3'] 8 | ].each do |name,_,_| 9 | p name 10 | end 11 | 12 | # Result: 13 | # "Someone" 14 | # "Someone2" 15 | # "Someone3" 16 | 17 | ``` 18 | 19 | [View Source](source_code/unused_variable_format.rb) 20 | 21 | -------------------------------------------------------------------------------- /tricks/fast-memoization-fibonacci.md: -------------------------------------------------------------------------------- 1 | ### Fast memoization fibonacci 2 | 3 | ```ruby 4 | fibonacci = Hash.new{ |numbers,index| 5 | numbers[index] = fibonacci[index - 2] + fibonacci[index - 1] 6 | }.update(0 => 0, 1 => 1) 7 | 8 | 9 | p fibonacci[300] 10 | 11 | # Result: 12 | # 222232244629420445529739893461909967206666939096499764990979600 13 | 14 | ``` 15 | 16 | [View Source](source_code/fast_memoization_fibonacci.rb) 17 | 18 | -------------------------------------------------------------------------------- /tricks/bubbling-up-thread-errors.md: -------------------------------------------------------------------------------- 1 | ### Bubbling up thread errors 2 | 3 | ```ruby 4 | Thread.abort_on_exception = true 5 | 6 | Thread.new do 7 | fail 'Ops, we cannot continue' 8 | end 9 | 10 | loop do 11 | sleep 12 | end 13 | 14 | # Result: 15 | # ./bubbling_up_thread_errors.rb:4:in `block in
': Ops, we cannot continue (RuntimeError) 16 | 17 | ``` 18 | 19 | [View Source](source_code/bubbling_up_thread_errors.rb) 20 | 21 | -------------------------------------------------------------------------------- /tricks/blocks-can-take-blocks.md: -------------------------------------------------------------------------------- 1 | ### Blocks can take blocks 2 | 3 | ```ruby 4 | var = :var 5 | object = Object.new 6 | 7 | object.define_singleton_method(:show_var_and_block) do |&block| 8 | p [var, block] 9 | end 10 | 11 | object.show_var_and_block { :block } 12 | 13 | # Result: 14 | # [:var, #] 15 | 16 | ``` 17 | 18 | [View Source](source_code/blocks_can_take_blocks.rb) 19 | 20 | -------------------------------------------------------------------------------- /tricks/case-on-ranges.md: -------------------------------------------------------------------------------- 1 | ### Case on ranges 2 | 3 | ```ruby 4 | age = rand(1..100) 5 | p age 6 | 7 | case age 8 | when -Float::INFINITY..20 9 | p 'You are too young' 10 | when 21..64 11 | p 'You are at the right age' 12 | when 65..Float::INFINITY 13 | p 'You are too old' 14 | end 15 | 16 | # Result: 17 | # 55 18 | # "You are at the right age" 19 | 20 | ``` 21 | 22 | [View Source](source_code/case_on_ranges.rb) 23 | 24 | -------------------------------------------------------------------------------- /tricks/fetch-data.md: -------------------------------------------------------------------------------- 1 | ### Fetch data 2 | 3 | ```ruby 4 | params = {var: 42} 5 | 6 | p params.fetch(:var) 7 | p params.fetch(:missing, 42) 8 | p params.fetch(:missing) { 40 + 2 } 9 | 10 | params.fetch(:missing) 11 | 12 | 13 | # Result: 14 | # 42 15 | # 42 16 | # 42 17 | # ./fetch_data.rb:7:in `fetch': key not found: :missing (KeyError) 18 | # from ./fetch_data.rb:7:in `
' 19 | 20 | ``` 21 | 22 | [View Source](source_code/fetch_data.rb) 23 | 24 | -------------------------------------------------------------------------------- /tricks/ruby-debug-flag.md: -------------------------------------------------------------------------------- 1 | ### Ruby debug flag 2 | 3 | ```ruby 4 | def var 5 | @var || 40 6 | end 7 | 8 | if $DEBUG 9 | p "var is %p" % var 10 | end 11 | 12 | p var + 2 13 | 14 | # Result: 15 | # ruby_debug_flag.rb:2: warning: instance variable @var not initialized 16 | # "var is 40" 17 | # ruby_debug_flag.rb:2: warning: instance variable @var not initialized 18 | # 42 19 | 20 | ``` 21 | 22 | [View Source](source_code/ruby_debug_flag.rb) 23 | 24 | -------------------------------------------------------------------------------- /tricks/source_code/add_uniq_value_to_array.rb: -------------------------------------------------------------------------------- 1 | array = [1, 2, 3] 2 | 3 | array << 2 4 | array << 4 5 | 6 | # Result: 7 | # [1, 2, 3, 2, 4] 8 | 9 | p array.uniq 10 | 11 | # Result: 12 | # [1, 2, 3, 4] 13 | 14 | array = [1, 2, 3] 15 | 16 | array = array | [2] 17 | array = array | [4] 18 | 19 | p array 20 | 21 | # Result: 22 | # [1, 2, 3, 4] 23 | 24 | array = [1, 2, 3] 25 | 26 | array |= [2, 4] 27 | 28 | p array 29 | 30 | # Result: 31 | # [1, 2, 3, 4] 32 | -------------------------------------------------------------------------------- /tricks/ruby_can_even_explain_it_to_you.txt: -------------------------------------------------------------------------------- 1 | ruby -e 'puts { is_this_a_block }' --dump parsetree 2 | ruby -e 'puts { is_this_a_block }' --dump parsetree_with_comment 3 | 4 | # Output yacc's debug info when ruby parsing code. 5 | ruby -e 'puts { is_this_a_block }' --dump yydebug 6 | 7 | # Check ruby code syntax whether OK. 8 | ruby -e 'puts { is_this_a_block }' --dump syntax 9 | 10 | # Output yarv instructions info of compiled ruby code. 11 | ruby -e 'puts { is_this_a_block }' --dump insns 12 | -------------------------------------------------------------------------------- /tricks/source_code/super_magic_keyword4.rb: -------------------------------------------------------------------------------- 1 | class Parent 2 | def show_args(*args, &block) 3 | p [*args, block] 4 | end 5 | end 6 | 7 | class Child < Parent 8 | def show_args(a,b,c) 9 | # modify super by passing nothing 10 | # calling super with a nil proc, 11 | # which is basically calling super() 12 | super(&nil) 13 | end 14 | end 15 | 16 | #Nothing goes up, neither the block 17 | Child.new.show_args(:a, :b, :c) { :block } 18 | 19 | # Result: 20 | # [nil] 21 | -------------------------------------------------------------------------------- /tricks/iterating-over-specific-types.md: -------------------------------------------------------------------------------- 1 | ### Iterating over specific types 2 | 3 | ```ruby 4 | ObjectSpace.each_object(String) do |object| 5 | p object 6 | end 7 | 8 | # Result: 9 | # "block in dependent_specs" 10 | # "block in dependent_specs" 11 | # "block (3 levels) in dependent_gems" 12 | # "block (3 levels) in dependent_gems" 13 | # ... (huge output suppressed) 14 | # "This rdoc is bundled with Ruby" 15 | 16 | ``` 17 | 18 | [View Source](source_code/iterating_over_specific_types.rb) 19 | 20 | -------------------------------------------------------------------------------- /tricks/tail-call.md: -------------------------------------------------------------------------------- 1 | ### Tail call 2 | 3 | ```ruby 4 | RubyVM::InstructionSequence.compile_option = { tailcall_optimization: true, 5 | trace_instruction: false } 6 | 7 | eval <30163, 7 | # :FREE=>1007, 8 | # :T_OBJECT=>39, 9 | # :T_CLASS=>534, 10 | # :T_MODULE=>24, 11 | # :T_FLOAT=>4, 12 | # :T_STRING=>9290, 13 | # :T_REGEXP=>70, 14 | # :T_ARRAY=>2231, 15 | # :T_HASH=>53, 16 | # :T_STRUCT=>1, 17 | # :T_BIGNUM=>2, 18 | # :T_FILE=>14, 19 | # :T_DATA=>966, 20 | # :T_MATCH=>1, 21 | # :T_COMPLEX=>1, 22 | # :T_NODE=>15896, 23 | # :T_ICLASS=>30} 24 | -------------------------------------------------------------------------------- /tricks/inspecting-the-source-with-script-lines.md: -------------------------------------------------------------------------------- 1 | ### Inspecting the source with script lines 2 | 3 | ```ruby 4 | SCRIPT_LINES__ = { } 5 | 6 | #require_relative = 'better_be_well_formed_code' 7 | require_relative = 'better_be_well_formed_code_with_a_line_size_greather_than_80_it_is_not_good' 8 | 9 | if SCRIPT_LINES__.values.flatten.any? { |line| line.size > 80} 10 | abort 'Clean up your code first!' 11 | end 12 | 13 | ``` 14 | 15 | [View Source](source_code/inspecting_the_source_with_script_lines.rb) 16 | 17 | -------------------------------------------------------------------------------- /tricks/tricks.md: -------------------------------------------------------------------------------- 1 | # Ruby Tricks 2 | 3 | [![Join the chat at https://gitter.im/franzejr/ruby-tricks](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/franzejr/ruby-tricks?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) 4 | 5 | The majority of these Ruby Tricks were extracted from James Edward Gray II [talk](https://www.youtube.com/watch?v=aBgnlBoIkVM). 6 | If you know some other tricks, please contribute! 7 | 8 | ## Table of Contents 9 | 10 | 11 | ## Tricks 12 | 13 | 14 | -------------------------------------------------------------------------------- /tricks/get-random-data.md: -------------------------------------------------------------------------------- 1 | ### Get random data 2 | 3 | ```ruby 4 | require 'securerandom' 5 | 6 | p SecureRandom.random_number 7 | p SecureRandom.random_number(100) 8 | p 9 | p SecureRandom.hex(20) 10 | p SecureRandom.base64(20) 11 | p SecureRandom.uuid 12 | 13 | # Result: 14 | # 0.7851536586163714 15 | # 46 16 | # "3efb674fbc2ba390856c15489652e75e8afff6d1" 17 | # "yFv0WzugzFC6/D71teVe1Y5r1kU=" 18 | # "64055f69-2f81-4e61-9730-495aa5c156fc" 19 | 20 | ``` 21 | 22 | [View Source](source_code/get_random_data.rb) 23 | 24 | -------------------------------------------------------------------------------- /tricks/trigger-irb-as-needed.md: -------------------------------------------------------------------------------- 1 | ### Trigger irb as needed 2 | 3 | ```ruby 4 | require 'irb' 5 | 6 | def my_program_context 7 | @my_program_context ||= Struct.new(:value).new(40) 8 | end 9 | 10 | trap(:INT) do 11 | IRB.start 12 | trap(:INT, 'EXIT') 13 | end 14 | 15 | loop do 16 | p "Current value: #{my_program_context.value}" 17 | sleep 1 18 | end 19 | 20 | # Result: 21 | # "Current value: 40" 22 | # "Current value: 40" 23 | 24 | ``` 25 | 26 | [View Source](source_code/trigger_irb_as_needed.rb) 27 | 28 | -------------------------------------------------------------------------------- /tricks/super-magic-keyword3.md: -------------------------------------------------------------------------------- 1 | ### Super magic keyword3 2 | 3 | ```ruby 4 | class Parent 5 | def show_args(*args, &block) 6 | p [*args, block] 7 | end 8 | end 9 | 10 | class Child < Parent 11 | def show_args(a,b,c) 12 | # Call super without any params 13 | # making args an empty array [] 14 | super() 15 | end 16 | end 17 | 18 | #Nothing goes up 19 | Child.new.show_args(:a, :b, :c) 20 | 21 | # Result: 22 | # [nil] 23 | 24 | ``` 25 | 26 | [View Source](source_code/super_magic_keyword3.rb) 27 | 28 | -------------------------------------------------------------------------------- /tricks/super-magic-keyword2.md: -------------------------------------------------------------------------------- 1 | ### Super magic keyword2 2 | 3 | ```ruby 4 | class Parent 5 | def show_args(*args, &block) 6 | p [*args, block] 7 | end 8 | end 9 | 10 | class Child < Parent 11 | def show_args(a,b,c) 12 | super 13 | end 14 | end 15 | 16 | #Everything goes up, including the block 17 | Child.new.show_args(:a, :b, :c) { :block } 18 | 19 | # Result: 20 | # [:a, :b, :c, #] 21 | 22 | ``` 23 | 24 | [View Source](source_code/super_magic_keyword2.rb) 25 | 26 | -------------------------------------------------------------------------------- /idiomatic_ruby/collect_vs_select.md: -------------------------------------------------------------------------------- 1 | ## Collect vs Select 2 | 3 | collect : Creates a new array containing the values returned by the block. 4 | 5 | ```ruby 6 | arr = (1..10).to_a 7 | # => [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] 8 | arr.collect{ |num| num * num } 9 | # => [1, 4, 9, 16, 25, 36, 49, 64, 81, 100] 10 | ``` 11 | 12 | select : Elements can be selected from an array according to criteria defined in a block. 13 | 14 | ```ruby 15 | arr = (1..10).to_a 16 | # => [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] 17 | arr.select(&:even?) 18 | # => [2, 4, 6, 8, 10] 19 | ``` 20 | -------------------------------------------------------------------------------- /tricks/super-magic-keyword4.md: -------------------------------------------------------------------------------- 1 | ### Super magic keyword4 2 | 3 | ```ruby 4 | class Parent 5 | def show_args(*args, &block) 6 | p [*args, block] 7 | end 8 | end 9 | 10 | class Child < Parent 11 | def show_args(a,b,c) 12 | # modify super by passing nothing 13 | # calling super with a nil proc, 14 | # which is basically calling super() 15 | super(&nil) 16 | end 17 | end 18 | 19 | #Nothing goes up, neither the block 20 | Child.new.show_args(:a, :b, :c) { :block } 21 | 22 | # Result: 23 | # [nil] 24 | 25 | ``` 26 | 27 | [View Source](source_code/super_magic_keyword4.rb) 28 | 29 | -------------------------------------------------------------------------------- /tricks/count-all-objects.md: -------------------------------------------------------------------------------- 1 | ### Count all objects 2 | 3 | ```ruby 4 | require 'pp' 5 | 6 | pp ObjectSpace.count_objects 7 | 8 | # Result: 9 | # {:TOTAL=>30163, 10 | # :FREE=>1007, 11 | # :T_OBJECT=>39, 12 | # :T_CLASS=>534, 13 | # :T_MODULE=>24, 14 | # :T_FLOAT=>4, 15 | # :T_STRING=>9290, 16 | # :T_REGEXP=>70, 17 | # :T_ARRAY=>2231, 18 | # :T_HASH=>53, 19 | # :T_STRUCT=>1, 20 | # :T_BIGNUM=>2, 21 | # :T_FILE=>14, 22 | # :T_DATA=>966, 23 | # :T_MATCH=>1, 24 | # :T_COMPLEX=>1, 25 | # :T_NODE=>15896, 26 | # :T_ICLASS=>30} 27 | 28 | ``` 29 | 30 | [View Source](source_code/count_all_objects.rb) 31 | 32 | -------------------------------------------------------------------------------- /tricks/super-magic-keyword5.md: -------------------------------------------------------------------------------- 1 | ### Super magic keyword5 2 | 3 | ```ruby 4 | class DontDelegateToMe; end 5 | class DelegateToMe; def delegate; "DelegateToMe" end end 6 | 7 | module DelegateIfCan 8 | def delegate 9 | if defined? super 10 | "Modified: #{super}" 11 | else 12 | "DelegateIfCan" 13 | end 14 | end 15 | end 16 | 17 | p DelegateToMe.new.extend(DelegateIfCan).delegate 18 | p DontDelegateToMe.new.extend(DelegateIfCan).delegate 19 | 20 | # Result: 21 | # "Modified: DelegateToMe" 22 | # "DelegateIfCan" 23 | 24 | ``` 25 | 26 | [View Source](source_code/super_magic_keyword5.rb) 27 | 28 | -------------------------------------------------------------------------------- /tricks/source_code/easiest_database_pstore.rb: -------------------------------------------------------------------------------- 1 | require 'pstore' 2 | 3 | db = PStore.new('mydatabase.pstore') 4 | 5 | db.transaction do 6 | db['people1'] = 'Someone' 7 | db['money1'] = 400 8 | end 9 | 10 | db.transaction do 11 | db['people2'] = 'Someone2' 12 | db['money2'] = 300 13 | end 14 | 15 | 16 | db.transaction(true) do 17 | p 'People %p' % db['people1'] 18 | p 'Money %p' % db['money1'] 19 | p "SECOND PERSON" 20 | p 'People %p' % db['people2'] 21 | p 'Money %p' % db['money2'] 22 | end 23 | 24 | # Result: 25 | # "People \"Someone\"" 26 | # "Money 400" 27 | # "SECOND PERSON" 28 | # "People \"Someone2\"" 29 | # "Money 300" 30 | -------------------------------------------------------------------------------- /tricks/source_code/easiest_database_pstore_yaml.rb: -------------------------------------------------------------------------------- 1 | require 'yaml/store' 2 | 3 | db = YAML::Store.new('people.yml') 4 | 5 | db.transaction do 6 | db['people1'] = 'Someone' 7 | db['money1'] = 400 8 | end 9 | 10 | db.transaction do 11 | db['people2'] = 'Someone2' 12 | db['money2'] = 300 13 | end 14 | 15 | 16 | db.transaction(true) do 17 | p 'People %p' % db['people1'] 18 | p 'Money %p' % db['money1'] 19 | p "SECOND PERSON" 20 | p 'People %p' % db['people2'] 21 | p 'Money %p' % db['money2'] 22 | end 23 | 24 | # Result: 25 | # "People \"Someone\"" 26 | # "Money 400" 27 | # "SECOND PERSON" 28 | # "People \"Someone2\"" 29 | # "Money 300" 30 | -------------------------------------------------------------------------------- /idiomatic_ruby/options_hash_with_defaults.md: -------------------------------------------------------------------------------- 1 | ## Options Hash with defaults 2 | 3 | Merge two hashes to get an overwritten version in favor of the second one. 4 | 5 | ```ruby 6 | def create_user(options = {}) 7 | user_options = { name: 'user', avatar: 'default.png'}.merge!(options) 8 | end 9 | 10 | p create_user 11 | #=> { name: 'user', avatar: 'default.png'} 12 | 13 | p create_user name: 'Adam' 14 | #=> { name: 'Adam', avatar: 'default.png'} 15 | 16 | p create_user name: 'Salma', avatar: 'special.png' 17 | #=> { name: 'Salma', avatar: 'special.png'} 18 | ``` 19 | 20 | Note that ``merge!`` alters its receiver (original hash), while ``merge`` returns a new hash. -------------------------------------------------------------------------------- /tricks/add_uniq_value_to_array.md: -------------------------------------------------------------------------------- 1 | ### How to add uniq value to array 2 | 3 | ```ruby 4 | array = [1, 2, 3] 5 | ``` 6 | 7 | #### bad 8 | ```ruby 9 | array << 2 10 | array << 4 11 | 12 | # Result: 13 | # [1, 2, 3, 2, 4] 14 | 15 | p array.uniq 16 | 17 | # Result: 18 | # [1, 2, 3, 4] 19 | 20 | ``` 21 | 22 | #### good (but need refactor) 23 | 24 | ```ruby 25 | array = array | [2] 26 | array = array | [4] 27 | 28 | p array 29 | 30 | # Result: 31 | # [1, 2, 3, 4] 32 | ``` 33 | 34 | #### good 35 | 36 | ```ruby 37 | array |= [2, 4] 38 | 39 | p array 40 | 41 | # Result: 42 | # [1, 2, 3, 4] 43 | ``` 44 | 45 | [View Source](source_code/add_uniq_value_to_array.rb) 46 | -------------------------------------------------------------------------------- /tricks/source_code/unfreeze_objects_with_fiddle.rb: -------------------------------------------------------------------------------- 1 | require 'fiddle' 2 | 3 | class Object 4 | # RUBY_FL_FREEZE = (1<<11) http://git.io/v8WEt 5 | 6 | # [ 0 ][ 1 ] 7 | # 0 1 2 3 4 5 6 7 8 9 10 11 ... 8 | # 1 2 4 8 16 32 64 128 256 512 1024 2048 ... 9 | # 1 2 4 8 < Zero this bit unconditionally. 10 | def unfreeze 11 | Fiddle::Pointer.new(object_id * 2)[1] &= ~8 12 | self 13 | end 14 | 15 | alias thaw unfreeze 16 | end 17 | 18 | str = 'foo'.freeze 19 | p str.frozen? 20 | str << 'bar' rescue p $! 21 | 22 | str.thaw 23 | p str.frozen? 24 | p str << 'bar' 25 | 26 | # Result: 27 | # true 28 | # # 29 | # false 30 | # "foobar" 31 | -------------------------------------------------------------------------------- /tricks/easiest-database-pstore.md: -------------------------------------------------------------------------------- 1 | ### Easiest database pstore 2 | 3 | ```ruby 4 | require 'pstore' 5 | 6 | db = PStore.new('mydatabase.pstore') 7 | 8 | db.transaction do 9 | db['people1'] = 'Someone' 10 | db['money1'] = 400 11 | end 12 | 13 | db.transaction do 14 | db['people2'] = 'Someone2' 15 | db['money2'] = 300 16 | end 17 | 18 | 19 | db.transaction(true) do 20 | p 'People %p' % db['people1'] 21 | p 'Money %p' % db['money1'] 22 | p "SECOND PERSON" 23 | p 'People %p' % db['people2'] 24 | p 'Money %p' % db['money2'] 25 | end 26 | 27 | # Result: 28 | # "People \"Someone\"" 29 | # "Money 400" 30 | # "SECOND PERSON" 31 | # "People \"Someone2\"" 32 | # "Money 300" 33 | 34 | ``` 35 | 36 | [View Source](source_code/easiest_database_pstore.rb) 37 | 38 | -------------------------------------------------------------------------------- /tricks/easiest-database-pstore-yaml.md: -------------------------------------------------------------------------------- 1 | ### Easiest database pstore yaml 2 | 3 | ```ruby 4 | require 'yaml/store' 5 | 6 | db = YAML::Store.new('people.yml') 7 | 8 | db.transaction do 9 | db['people1'] = 'Someone' 10 | db['money1'] = 400 11 | end 12 | 13 | db.transaction do 14 | db['people2'] = 'Someone2' 15 | db['money2'] = 300 16 | end 17 | 18 | 19 | db.transaction(true) do 20 | p 'People %p' % db['people1'] 21 | p 'Money %p' % db['money1'] 22 | p "SECOND PERSON" 23 | p 'People %p' % db['people2'] 24 | p 'Money %p' % db['money2'] 25 | end 26 | 27 | # Result: 28 | # "People \"Someone\"" 29 | # "Money 400" 30 | # "SECOND PERSON" 31 | # "People \"Someone2\"" 32 | # "Money 300" 33 | 34 | ``` 35 | 36 | [View Source](source_code/easiest_database_pstore_yaml.rb) 37 | 38 | -------------------------------------------------------------------------------- /idiomatic_ruby.md: -------------------------------------------------------------------------------- 1 | # Idiomatic Ruby 2 | 3 | * [Each vs map](idiomatic_ruby/each_vs_map.md) 4 | * [Conditional assignment](idiomatic_ruby/conditional_assignment.md) 5 | * [Combine operation over collections (enumerables)](idiomatic_ruby/combine_elements_in_collection.md) 6 | * [Array of Strings or Symbols](idiomatic_ruby/array_of_strings_symbols.md) 7 | * [Multiple Assignment](idiomatic_ruby/multiple_assignment.md) 8 | * [Use Symbol to_proc](idiomatic_ruby/use_symbol_to_proc.md) 9 | * [Array Sample (enumerables)](idiomatic_ruby/array_sample.md) 10 | * [Use Fixnum#times](idiomatic_ruby/use_times.md) 11 | * [Implicit Return](idiomatic_ruby/implicit_return.md) 12 | * [Collect vs Select](idiomatic_ruby/collect_vs_select.md) 13 | * [Options Hash with Defaults](idiomatic_ruby/options_hash_with_defaults.md) 14 | -------------------------------------------------------------------------------- /tricks/unfreeze-objects-with-fiddle.md: -------------------------------------------------------------------------------- 1 | ### Unfreeze objects with fiddle 2 | 3 | ```ruby 4 | require 'fiddle' 5 | 6 | class Object 7 | # RUBY_FL_FREEZE = (1<<11) http://git.io/v8WEt 8 | 9 | # [ 0 ][ 1 ] 10 | # 0 1 2 3 4 5 6 7 8 9 10 11 ... 11 | # 1 2 4 8 16 32 64 128 256 512 1024 2048 ... 12 | # 1 2 4 8 < Zero this bit unconditionally. 13 | def unfreeze 14 | Fiddle::Pointer.new(object_id * 2)[1] &= ~8 15 | self 16 | end 17 | 18 | alias thaw unfreeze 19 | end 20 | 21 | str = 'foo'.freeze 22 | p str.frozen? 23 | str << 'bar' rescue p $! 24 | 25 | str.thaw 26 | p str.frozen? 27 | p str << 'bar' 28 | 29 | # Result: 30 | # true 31 | # # 32 | # false 33 | # "foobar" 34 | 35 | ``` 36 | 37 | [View Source](source_code/unfreeze_objects_with_fiddle.rb) 38 | 39 | -------------------------------------------------------------------------------- /tricks/source_code/splat_operator.rb: -------------------------------------------------------------------------------- 1 | # Splat Operator (*) 2 | 3 | # When calling methods 4 | 5 | arguments = [1, 2, 3, 4] 6 | my_method(*arguments) # any number of arguments 7 | 8 | 9 | 10 | # or: 11 | 12 | arguments = [2, 3, 4] 13 | my_method(1, *arguments) # any number of trailing arguments 14 | 15 | # or: 16 | 17 | arguments = [1, 2] 18 | my_method(*arguments, 3, 4) # any number of preceding arguments 19 | 20 | 21 | # or: 22 | 23 | arguments = [2, 3] 24 | my_method(1, *arguments, 4) # any number of "in between" arguments 25 | 26 | # All are equivalent to: 27 | 28 | my_method(1, 2, 3, 4) 29 | 30 | # Two splats (**) convert a hash into an arbitary number of keyword arguments 31 | # This operator doesn't technically have a name 32 | 33 | arguments = { first: 1, second: 2, third: 3 } 34 | my_method(**arguments) 35 | 36 | # or: 37 | 38 | arguments = { first: 1, second: 2 } 39 | my_method(third: 3, **arguments) 40 | 41 | # Are equivalent to: 42 | 43 | my_method(first:1, second:2, third:3) 44 | -------------------------------------------------------------------------------- /refactorings/conditionals_when_object_is_nil.md: -------------------------------------------------------------------------------- 1 | ## Conditionals when object is nil 2 | 3 | **Before:** 4 | 5 | ```ruby 6 | event.end_date.nil? ? '' : event.end_date.to_s(:long) 7 | ``` 8 | 9 | **After:** 10 | 11 | ```ruby 12 | event.end_date.try(:to_s, :long) 13 | ``` 14 | 15 | **Or (2.3+):** 16 | 17 | ```ruby 18 | event.end_date&.to_s&.long 19 | ``` 20 | [About &. operator](http://mitrev.net/ruby/2015/11/13/the-operator-in-ruby/) 21 | 22 | **Remembering:** [try](http://apidock.com/rails/Object/try) is a Rails method and it's not in Ruby Core. 23 | 24 | The documentation for try says: 25 | 26 | > Invokes the method identified by the symbol method, passing it any arguments and/or the block specified, just like Ruby. 27 | > Object#send. Unlike that method, nil will be returned if the receiving object is a nil object or NilClass. 28 | 29 | It’s usually worth spending time identifying why you have to do this at all. If you can remove the scenario where the object is nil, that’s preferable. 30 | 31 | From: https://robots.thoughtbot.com/code-review-ruby-and-rails-idioms 32 | -------------------------------------------------------------------------------- /tricks/source_code/stab_operator.rb: -------------------------------------------------------------------------------- 1 | # Stab Operator - Lambdas in Ruby 1.9 or later. 2 | # Y Combinator 3 | # Ruby supports a syntax for lambdas known as the 'stab' operator. 4 | # Rather than something like lambda { a < 5 }, 5 | # you can type -> { a < 5 }. 6 | # 7 | # Below is a version of the fibonacci sequence that can 8 | # perform recursive calls without named functions. 9 | # 10 | # Improver function for fibonacci sequence 11 | # Assumes that the 0th element of the sequence is 0, 12 | # and the 1st element of the sequence is 1. 13 | fib_improver = ->(partial) { 14 | ->(n) { n < 2 ? n : partial.(n-1) + partial.(n-2) } 15 | } 16 | 17 | # The y combinator 18 | y = ->(f) { 19 | ->(x) { x.(x) }.( 20 | ->(x) { f.(->(v) { x.(x).(v)}) } 21 | ) 22 | } 23 | 24 | # Using the stab operator and y combinator, we can 25 | # write a fibonacci function with anonymous functions 26 | # This solution is not memoized and so will be very slow. 27 | fib = fib_improver.(y.(fib_improver)) 28 | 29 | p fib.(1) 30 | 31 | p fib.(10) 32 | # Notice that after loading, fib isn't defined anymore. 33 | -------------------------------------------------------------------------------- /tricks/splat-operator.md: -------------------------------------------------------------------------------- 1 | ### Splat operator 2 | 3 | ```ruby 4 | # Splat Operator (*) 5 | 6 | # When calling methods 7 | 8 | arguments = [1, 2, 3, 4] 9 | my_method(*arguments) # any number of arguments 10 | 11 | # or: 12 | 13 | arguments = [2, 3, 4] 14 | my_method(1, *arguments) # any number of trailing arguments 15 | 16 | # or: 17 | 18 | arguments = [1, 2] 19 | my_method(*arguments, 3, 4) # any number of preceding arguments 20 | 21 | # or: 22 | 23 | arguments = [2, 3] 24 | my_method(1, *arguments, 4) # any number of "in between" arguments 25 | 26 | # All are equivalent to: 27 | 28 | my_method(1, 2, 3, 4) 29 | 30 | # Two splats (**) convert a hash into an arbitary number of keyword arguments 31 | # This operator doesn't technically have a name 32 | 33 | arguments = { first: 1, second: 2, third: 3 } 34 | my_method(**arguments) 35 | 36 | # or: 37 | 38 | arguments = { first: 1, second: 2 } 39 | my_method(third: 3, **arguments) 40 | 41 | # Are equivalent to: 42 | 43 | my_method(first:1, second:2, third:3) 44 | 45 | ``` 46 | 47 | [View Source](source_code/splat_operator.rb) 48 | 49 | -------------------------------------------------------------------------------- /tricks/introspecting_block_parameters.md: -------------------------------------------------------------------------------- 1 | ## Introspecting Block Parameters 2 | 3 | Suppose you would like to iterate over a hash, get its elements and use those 4 | in a block. One thing you can do is use `Proc#parameters` to help you. 5 | 6 | For example: 7 | 8 | ```ruby 9 | hash = { 10 | first_name: "John", 11 | last_name: "Smith", 12 | age: 35, 13 | # ... 14 | } 15 | 16 | hash.using do |first_name, last_name| 17 | puts "Hello, #{first_name} #{last_name}." 18 | end 19 | 20 | # or even... 21 | 22 | circle = { 23 | radius: 5, 24 | color: "blue", 25 | # ... 26 | } 27 | 28 | area = circle.using { |radius| Math::PI * radius**2 } 29 | ``` 30 | 31 | You can check how the implementation is really simple: 32 | 33 | ```ruby 34 | class Hash 35 | module Using 36 | def using(&block) 37 | values = block.parameters.map do |(type, name)| 38 | self[name] 39 | end 40 | 41 | block.call(*values) 42 | end 43 | end 44 | 45 | include Using 46 | end 47 | ``` 48 | 49 | From: 50 | 51 | http://weblog.jamisbuck.org/2015/12/12/little-things-proc-parameters.html 52 | -------------------------------------------------------------------------------- /tricks/source_code/Rakefile: -------------------------------------------------------------------------------- 1 | 2 | desc "Build summary.md from source files" 3 | task :build do 4 | toc = [] 5 | 6 | File.open("SUMMARY.md", "w+") do |summary| 7 | 8 | Dir.glob("*.rb").sort.each do |file| 9 | filename = File.basename file 10 | heading = File.basename(file, ".rb").tr("_", " ").capitalize 11 | link = heading.tr(" ", "-").downcase 12 | content = File.read file 13 | 14 | # Add link to table on contents 15 | toc << "[#{heading}](#{link}.md)" 16 | 17 | # Add trick file 18 | trick_content_file = %{### #{heading} 19 | 20 | ```ruby 21 | #{content} 22 | ``` 23 | 24 | [View Source](source_code/#{filename}) 25 | 26 | } 27 | 28 | # Render tricks 29 | File.open("#{link}.md", 'w+') do |trick_file| 30 | trick_file.puts trick_content_file 31 | end 32 | 33 | end 34 | 35 | 36 | # Render intro 37 | summary.puts %{# Tricks} 38 | 39 | # Render table of contents 40 | summary.puts "\n" 41 | toc.each do |link| 42 | summary.puts "- #{link}" 43 | end 44 | 45 | summary.puts "\n" 46 | end 47 | end 48 | -------------------------------------------------------------------------------- /tricks/source_code/at_exit_method.rb: -------------------------------------------------------------------------------- 1 | #Basic use 2 | puts 'script start' 3 | at_exit do 4 | puts 'inside at_exit method for the first time' 5 | end 6 | 7 | #anywhere in your code again 8 | at_exit do 9 | puts 'inside at_exit method for the second time' 10 | end 11 | puts "script end" 12 | 13 | #Result: 14 | #script start 15 | #script end 16 | #inside at_exit method for the second time 17 | #inside at_exit method for the first time 18 | 19 | 20 | #Own exception crash logger 21 | at_exit do 22 | if $! # If the program exits due to an exception 23 | puts 'Exiting' 24 | 25 | #you can also print log to a file 26 | #you can send notification to another app 27 | end 28 | end 29 | 30 | 31 | 32 | #Logging error anywhere when program exit 33 | 34 | (Thread.current[:errors] ||= []) << 'Any error message goes here' 35 | #or 36 | def log_error(error_message) 37 | (Thread.current[:errors] ||= []) << "#{error_message}" 38 | end 39 | 40 | #Now, log all the errors 41 | at_exit do 42 | File.open('errors.txt', 'a') do |file| 43 | (Thread.current[:errors] ||= []).each do |error| 44 | file.puts error 45 | end 46 | end 47 | end -------------------------------------------------------------------------------- /idiomatic_ruby/combine_elements_in_collection.md: -------------------------------------------------------------------------------- 1 | ## Combine operation in collections (enumerables) 2 | 3 | Given the following collection: 4 | 5 | ```ruby 6 | values = [1, 2, 3, 4] 7 | ``` 8 | 9 | ### Combine elements with **reduce** 10 | 11 | An operation such as: 12 | 13 | ```ruby 14 | product = 1 15 | values.each { |value| product *= value } 16 | product 17 | # => 24 18 | ``` 19 | 20 | Can be simplified with `reduce` method: 21 | 22 | ```ruby 23 | values.reduce(:*) 24 | # => 24 25 | ``` 26 | 27 | ### Combine elements with **inject** 28 | 29 | An operation such as: 30 | ```ruby 31 | hash = {} 32 | values.each do |value| 33 | hash.merge!(value => value ** 2) 34 | end 35 | hash 36 | # => { 1 => 1, 2 => 4, 3 => 9, 4 => 16 } 37 | ``` 38 | 39 | Can be simplified with `inject` method: 40 | 41 | ```ruby 42 | values.inject({}) do |hash, value| 43 | hash.merge(value => value ** 2) 44 | end 45 | # => { 1 => 1, 2 => 4, 3 => 9, 4 => 16 } 46 | ``` 47 | 48 | Or with the `each_with_object` method: 49 | 50 | ```ruby 51 | values.each_with_object({}) do |value, hash| 52 | hash[value] = value ** 2 53 | end 54 | # => { 1 => 1, 2 => 4, 3 => 9, 4 => 16 } 55 | ``` 56 | -------------------------------------------------------------------------------- /tricks/stab-operator.md: -------------------------------------------------------------------------------- 1 | ### Stab operator 2 | 3 | ```ruby 4 | # Stab Operator - Lambdas in Ruby 1.9 or later. 5 | # Y Combinator 6 | # Ruby supports a syntax for lambdas known as the 'stab' operator. 7 | # Rather than something like lambda { a < 5 }, 8 | # you can type -> { a < 5 }. 9 | # 10 | # Below is a version of the fibonacci sequence that can 11 | # perform recursive calls without named functions. 12 | # 13 | # Improver function for fibonacci sequence 14 | # Assumes that the 0th element of the sequence is 0, 15 | # and the 1st element of the sequence is 1. 16 | fib_improver = ->(partial) { 17 | ->(n) { n < 2 ? n : partial.(n-1) + partial.(n-2) } 18 | } 19 | 20 | # The y combinator 21 | y = ->(f) { 22 | ->(x) { x.(x) }.( 23 | ->(x) { f.(->(v) { x.(x).(v)}) } 24 | ) 25 | } 26 | 27 | # Using the stab operator and y combinator, we can 28 | # write a fibonacci function with anonymous functions 29 | # This solution is not memoized and so will be very slow. 30 | fib = fib_improver.(y.(fib_improver)) 31 | 32 | p fib.(1) 33 | 34 | p fib.(10) 35 | # Notice that after loading, fib isn't defined anymore. 36 | 37 | ``` 38 | 39 | [View Source](source_code/stab_operator.rb) 40 | 41 | -------------------------------------------------------------------------------- /tricks/at-exit-method.md: -------------------------------------------------------------------------------- 1 | ### At exit method 2 | 3 | ```ruby 4 | #Basic use 5 | puts 'script start' 6 | at_exit do 7 | puts 'inside at_exit method for the first time' 8 | end 9 | 10 | #anywhere in your code again 11 | at_exit do 12 | puts 'inside at_exit method for the second time' 13 | end 14 | puts "script end" 15 | 16 | #Result: 17 | #script start 18 | #script end 19 | #inside at_exit method for the second time 20 | #inside at_exit method for the first time 21 | 22 | 23 | #Own exception crash logger 24 | at_exit do 25 | if $! # If the program exits due to an exception 26 | puts 'Exiting' 27 | 28 | #you can also print log to a file 29 | #you can send notification to another app 30 | end 31 | end 32 | 33 | 34 | 35 | #Logging error anywhere when program exit 36 | 37 | (Thread.current[:errors] ||= []) << 'Any error message goes here' 38 | #or 39 | def log_error(error_message) 40 | (Thread.current[:errors] ||= []) << "#{error_message}" 41 | end 42 | 43 | #Now, log all the errors 44 | at_exit do 45 | File.open('errors.txt', 'a') do |file| 46 | (Thread.current[:errors] ||= []).each do |error| 47 | file.puts error 48 | end 49 | end 50 | end 51 | ``` 52 | 53 | [View Source](source_code/at_exit_method.rb) 54 | 55 | -------------------------------------------------------------------------------- /tricks/source_code/memoization.rb: -------------------------------------------------------------------------------- 1 | # based on Justin Weiss' article: 2 | # http://www.justinweiss.com/articles/4-simple-memoization-patterns-in-ruby-and-one-gem/ 3 | 4 | class Memoize 5 | # one liner 6 | def my_simple_method 7 | @my_simple_method ||= do_some_calculation 8 | end 9 | 10 | # multiple lines 11 | def my_more_complex_method 12 | @my_more_complex_method ||= begin 13 | a = do_some_calculation 14 | b = do_some_more_calculation 15 | a + b 16 | end 17 | end 18 | 19 | # what if our calculations return nil?... 20 | 21 | # one liner 22 | def my_simple_method 23 | return @my_simple_method if defined? @my_simple_method 24 | @my_simple_method = do_some_calculation 25 | end 26 | 27 | # multiple lines 28 | def my_more_complex_method 29 | return @my_more_complex_method if defined? @my_more_complex_method 30 | @my_more_complex_method = begin 31 | a = do_some_calculation 32 | b = do_some_more_calculation 33 | a + b 34 | end 35 | end 36 | 37 | # what about differing arguments?... 38 | 39 | def my_really_complex_method(*args) 40 | @my_really_complex_method ||= Hash.new do |h, key| 41 | h[key] = do_some_calculation(*key) 42 | end 43 | @my_really_complex_method[args] 44 | end 45 | end 46 | -------------------------------------------------------------------------------- /tricks/memoization.md: -------------------------------------------------------------------------------- 1 | ### Memoization 2 | 3 | ```ruby 4 | # based on Justin Weiss' article: 5 | # http://www.justinweiss.com/articles/4-simple-memoization-patterns-in-ruby-and-one-gem/ 6 | 7 | class Memoize 8 | # one liner 9 | def my_simple_method 10 | @my_simple_method ||= do_some_calculation 11 | end 12 | 13 | # multiple lines 14 | def my_more_complex_method 15 | @my_more_complex_method ||= begin 16 | a = do_some_calculation 17 | b = do_some_more_calculation 18 | a + b 19 | end 20 | end 21 | 22 | # what if our calculations return nil?... 23 | 24 | # one liner 25 | def my_simple_method 26 | return @my_simple_method if defined? @my_simple_method 27 | @my_simple_method = do_some_calculation 28 | end 29 | 30 | # multiple lines 31 | def my_more_complex_method 32 | return @my_more_complex_method if defined? @my_more_complex_method 33 | @my_more_complex_method = begin 34 | a = do_some_calculation 35 | b = do_some_more_calculation 36 | a + b 37 | end 38 | end 39 | 40 | # what about differing arguments?... 41 | 42 | def my_really_complex_method(*args) 43 | @my_really_complex_method ||= Hash.new do |h, key| 44 | h[key] = do_some_calculation(*key) 45 | end 46 | @my_really_complex_method[args] 47 | end 48 | end 49 | 50 | ``` 51 | 52 | [View Source](source_code/memoization.rb) 53 | 54 | -------------------------------------------------------------------------------- /idiomatic_ruby/conditional_assignment.md: -------------------------------------------------------------------------------- 1 | ## Conditional assignment 2 | Ruby is heavily influenced by lisp. One piece of obvious inspiration in its 3 | design is that conditional operators return values. This makes assignment based 4 | on conditions quite clean and simple to read. 5 | 6 | There are quite a number of conditional operators you can use. Optimize for 7 | readability, maintainability, and concision. 8 | 9 | **Before:** 10 | ```rb 11 | if some_bool 12 | string_version = 'yes' 13 | else 14 | string_version = 'no' 15 | end 16 | ``` 17 | 18 | **After:** 19 | 20 | If you're just assigning based on a boolean, the ternary operator works best 21 | (this is not specific to ruby/lisp but still good and in the spirit of the 22 | following examples!). 23 | ```rb 24 | string_version = some_bool ? 'yes' : 'no' 25 | ``` 26 | 27 | If you need to perform more complex logic based on a conditional or allow for 28 | \> 2 outcomes, `if`/`elsif`/`else` expressions work well. 29 | ```rb 30 | retval = if foo 31 | 'foooooo!' 32 | elsif bar 33 | 'baaaar' 34 | else 35 | 'dunno' 36 | end 37 | ``` 38 | 39 | If you're assigning based on the value of a single variable, use `case`/`when` 40 | A good barometer is to think if you could represent the assignment in a hash. 41 | For example, in the following example you could look up the value of `opinion` 42 | in a hash that looks like `{"ANGRY" => comfort, "MEH" => ignore ...}` 43 | ```rb 44 | action_result = case opinion 45 | when "ANGRY" 46 | comfort 47 | when "MEH" 48 | ignore 49 | when "HAPPY" 50 | high_five 51 | else 52 | ask_opinion 53 | end 54 | ``` 55 | -------------------------------------------------------------------------------- /best_practices/using_exception_e.md: -------------------------------------------------------------------------------- 1 | ## rescue => Exception e 2 | 3 | Let’s say you want to capture exception details, like in the following example: 4 | 5 | **Problem:** 6 | 7 | ```ruby 8 | def do_something! 9 | # ... do something ... 10 | success 11 | rescue Exception => e 12 | failed e 13 | end 14 | ``` 15 | 16 | [Example](https://gist.github.com/rafaelsales/1067532247934508e455#file-non-stopper-rb): 17 | 18 | ```ruby 19 | loop do 20 | begin 21 | sleep 1 22 | rescue Exception => e 23 | puts "I'm STRONGER. Give up!" 24 | end 25 | end 26 | # Run and try CTRL+C 27 | ``` 28 | 29 | Using ``Exception => e`` we are allowing ALL the Exception types, as you can see above: 30 | 31 | ``` 32 | Exception 33 | NoMemoryError 34 | ScriptError 35 | LoadError 36 | NotImplementedError 37 | SyntaxError 38 | SignalException 39 | Interrupt 40 | StandardError 41 | ArgumentError 42 | IOError 43 | EOFError 44 | IndexError 45 | LocalJumpError 46 | NameError 47 | NoMethodError 48 | RangeError 49 | FloatDomainError 50 | RegexpError 51 | RuntimeError 52 | SecurityError 53 | SystemCallError 54 | SystemStackError 55 | ThreadError 56 | TypeError 57 | ZeroDivisionError 58 | SystemExit 59 | fatal 60 | ``` 61 | 62 | **Solution:** 63 | 64 | What to do instead? Start using rescue => e as it’s the same for rescue StandardError => e and is almost certainly the broadest type of Exception that we want to rescue. 65 | 66 | ```ruby 67 | def do_something! 68 | # ... do something ... 69 | success 70 | rescue => e 71 | failed e 72 | end 73 | ``` 74 | 75 | Interesting Links: 76 | 77 | - http://stackoverflow.com/questions/10048173/why-is-it-bad-style-to-rescue-exception-e-in-ruby 78 | - http://daniel.fone.net.nz/blog/2013/05/28/why-you-should-never-rescue-exception-in-ruby/ 79 | - https://robots.thoughtbot.com/rescue-standarderror-not-exception 80 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Code of Conduct 2 | 3 | As contributors and maintainers of this project, and in the interest of fostering an open and welcoming community, we pledge to respect all people who contribute through reporting issues, posting feature requests, updating documentation, submitting pull requests or patches, and other activities. 4 | 5 | We are committed to making participation in this project a harassment-free experience for everyone, regardless of level of experience, gender, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, ethnicity, age, religion, or nationality. 6 | 7 | Examples of unacceptable behavior by participants include: 8 | 9 | * The use of sexualized language or imagery 10 | * Personal attacks 11 | * Trolling or insulting/derogatory comments 12 | * Public or private harassment 13 | * Publishing other's private information, such as physical or electronic addresses, without explicit permission 14 | * Other unethical or unprofessional conduct. 15 | 16 | Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct. By adopting this Code of Conduct, project maintainers commit themselves to fairly and consistently applying these principles to every aspect of managing this project. Project maintainers who do not follow or enforce the Code of Conduct may be permanently removed from the project team. 17 | 18 | This code of conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. 19 | 20 | Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by opening an issue or contacting one or more of the project maintainers. 21 | 22 | This Code of Conduct is adapted from the [Contributor Covenant](http://contributor-covenant.org), version 1.2.0, available at [http://contributor-covenant.org/version/1/2/0/](http://contributor-covenant.org/version/1/2/0/) 23 | -------------------------------------------------------------------------------- /idiomatic_ruby/implicit_return.md: -------------------------------------------------------------------------------- 1 | ## Implicit return 2 | 3 | Every block in ruby will return the value of the last line automatically, so it's common to not use the `return` keyword in favor of minimal code (specially if the method fits in one line): 4 | 5 | ```ruby 6 | def extract_user_ids(users) 7 | users.map(&:id) 8 | end 9 | 10 | # is the same as 11 | 12 | def extract_user_ids(users) 13 | return users.map(&:id) 14 | end 15 | ``` 16 | 17 | Although it may cause some confusion in bigger methods, some people tend to not use the return keyword explicitly. 18 | 19 | In the following example the explicit return is misleading because even though the return is inside a map block, it is actually stopping the entire method. 20 | 21 | ```ruby 22 | def odd_or_even(numbers) 23 | numbers.map do |number| 24 | "odd" if number.odd? 25 | "even" if number.even? 26 | end 27 | end 28 | 29 | odd_or_even([1,2,4,3]) 30 | # returns ["odd", "even", "even", "odd"] 31 | 32 | def odd_or_even(numbers) 33 | numbers.map do |number| 34 | return "odd" if number.odd? 35 | return "even" if number.even? 36 | end 37 | end 38 | 39 | odd_or_even([1,2,4,3]) 40 | # returns "odd" 41 | ``` 42 | 43 | Using return explicitly can also lead to errors if used inside Procs. The LocalJumpError exception is raised when Ruby can’t yield, like in the following example: 44 | 45 | ```ruby 46 | yelling = Proc.new do |message| 47 | return message.upcase 48 | end 49 | 50 | calming = Proc.new do |message| 51 | message.downcase 52 | end 53 | 54 | def tell(message, manner) 55 | manner.call(message) 56 | end 57 | 58 | tell("hey", yelling) 59 | # will throw LocalJumpError 60 | 61 | tell("HELLO!", calming) 62 | # will return "hello!" 63 | 64 | ``` 65 | In this case it is better to let the language handle the flow of calls and not use the `return` keyword. 66 | 67 | More discussions about return in ruby: 68 | 69 | http://stackoverflow.com/questions/1023146/is-it-good-style-to-explicitly-return-in-ruby 70 | http://stackoverflow.com/questions/15187287/ruby-block-statements-and-implicit-returns 71 | http://stackoverflow.com/questions/8162831/ruby-lambda-vs-proc-localjumperror 72 | 73 | -------------------------------------------------------------------------------- /tricks/SUMMARY.md: -------------------------------------------------------------------------------- 1 | # Tricks 2 | 3 | - [Alphanumeric incrementing](alphanumeric-incrementing.md) 4 | - [Associative arrays](associative-arrays.md) 5 | - [At exit method](at-exit-method.md) 6 | - [Autovivification](autovivification.md) 7 | - [Blocks can take blocks](blocks-can-take-blocks.md) 8 | - [Bubbling up thread errors](bubbling-up-thread-errors.md) 9 | - [Case on ranges](case-on-ranges.md) 10 | - [Count all objects](count-all-objects.md) 11 | - [Cycle](cycle.md) 12 | - [Data](data.md) 13 | - [Easiest database pstore](easiest-database-pstore.md) 14 | - [Easiest database pstore yaml](easiest-database-pstore-yaml.md) 15 | - [Enable garbage collector profiler](enable-garbage-collector-profiler.md) 16 | - [Enable ruby warnings](enable-ruby-warnings.md) 17 | - [Fast memoization fibonacci](fast-memoization-fibonacci.md) 18 | - [Fetch data](fetch-data.md) 19 | - [Get random data](get-random-data.md) 20 | - [Head tail](head-tail.md) 21 | - [Inject](inject.md) 22 | - [Inspecting the source with script lines](inspecting-the-source-with-script-lines.md) 23 | - [Iterating over specific types](iterating-over-specific-types.md) 24 | - [Lambda your own syntax](lambda-your-own-syntax.md) 25 | - [Memoization](memoization.md) 26 | - [Print formatted with debug](print-formatted-with-debug.md) 27 | - [Ruby debug flag](ruby-debug-flag.md) 28 | - [Shortcut variable interpolation](shortcut-variable-interpolation.md) 29 | - [Single instance running](single-instance-running.md) 30 | - [Smalltalk conditionals](smalltalk-conditionals.md) 31 | - [Splat operator](splat-operator.md) 32 | - [Stab operator](stab-operator.md) 33 | - [Struct without assignment](struct-without-assignment.md) 34 | - [Super magic keyword](super-magic-keyword.md) 35 | - [Super magic keyword2](super-magic-keyword2.md) 36 | - [Super magic keyword3](super-magic-keyword3.md) 37 | - [Super magic keyword4](super-magic-keyword4.md) 38 | - [Super magic keyword5](super-magic-keyword5.md) 39 | - [Tail call](tail-call.md) 40 | - [Trigger irb as needed](trigger-irb-as-needed.md) 41 | - [Unfreeze objects with fiddle](unfreeze-objects-with-fiddle.md) 42 | - [Unused variable format](unused-variable-format.md) 43 | - [Variables from a regex](variables-from-a-regex.md) 44 | - [Zip](zip.md) 45 | 46 | -------------------------------------------------------------------------------- /tricks.md: -------------------------------------------------------------------------------- 1 | # Tricks 2 | 3 | The majority of these Ruby Tricks were extracted from James Edward Gray II [talk](https://www.youtube.com/watch?v=aBgnlBoIkVM). 4 | 5 | * [Alphanumeric incrementing](tricks/alphanumeric-incrementing.md) 6 | * [Associative arrays](tricks/associative-arrays.md) 7 | * [At exit method](tricks/at-exit-method.md) 8 | * [Autovivification](tricks/autovivification.md) 9 | * [Blocks can take blocks](tricks/blocks-can-take-blocks.md) 10 | * [Bubbling up thread errors](tricks/bubbling-up-thread-errors.md) 11 | * [Case on ranges](tricks/case-on-ranges.md) 12 | * [Count all objects](tricks/count-all-objects.md) 13 | * [Cycle](tricks/cycle.md) 14 | * [Data](tricks/data.md) 15 | * [Easiest database pstore](tricks/easiest-database-pstore.md) 16 | * [Easiest database pstore yaml](tricks/easiest-database-pstore-yaml.md) 17 | * [Enable garbage collector profiler](tricks/enable-garbage-collector-profiler.md) 18 | * [Enable ruby warnings](tricks/enable-ruby-warnings.md) 19 | * [Fast memoization fibonacci](tricks/fast-memoization-fibonacci.md) 20 | * [Fetch data](tricks/fetch-data.md) 21 | * [Get random data](tricks/get-random-data.md) 22 | * [Head tail](tricks/head-tail.md) 23 | * [Inject](tricks/inject.md) 24 | * [Inspecting the source with script lines](tricks/inspecting-the-source-with-script-lines.md) 25 | * [Integer#digits](tricks/digits.md) 26 | * [Iterating over specific types](tricks/iterating-over-specific-types.md) 27 | * [Lambda your own syntax](tricks/lambda-your-own-syntax.md) 28 | * [Memoization](tricks/memoization.md) 29 | * [Print formatted with debug](tricks/print-formatted-with-debug.md) 30 | * [Ruby debug flag](tricks/ruby-debug-flag.md) 31 | * [Shortcut variable interpolation](tricks/shortcut-variable-interpolation.md) 32 | * [Single instance running](tricks/single-instance-running.md) 33 | * [Smalltalk conditionals](tricks/smalltalk-conditionals.md) 34 | * [Splat operator](tricks/splat-operator.md) 35 | * [Stab operator](tricks/stab-operator.md) 36 | * [Struct without assignment](tricks/struct-without-assignment.md) 37 | * [Super magic keyword](tricks/super-magic-keyword.md) 38 | * [Super magic keyword2](tricks/super-magic-keyword2.md) 39 | * [Super magic keyword3](tricks/super-magic-keyword3.md) 40 | * [Super magic keyword4](tricks/super-magic-keyword4.md) 41 | * [Super magic keyword5](tricks/super-magic-keyword5.md) 42 | * [Tail call](tricks/tail-call.md) 43 | * [Trigger irb as needed](tricks/trigger-irb-as-needed.md) 44 | * [Unfreeze objects with fiddle](tricks/unfreeze-objects-with-fiddle.md) 45 | * [Unused variable format](tricks/unused-variable-format.md) 46 | * [Variables from a regex](tricks/variables-from-a-regex.md) 47 | * [Zip](tricks/zip.md) 48 | * [Introspecting Block Parameters](tricks/introspecting_block_parameters.md) 49 | * [How to add uniq value to array](tricks/add_uniq_value_to_array.md) 50 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Ruby Tricks, Idiomatic Ruby, Refactorings and Best Practices 2 | 3 | > Do you know why experienced Ruby programmers tend to reach for basic collections 4 | > and hashes while programmers from other languages go for more specialized classes? 5 | > Do you know the difference between strip, chop, and chomp; and why there are three 6 | > such similar methods when apparently one might suffice (Not to mention lstrip and 7 | > rstrip!)? Do you know the downsides of dynamic typing? Do you know why the differences 8 | > between strings and symbols get so blurry, even to experienced Ruby developers? 9 | > How about metaprogramming? What the heck is an eigenclass? How about 10 | > protected methods? Do you know what they’re really about? Really? Are you sure? 11 | [Eloquent Ruby](http://www.amazon.com/Eloquent-Ruby-Addison-Wesley-Professional/dp/0321584104) 12 | 13 | > Absolutely the best way to learn to write idiomatic Ruby code is to read idiomatic Ruby code. [Eloquent Ruby](http://www.amazon.com/Eloquent-Ruby-Addison-Wesley-Professional/dp/0321584104) 14 | 15 | This repository aims to help everyone write more idiomatic, clean, and tricky ruby code and also document good refactoring techniques. You can add your own technique or paste it from some website. Do not forget the source, of course. All the tricks are in the /tricks folder. 16 | 17 | For the sake of clarity, you should paste in the markdown format. At the end, if the code is not your own, paste a reference to the author and source of the technique. 18 | 19 | ## [Tricks](tricks.md) 20 | 21 | In this part we can review some obscure or awesome features from the and the standard ruby library which we normally forget. 22 | 23 | ## [Idiomatic Ruby](idiomatic_ruby.md) 24 | 25 | You can write Ruby code, but it can sometimes look like Java code. Here you can find some tips to write more naturally and take advantage of idiomatic Ruby. 26 | 27 | ## [Refactorings](refactorings.md) 28 | 29 | Small (and big) improvements you can apply to your code and improve it's readability and maintenance. Change the internal structure of the code without changing it's behaviour. 30 | 31 | ## [Best Practices](best_practices.md) 32 | 33 | If you keep your house cleaned constantly you'll never need to waste a weekend cleaning it. The same applies to your code. Be disciplined and keep your code looking good with those tips. 34 | 35 | ## Contributors 36 | 37 | A big thanks to the following [people](https://github.com/franzejr/best-ruby/graphs/contributors) 38 | 39 | ## Contributing 40 | 41 | 1. [Fork it](https://github.com/franzejr/best-ruby) 42 | 2. Create a branch with your idea: `git checkout -b my-idea` 43 | 3. Check in which category it should be: best practice, idiomatic ruby, refactoring or trick. If you don't know, please open an issue and ask. 44 | 4. Add your idea to the collection of `.md` files in the correct folder (tricks, refactorings, idiomatic_ruby or best_practices) folder 45 | 5. Commit your changes: `git commit -am 'Add my idea'` 46 | 6. Push to the branch: `git push origin my-idea` 47 | 7. Create a new Pull Request and explain your technique in the markdown file 48 | -------------------------------------------------------------------------------- /refactorings/case_with_hashes.md: -------------------------------------------------------------------------------- 1 | ## Refactoring switch case with Hashes 2 | 3 | The author presents a simple refactoring from case statement to hash table, as an ode to Ruby's "little things". 4 | Ruby owes its popularity to an abundance of “little things”–small touches in just the right places that make all of its features come together in delightful ways. One of those little things, for me, is the humble Hash class. 5 | 6 | Hashes are one of the most versatile data structures in Ruby. I’ve written about them before, regarding their interchangability with Proc objects, but there’s so much more they can do. 7 | 8 | I was recently doing a code review and encountered a pattern where user input was being used to derive a class to instantiate. It looked something like this. (Note that this is not the actual code, and is not even the same use-case. I’ve taken some liberties here.) 9 | 10 | ```ruby 11 | case params[:student_level] 12 | when :freshman, :sophomore then 13 | student = Student::Underclassman.new(name, birthdate, 14 | address, phone) 15 | when :junior, :senior then 16 | student = Student::Upperclassman.new(name, birthdate, 17 | address, phone) 18 | when :graduate 19 | student = Student::Graduate.new(name, birthdate, 20 | address, phone) 21 | else 22 | student = Student::Unregistered.new(name, birthdate, 23 | address, phone) 24 | end 25 | ``` 26 | 27 | I have no doubt that many of you reading this will take one look at that code and think of half a dozen ways in which it might be refactored. (In fact, I was a bit reluctant to write this article, for fear that folks might bike-shed over the best way to refactor my example here. I did it anyway. :)) 28 | 29 | Looking at the code, my first impression was that the case statement was merely selecting a different class based on the value of the user input. We could easily refactor it (for a slight improvement in clarity) like this: 30 | 31 | ```ruby 32 | klass = case params[:student_level] 33 | when :freshman, :sophomore then 34 | Student::Underclassman 35 | when :junior, :senior then 36 | Student::Upperclassman 37 | when :graduate 38 | Student::Graduate 39 | else 40 | Student::Unregistered 41 | end 42 | student = klass.new(name, birthdate, address, phone) 43 | ``` 44 | 45 | Right? And when I see a case statement being used simply to select between different values given some input, I find myself itching to rewrite it using a hash. Because, really, what is a hash, except a mapping that selects between different values, given some input? 46 | 47 | This is the pattern I proposed in the code review: 48 | 49 | ```ruby 50 | STUDENT_LEVELS = Hash.new(Student::Unregistered).merge( 51 | freshman: Student::Underclassman, 52 | sophomore: Student::Underclassman, 53 | junior: Student::Upperclassman, 54 | senior: Student::Upperclassman, 55 | graduate: Student::Graduate 56 | ) 57 | 58 | klass = STUDENT_LEVELS[params[:student_level]] 59 | student = klass.new(name, birthdate, address, phone) 60 | ``` 61 | 62 | It takes advantage of Hash.new(default_value) to ensure that Student::Unregistered is always what we get for any unrecognized input, and then Hash#merge adds in the specific mappings. 63 | 64 | The beauty of this, to me, is that the class-selection logic is now separate from the class-instantiation logic. The mapping itself can be declared outside the method, reducing clutter. That leaves us with just the two lines in the method itself: fetching the class to instantiate, and instantiating it. Easy to read, easy to test, and easy to maintain. 65 | 66 | Win, win, and win! 67 | 68 | [From](http://weblog.jamisbuck.org/2015/11/14/little-things-refactoring-with-hashes.html) 69 | -------------------------------------------------------------------------------- /SUMMARY.md: -------------------------------------------------------------------------------- 1 | # Summary 2 | 3 | * [Introduction](README.md) 4 | * [Tricks](tricks.md) 5 | * [Alphanumeric incrementing](tricks/alphanumeric-incrementing.md) 6 | * [Associative arrays](tricks/associative-arrays.md) 7 | * [At exit method](tricks/at-exit-method.md) 8 | * [Autovivification](tricks/autovivification.md) 9 | * [Blocks can take blocks](tricks/blocks-can-take-blocks.md) 10 | * [Bubbling up thread errors](tricks/bubbling-up-thread-errors.md) 11 | * [Case on ranges](tricks/case-on-ranges.md) 12 | * [Count all objects](tricks/count-all-objects.md) 13 | * [Cycle](tricks/cycle.md) 14 | * [Data](tricks/data.md) 15 | * [Easiest database pstore](tricks/easiest-database-pstore.md) 16 | * [Easiest database pstore yaml](tricks/easiest-database-pstore-yaml.md) 17 | * [Enable garbage collector profiler](tricks/enable-garbage-collector-profiler.md) 18 | * [Enable ruby warnings](tricks/enable-ruby-warnings.md) 19 | * [Fast memoization fibonacci](tricks/fast-memoization-fibonacci.md) 20 | * [Fetch data](tricks/fetch-data.md) 21 | * [Get random data](tricks/get-random-data.md) 22 | * [Head tail](tricks/head-tail.md) 23 | * [Inject](tricks/inject.md) 24 | * [Inspecting the source with script lines](tricks/inspecting-the-source-with-script-lines.md) 25 | * [Iterating over specific types](tricks/iterating-over-specific-types.md) 26 | * [Lambda your own syntax](tricks/lambda-your-own-syntax.md) 27 | * [Memoization](tricks/memoization.md) 28 | * [Print formatted with debug](tricks/print-formatted-with-debug.md) 29 | * [Ruby debug flag](tricks/ruby-debug-flag.md) 30 | * [Shortcut variable interpolation](tricks/shortcut-variable-interpolation.md) 31 | * [Single instance running](tricks/single-instance-running.md) 32 | * [Smalltalk conditionals](tricks/smalltalk-conditionals.md) 33 | * [Splat operator](tricks/splat-operator.md) 34 | * [Stab operator](tricks/stab-operator.md) 35 | * [Struct without assignment](tricks/struct-without-assignment.md) 36 | * [Super magic keyword](tricks/super-magic-keyword.md) 37 | * [Super magic keyword2](tricks/super-magic-keyword2.md) 38 | * [Super magic keyword3](tricks/super-magic-keyword3.md) 39 | * [Super magic keyword4](tricks/super-magic-keyword4.md) 40 | * [Super magic keyword5](tricks/super-magic-keyword5.md) 41 | * [Tail call](tricks/tail-call.md) 42 | * [Trigger irb as needed](tricks/trigger-irb-as-needed.md) 43 | * [Unfreeze objects with fiddle](tricks/unfreeze-objects-with-fiddle.md) 44 | * [Unused variable format](tricks/unused-variable-format.md) 45 | * [Variables from a regex](tricks/variables-from-a-regex.md) 46 | * [Zip](tricks/zip.md) 47 | * [Introspecting Block Parameters](tricks/introspecting_block_parameters.md) 48 | * [Idiomatic Ruby](idiomatic_ruby.md) 49 | * [Each vs map](idiomatic_ruby/each_vs_map.md) 50 | * [Conditional assignment](idiomatic_ruby/conditional_assignment.md) 51 | * [Combine operation over collections (enumerables)](idiomatic_ruby/combine_elements_in_collection.md) 52 | * [Array of Strings or Symbols](idiomatic_ruby/array_of_strings_symbols.md) 53 | * [Multiple Assignment](idiomatic_ruby/multiple_assignment.md) 54 | * [Use Symbol to_proc](idiomatic_ruby/use_symbol_to_proc.md) 55 | * [Array Sample (enumerables)](idiomatic_ruby/array_sample.md) 56 | * [Use Fixnum#times](idiomatic_ruby/use_times.md) 57 | * [Implicit Return](idiomatic_ruby/implicit_return.md) 58 | * [Refactorings](refactorings.md) 59 | * [Conditionals when object is nil](refactorings/conditionals_when_object_is_nil.md) 60 | * [Switch case with Hashes](refactorings/case_with_hashes.md) 61 | * [Best Practices](best_practices.md) 62 | * [rescue => Exception e](best_practices/using_exception_e.md) 63 | --------------------------------------------------------------------------------