Giter Site home page Giter Site logo

blog's People

Contributors

genkio avatar

Watchers

 avatar  avatar

Forkers

vldbnc

blog's Issues

Adapter pattern

ajax({
    url:'/getData',
    type:'Post',
    dataType:'json',
    data:{
        id:"123"
    }
})
.done(function(){})

var $ = {
    ajax:function (options){
        return ajax(options);
    }
}

ref

A simple fake ajax function implementation

"use strict"

function fakeAjax(callback) {
    setTimeout(function() {
        callback("ajax data");
    }, 1000);
}

console.log("start");
fakeAjax(processData);
console.log("end");

function processData(data) {
    console.log("ajax returned: " + data);
}

// output:
// start
// end
// ajax returned: ajax data

Stack implementation

"use strict"

var Stack = function() {
    this.items = [];
}

Stack.prototype.push = function(element) {
    this.items.push(element);
}

Stack.prototype.pop = function() {
    return this.items.pop();
}

Stack.prototype.peek = function() {
    return this.items[this.items.length - 1];
}

Stack.prototype.isEmpty = function() {
    return this.items.length === 0;
}

Stack.prototype.size = function() {
    return this.items.length;
}

Stack.prototype.clear = function() {
    this.items = [];
}

Stack.prototype.print = function() {
    console.log(this.items.toString());
}

module.exports = Stack; // http://www.sitepoint.com/understanding-module-exports-exports-node-js/

var assert = require("./assert.js");

// function assert(condition, testCase) {
//  if (!condition) {
//      console.log("Assertion failed on: " + testCase);
//  }
// }

// module.exports = assert; 

function init() {
    var stack = new Stack();
    stack.items = [1, 2, 3];
    return stack;
}

(function(stack) {
    stack.push(4);
    var itemOnTheTop = stack.items[stack.items.length - 1];
    assert(itemOnTheTop === 4, "PUSH should add a new item to the top of the stack");
})(init());

(function(stack) {
    var itemPopped = stack.pop();
    assert(stack.items.length === 2, "POP should remove the top item from the top of the stack");
    assert(itemPopped === 3, "POP should return the removed item");
})(init());

(function(stack) {
    var itemPeeked = stack.peek();
    var itemOnTheTop = stack.items[stack.items.length - 1];
    assert(itemPeeked === itemOnTheTop, "PEEK should return the top item from the stack");
    assert(stack.items.length === 3, "PEEK should not modify the stack");
})(init());

(function(stack) {
    var isStackEmpty = stack.isEmpty();
    assert(isStackEmpty === false, "ISEMPTY should return false if the size of the stack is bigger than 0");    
})(init());

(function(stack) {
    var stackSize = stack.size();
    assert(stackSize === stack.items.length, "SIZE returns how many items the stack contains");
})(init());

(function(stack) {
    stack.clear();
    var stackSize = stack.items.length;
    assert(stackSize === 0, "CLEAR should removes all elements of the stack");  
})(init());

Prototypical inheritance

constructor stealing

function SuperType(name) {
  this.name = name;
}
function SubType() {
  SuperType.call(this, 'Ji Wu'); // the good: [1] the new SubType instance could 'pick up' the name property; [2] you can pass in arguments
  this.age = undefined; 
}

var person = new SubType();
console.log(person.name); // Ji Wu

console.log(person.__proto__ === SuperType.prototype); // false, which means methods in the SuperType's prototype object are invisible to the person instance.
SuperType.prototype.newAwesomeMethod = function() {};
console.log(person.newAwesomeMethod); // undefined

console.log(person.__proto__ === SubType.prototype); // true
console.log(person.__proto__.constructor === SubType.prototype.constructor); // true

Rank of a word

/**
 * Solution for the Rank of a Word coding challenge
 *
 * @author  Ji Wu
 * @version 1.0, 02/02/16
 */

assert(getPosition('bac')  === 2, 'bac ranked at 2 place');
assert(getPosition('aaa')  === 0, 'aaa ranked at 0 place');
assert(getPosition('abba') === 2, 'abba ranked at 2 place');

/**
 * @param  {string}
 * @return {int}
 */
function getPosition(word) {
    var permutations = getPermutations(word);
    for (var i = 0; i < permutations.length; i ++) {
        if (word === permutations[i]) {
            return i;
        }
    }
}

/**
 * @param  {string}
 * @return {array}
 */
function getPermutations(word) {
    var permutations = [];
    var charArray = word.split('').sort();
    for (var i = 0; i < charArray.length; i ++) {
        var restOfTheChar = charArray.map(function(elem) { return elem });
        var initialChar = charArray[i];
        delete restOfTheChar[i];
        restOfTheChar = restOfTheChar.filter(function(elem) { return !!elem } );
        var permutationsForRestOfTheChar = getPermutationsForRestOfTheChar(restOfTheChar);
        for (var j = 0; j < permutationsForRestOfTheChar.length; j ++) {
            var newWord = initialChar + permutationsForRestOfTheChar[j];
            permutations.push(newWord);
        }
    }
    return permutations;
}

/**
 * @param  {array}
 * @return {array}
 */
function getPermutationsForRestOfTheChar(charArray) {
    var permutations = [];
    var newWord = '';
    var charArrayCopy = charArray.map(function(elem) { return elem });
    var pointer = 0;
    permutations.push(charArray.join(''));
    while (pointer < charArray.length - 1) {
        newWord = getNewWordBySwappingElem(charArrayCopy, pointer, pointer + 1);
        permutations.push(newWord);
        pointer++;
    }
    return permutations;
}

/**
 * @param  {array}
 * @param  {int}
 * @param  {int}
 * @return {string}
 */
function getNewWordBySwappingElem(arr, originalPos, newPos) {
    var tempElem = arr[originalPos];
    arr[originalPos] = arr[newPos];
    arr[newPos] = tempElem;
    return arr.join('');
}

/**
 * @param  {boolean}
 * @param  {string}
 */
function assert(condition, testCaseDescription) {
    if (condition) {
        console.log('Test Ok: ' + testCaseDescription);
    } else {
        console.log('Test Failed: ' + testCaseDescription)
    }
}

All about Git

This knowledge article now has its own repo for testing things out more easily

How-to's

How to tag older commit

$ git tag -a myAwesomeTag 9fceb02 -m "message here"
$ git push --tags origin master
$ git checkout -b myAwesomeNewBranch myAwesomeTag

How to revert all changes

$ git checkout master -f
$ git clean -df # to remove any new files created

How to revert the last local commit

$ git reset --soft HEAD^     # use --soft if you want to keep your changes
$ git reset --hard HEAD^     # use --hard if you don't care about keeping the changes you made

How to revert the last public (github) commit

# surround HEAD^ with "" if you run into problem
$ git reset HEAD^ --hard 
$ git push origin master -f

How to use Git rebase to edit a previous commit

# here's the current state
$ git log --graph --oneline
* 1bbb4e0 commit3
* 90767f1 commit2
* b684702 commit1
# the goal is to edit commit2 (not only the commit message, but also the content committed)

# step 1. travel back to commit1
$ git rebase b684702 -i
# step 2. reset head (with the "", the terminal may keep ask you More? on windows)
$ git reset "HEAD^"
# step 3. make your changes
# step 4. commit the changed content with a new commit message
$ git add .
$ git commit -m "new commit!"
# step 5. continue rebase
$ git rebase --continue
# step 6. force push
$ git push origin master --force

# here's the new look, commit2 got updated with a new commit id, and commit3 also got a new commit id
$ git log --graph --oneline
* f56ad2c commit3
* 9b7701e new commit!
* b684702 commit1

For more information, please ref

How to config a different git user to a project

# cd into the project folder
$ git config user.name 'user'
$ git config user.email '[email protected]'

How to git add all except certain file

$ git add .
$ git reset -- file_name_you_would_like_to_skip

How to delete a branch

$ git branch -d the_local_branch
# to delete the remote branch
$ git push origin :the_remote_branch

How to checkout a remote branch

$ git checkout -b remote_branch origin/remote_branch

How to remove commits on github

$ git reset --hard commit_id
$ git push origin master --force

How to amend a previous commit

# make some changes, for example, delete everything...
$ rm -rf *
$ git add -A
$ git commit --amend -m "initial commit"
$ git push origin master --force

How to pretty print commit log

$ git log --pretty=oneline
# or print out the shorter commit id with:
$ git log --graph --oneline

How to fix LF will be replaced by CRLF in git

$ git config --global core.autocrlf true

How to undo git add

$ git reset

How to work with multiple branches with each branch on its own

$ git checkout -b new_branch
$ git reset --hard initial_commit_id
$ git push origin new_branch -f
# now you have a clean new branch on its own

How to only commit the files previously committed

# instead of git add .
$ git commit -am "only commit the files previously committed"

How to push to another repo

$ git remote add new_origin https://another_repo.github.git
$ git push new_origin HEAD:<new_branch> 

How to push commits to a new branch

# once you done with working on the master branch (3 commits for example)
$ git checkout -b new_branch
$ git push origin new_branch
$ git checkout master
$ git reset --hard HEAD~3
$ git push origin master -f

How to rename a branch

$ git checkout old_branch
# rename
$ git branch -m new_branch
# delete remote old branch
$ git push origin :old_branch
# create remote new branch
$ git push origin new_branch

How to merge one repo into another

# merge project_a to project_b
$ cd project_b
$ git remote add project_a project_a_path
$ git fetch project_a
$ git merge project_a/master # or whichever branch you want to merge
$ git remote remove project_a
$ git push origin project_b

How to merge commits with rebase

# third_commit (to be merged)
# second_commit (to be merged)
# initial_commit
$ git log --pretty --oneline
$ git rebase --i HEAD~2
# pick b76d157 second_commit
# s a931ac7 third_commit
# wq to quit
$ git log --pretty --oneline
$ git push origin master -f

How to edit the very first commit

$ git rebase -i --root

How to set vim as the default editor when doing git rebase

$ git config --global core.editor vim

How does bindAggregation work?

oList.bindAggregation("items", {
    path : '/Opportunities',
    template : oTemplate,
    filters : afilters,
    parameters : aParameters
});

Questions:
At what point does the odata request get sent?
Where does the success response handled?

Answer:
image

FizzBuzz

var msg;
for (var i = 1; i <= 100; i++) {
  msg = "";
  if (i % 3 === 0) { msg = "Fizz"; }
  if (i % 5 === 0) { msg += "Buzz"; }
  console.log(msg || i);
}

Awesome macOS

ref

Setup

# Install homebrew
$ /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install.sh)"

# Install docker
$ brew cask install docker
$ open /Applications/Docker.app
$ docker version

# Install nvm
$ curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.35.3/install.sh | bash
$ vim ~/.zshrc
$ source ~/.zshrc
$ nvm
$ nvm install 12
$ node --version
$ npm login

# Install aws-cli
$ unzip awscli-bundle.zip
$ sudo ./awscli-bundle/install -i /usr/local/aws -b /usr/local/bin/aws
$ aws configure

# Generate SSH key
$ ssh-keygen -t rsa -b 4096 -C "[email protected]"
$ vim ~/.ssh/id_rsa.pub

# Install iTerm 2
$ brew cask install iterm2
$ brew install zsh
$ sudo vim /etc/shells
$ chsh -s /usr/local/bin/zsh
$ echo $SEHLL

# Install oh-my-zsh
$ sh -c "$(curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)"
$ vim ~/.zshrc
$ source ~/.zshrc
$ nvm

# Install essential apps
$ brew cask install iina
$ brew cask install sublime-text
$ subl

# Configure git
$ git config --global user.name ''
$ git config --global user.email ''

Essential apps

  • homebrew
  • Magnet
  • TablePlus
  • Dropbox
  • GIPHY Capture
  • Google Chrome
  • InsomniaX
  • iStat Mini
  • IINA
  • Pocket
  • ScreenFlow
  • Sequel Pro
  • Simple Comic
  • Skim
  • [] Skype
  • Sublime Text
  • VLC
  • z brew install z
  • jq brew install jq
  • The Unarchiver
  • LastPass
  • iTerm2
  • zshell
  • VS Code
  • ImageOptim
  • Unsplash Wallpapers

All about Ruby

How to skip ri and rdoc when installing gem

# skip it once
gem install rails --no-ri --no-rdoc
# skip it for good, add this to ~/.gemrc
gem: --no-ri --no-rdoc

What are the recommended .gemrc settings

---
:bulk_threshold: 1000
:benchmark: false
:sources:
- http://ruby.taobao.org
:update_sources: true
:backtrace: false
:verbose: true
gem: --no-ri --no-rdoc

Difference between $(document).ready and $(window).load

$(document).ready(function() {
  // DOM is now loaded
});

The contents of the callback we're providing to the ready method will only be executed once the document and its dependencies have loaded. Note, however, that this does not include images included via img tags. To wait for those as well, we instead want to wait until the window has loaded, like this:

$(window).load(function() {
  // DOM is loaded, img tags are loaded
});

You typically only have to wait for the DOM to finish loading unless your code relies on reading in the natural dimensions of images that appear on the page. For all other code, we can use the DOM ready callback.

There's an even shorter way to write a DOM ready callback. We can forego traversing to the document and binding to its ready event by simply passing in a callback function to the jQuery function.

$(function() {
  // DOM is now loaded
});

Steps involved for JavaScript compiler to execute JavaScript code

// first pass, scope resolution and function scope compiling

var foo = "bar"; // 1. register foo declaration to the global scope

function bar() { // 2. register function bar declaration to the global scope
    var foo = "baz"; // 3. 'compile' function and register foo declaration to the function bar scope
}

function baz(foo) { // 4. register function baz declaration to the global scope
                                        // 5. register local variable / parameter foo to the function baz scope
    var foo = "bam";  // 6. try to register foo which already exist in the current (baz) scope, registeration get ignored
    bam = "yay";
}

// second pass, assignment

var foo = "bar"; // 7. look for foo in the current scope, then do the assignment operation foo = "bar"

function bar() {    
    var foo = "baz"; 
}

function baz(foo) {
    var foo = "bam"; 
    bam = "yay"; 
}

// third pass, execution of function code

bar(); // 8. look for bar in the global scope, found it, get back the function object, then executing it
             // 9. look for foo in the current (bar) scope, then do the assignment operation
baz(5); // 10. look for baz in the global scope, found it, get back the function object, then executing it with 5 and its parameter
                // 11. look for foo in the current (baz) scope, then do the assignment operation (overwrite whatever value the parameter foo passed in)
                // 12. look for bam in the current (baz) scope, bam does not exist
                // go up one level (global scope in this case), look for bam, bam get created in the global scope (since we're not in the strict mode)
                // then do the assignment operation

Ruby beyond the basics

study notes taken from the Ruby Beyond the Basics course

Ruby is an Object-oriented Language

Objects are defined by two things

  1. local state
  2. responds to messages

Take the concept a step further, everything is an object in Ruby, the full definition of the Object

  1. a collection of references to other objects (local state)
  2. that responds to certain messages

Classes

require 'date'
class User
  def initialize(dob)
    days_since_birth = Date.today - Date.parse(dob)
    @age = days_since_birth / 365 # instance variable, the "local state"
  end

  def can_vote? # instance method
    @age >= 18
  end
end

class User # reopen the class
  def self.new_voter
    dob = Date.today - (18 * 365)
    new(dob.to_s) # same as calling User.new
  end
end

voter = User.new_voter
voter.can_vote? # true

Methods

# methods are also objects
str = "string"
m = str.method(:upcase) # <Method: String#upcase>
m.call # sending 'call' message to the m object => "STRING"
class User
  def initialize(name)
    @name = name
  end

  def name=(name) # setter
    @name = name
  end

  # method return true or false
  def can_vote?; end

  # method with unexpected / destructive behavior
  def reset!; end

  # method with default parameter
  # greet(name='bob', age, informal=false) # Ruby will complaint
  def greet(name, informal=false); end

  # named parameters come with Ruby 2+
  def greet_family(name, informal: false, shout: false); end

  # named parameter without default value
  def greet_coworker(name:); end

  # another example with method with named parameters
  def merge(from: list1, to: list2); end

  def odd_or_even(num)
    if num.odd?
      "odd" # no explicit return required
    else
      "even"
    end
  end

  def even_or_odd(num)
    # Rubyist does not use return to return the value but rather use it for cases like this
    return unless num.respond_to?(:odd?)
    if num.odd? then "odd" else "even" end
  end

  def another_method(*args)
    # *args (splat) turns arguments into a single array
    # another_method(a, b, c) -> another_method([a, b, c])
  end
end

bob = User.new
bob.name = "Mary" # calling the setter
bob.greet_family("Bob", shout: true) # calling method with named parameters

Duck typing

class E
  # you never know any given class / object responds to certain method unless at the runtime
  if gets("Type ping to add method> ").match("ping")
    def self.ping
      "pong"
    end
  end

  # example of duck typing style code
  def print_info(obj)
    # good Ruby code does not concern about Classes but rather focus on the methods passed between objects
    # good Ruby OOD should focus on the method flow between objects
    if obj.respond_to?(:name)
      obj.name
    else
      obj.to_s
    end
  end
end

Attributes

# instance variable without setting its value returns nil
class BuggyUser
  def initialize(name)
    @name = name
  end

  def say_my_name
    puts "My name is #{@naem}" # oh no! A type!
  end
end

me = BuggyUser.new("Bob")
me.say_my_name # My name is

class User
  attr_reader :age, :height
  attr_writer :avatar

  # think again before adding attr_accessor
  # cause good Ruby OOD should think about the method flow between objects,
  # not method that can mess with other objects' local states (instance variable)
  attr_accessor :weight

  def name # getter
    @name
  end

  def name=(name) # setter
    @name = name
  end
end

user = User.new
user.name = "Betty"
user.name # Betty

Reuse

# first type of reuse: inheritance
class User
  attr_reader :name

  def initialize(name)
    @name = name
  end
end

class AdminUser < User
  def is_admin?
    true
  end
end

AdminUser.superclass # User
User.superclass # Object
Object.superclass # BasicObject
BasicObject.superclass # nil

# to investigate where the object is from
class EmptyClass
  def ping
    "pong"
  end
end

obj = EmptyClass.new
m = obj.method(:ping)
m.receiver # #<EmptyClass:0x007fe5a94336e0>
m.owner # Object
# the other type of reuse: module
module Employee
  attr_accessor :start_date

  def employment_length
    days = Date.length - start_date.to_date
    "#{days.to_i} days"
  end
end

class User
  include Employee
end

u = User.new
u.start_date = Date.today - 365
u.employment_length # 365 days

# classes are special types of modules, ones can be instantiated with keyword new

Extend

module Employee
  attr_accessor :start_date
end

class User; end

user = User.new
user.extend(Employee)
user.start_date = Date.today

# however you can't find the extended method
User.public_instance_methods.grep(/start_date/) # []
another_user = User.new
another_user.methods.grep(/start_date/) # []

# extended methods live in the singleton class
user.methods.grep(/start_date/) # [:start_date, :start_date=]
user.singleton_class_public_instance_methods.grep(/start_date/) # [:start_date, :start_date=]

Method dispath

illustrated

# method_missing(name, *args, &block)
class AnyP
  def method_missing(name, *args)
    if name.to_s.start_with?('p')
      "You called #{name} with #{args.inspect}"
    else
      super # call the method with the same name and with same parameters in the superclass
    end
  end
end

has_p = AnyP.new
has_p.cactus # undefined method
has_p.pterodactyl # "You called pterodactyl with []"
has_p.people(true, 17, :whatever) # "You called people with [true, 17, :whatever]"

Constants

PI = 3.14
PI = 3.142 # warning
PI # 3.142

module Geometry
  PI = 3.14
end

module Circle
  PI = 3.142
end
Geometry::PI == Circle::PI # false

# Ruby classes are constants !
class ExampleClass; end
Object.constants.grep(/ExampleClass/) # [:ExampleClass]
Object::ExampleClass.new # same as ExampleClass.new

# Remove constants
Object.remove_const(:ExampleClass) # NoMethodError: private method remove_const called
Object.send(:remove_const, :ExampleClass)
Object.constants.grep(/ExampleClass/) # []

# Set constants
Object.const_set(:NewClass, Class.new do
  def ping
    "pong"
  end
end)
NewClass.new.ping # "pong"

Functions

A function is a relation between a set of input values and a set of output values

illustrated

Functional programming concepts

  1. functions are definitions, not list of instructions
  2. immutable definitions, not variables
  3. functions are first class citizens
    illustrated
def first_even(list)
  # non-functional programming
  for i in list
    if i.even?
      break i
    end
  end
end

def first_even(list)
  # recursive version
  return nil if list.empty?
  i = list.shift
  if i.even?
    i
  else
    first_even(list)
  end
end

Map

prices = [100, 75, 90, 80, 50]
# without map
def add_tax(prices)
  prices_with_tax = []
  prices.each do |price|
    prices_with_tax << price + (price * 0.2)
  end
  prices_with_tax
end

# use Proc object to define the action we'd like to carry (high order function)
tax = Proc.new do |price|
  price + (price * 0.2) # nothing happens when the Proc object get defined
end
tax.call(100) # this is when Proc object get executed

# a simple map implementation
def map(list, fn)
  results = []
  list.each do |item|
    results << fn.call(item)
  end
  results
end

map(prices, tax)

# use the built-in map
prices.map(&tax) # prefix the Proc object with & with pass it in to the map function

Blocks

# without Blocks, lots of typing
prices = [100, 75, 90, 80, 50]
tax = Proc.new do |price|
  price + (price * 0.2)
end
prices.map(&tax)

# with Blocks
prices.map do |price|
  price + (price * 0.2)
end

# block_given? method
def called_with_block?
  if block_given?
    puts "you called me with a block"
  end
end
called_with_block? # nil
called_with_block? do
  1 + 2
end # you called me with a block

# yield
def print_and_yield
  puts "before calling yield"
  yield
  puts "after calling yield"
end
print_and_yield do
  puts "I am the block"
end
# before calling yield
# I am the block
# after calling yield

# yield with value passed in arguments
def each_in_list(list)
  for i in 0..(list.length - 1)
    yield list[i]
  end
end
each_in_list([1, 2, 3, 4, 5]) do |x|
  puts x * 2
end
#2 4 6 8 10

# yield with return value
def map_words(input)
  results = []
  input.split.each do |word|
    results << yield(word)
  end
  results
end
map_words("My name is John") do |word|
  word.size
end
# [2, 4, 2, 4]

Proc vs. Blocks

prices = [10, 100, 40, 75, 30]
# Block
# create block with do...end
prices.select do |price|
  price < 50
end # [10, 40, 30]
# create block with {}
prices.select { |price| price < 50 }

# Proc
# create Proc with do...end
cheap = Proc.new do |price|
  price < 50
end
# create Proc with {}
cheap = Proc.new { |price| price < 50 }
# ways to call a Proc
cheap.call(100) # false, recommended
cheap[100] # false
cheap.(100) # false

# Proc with lambda
cheap = lambda { |price| price < 30 }
cheap.call(50) # false

# new lambda syntax with Ruby 1.9+
cheap = -> price { price < 30 }
cheap[10] # false

# lambda with multi-arguments
cheapest = -> price1, price2 { [price1, price2].min }
cheapest.call[10, 20] # 10
# refer lambda over Proc

# write method that takes block
def modify_prices(prices, &block)
  block.inspect
end
prices = [10, 100, 50]
modify_prices(prices) { |p| p * 1.2 }
# #<Proc:0x...> # a Proc object

price.select { |p| p.even? } # more typing
prices.select(&:even?) # prefer
# & first call to_proc method on even? :even?.to_proc
# & also tells Ruby the proc will be passed in as block
prices.map(&:to_f) # [10.0, 100.0, 50.0]

Currying

mult = -> x, y { x * y }
mult[2, 3] # 6
double = mult.curry[2] # <Proc:xxx (lambda)>
double[2] # 4
double[4] # 8

Functional composition

products.sample
# <struct Product price=10, rating=1, color=:green, sales=2251>
# first iteration
class Report
  def initialize(products)
    @products = products
  end

  def run
    money_taken = @products.inject(0) do |total, product|
      (product.price * product.sales) + total
    end

    total_sales = @products.inject(0) do |total, product|
      product.sales + total
    end

    money_taken / total_sales
  end
end

# functional style
sum = -> list { list.inject(&:+) }
sales_value = -> products do
  product_revenue = products.map { |product| product.sales * product.price }
  sum[product_revenue]
end

total_sales = -> products { sum[products.map(&:sales)] }
avg_sale_price = -> products { sales_value[products] / total_sales[products] }
avg_sale_price[PRODUCTS] # => 44

red = -> products { products.select { |p| p.color == :red } }

class FunctionalReport
  def initialize(products, *fns)
    @products = products
    @fns = fns
  end

  def run
    @fns.inject(@products) do |last_result, fn|
      fn[last_result]
    end
  end
end

FunctionalReport.new(PRODUCTS, avg_sale_price).run # 44
FunctionalReport.new(PRODUCTS, red, avg_sale_price).run # 48

Functional thinking

  • advantages of the functional approach
    • add features without changing existing code
    • create each step of the report with very little code
    • no need to support unrelated code from other steps

Metaprogramming

Defining dinosaurs

# some dummy data
TREX_DATA = {
  name: ,
  order: ,
  suborder: ,
  family: ,
  diet: ,
  period: ,
  length: ,
  weight: ,
  first_discovered: ,
  hobbies: []
}

PTERODACTYL_DATA = {
  name: ,
  order: ,
  suborder: ,
  family: ,
  diet: ,
  period: ,
  length: ,
  weight: ,
  first_discovered: ,
  hobbies: []
}

class Dinosaur
  def self.add_attribute(name, value)
    # to add attribute dynamically regardless what's the data source might look like
    define_method(name) do
      value
    end
  end

  def initialize(data)
    data.each do |key, value|
      self.class.add_attribute(key, value)
    end
  end
end

Simple matching

# implementation without metaprogramming
class Diplodocus < Dinosaur
  def match_diet(diet)
    self.diet == diet
  end

  def match_suborder(suborder)
    self.suborder == suborder
  end
end

# implementation with metaprogramming
class Dinosaur
  def self.match_on(attr_name)
    method_name = "match_#{attr_name}"
    define_method(method_name) do |value|
      attr = self.send(attr_name)
      attr == value
    end
  end
end

class Diplodocus < Dinosaur
  match_on :diet
  match_on :suborder
end

d = Diplodocus.new(data)
d.match_diet("herbivore") # true

Awesome Atom

Essential packages

for JavaScript focused web development

  • facebook-atom/atom-ide-ui
  • atom/ide-typescript
  • atomlinter/linter-eslint
  • t9md/vim-mode-plus
  • lloeki/ex-mode
  • akonwi/git-plus
  • richrace/highlight-selected
  • platformio/platformio-ide-terminal
  • emmetio/emmet
  • atom-minimap/minimap
  • atom-minimap/minimap-highlight-selected
  • atom-minimap/minimap-find-and-replace
  • atom-minimap/minimap-git-diff
  • atom-minimap/minimap-cursorline

Keyboard shortcuts

the obvious ones are not included here, and these shortcuts are only applicable in macOS

cmd shift H to open the git plus palette
cmd b browse open files
ctrl shift 9 to toggle git panel

Packages

  • vim-mode
  • terminal-plus
  • relative-numbers
  • minimap-highlight-selected
  • minimap
  • highlight-selected
  • git-plus
  • ex-mode
  • linter
  • jshint
  • emmet
  • todo-show
  • minimap-git-diff
  • git-history
  • advanced-open-file
  • script
  • ruby-block
  • rails-snippets
  • autocomplete-ruby (check out the package README for installation instruction)
  • linter-ruby
  • vim-mode-visual-block
  • linter-pep8
  • autocomplete-python
  • hyperclick
  • linter-scss-lint (first $gem install scss_lint)
  • atom-html-preview

Keyboard shortcuts

  • ctrl (cmd)+alt+i open devtool
  • ctrl (cmd) + p toggle file finder
  • ctrl (cmd) + r go to symbol
  • ctrl (cmd) + \ toggle tree view
  • ctrl (cmd) + k + left / right switch between left and right panel
  • alt + shift + T open terminal
  • alt + shift + X close terminal
  • ctrl (cmd) + alt + o advanced open file
  • ctrl + (shift) + tab shift between tabs
  • z + c fold current row
  • z + o unfold current row
  • ctrl+-+``` toggle terminal-plus
  • ctrl (cmd)+k+L covert to lower case
  • ctrl (cmd)+k+u covert to upper case
  • ctrl+alt+g go to (Python) definition (autocomplete-python package)

How to install Atom in Ubuntu

# tell sudo to preserve the environment with the -E option
$ sudo -E add-apt-repository ppa:webupd8team/atom
$ sudo apt-get update
$ sudo apt-get install atom

Fix SublimeREPL: Node stringToWrite must be a string

Original resource

The error:

readline.js:216
    throw new TypeError('stringToWrite must be a string');
    ^
TypeError: stringToWrite must be a string
    at REPLServer._writeToOutput (readline.js:216:11)
    at REPLServer.Interface.prompt (readline.js:184:10)
    at REPLServer.displayPrompt (repl.js:554:8)
    at new REPLServer (repl.js:470:8)
    at Object.exports.start (repl.js:487:14)
    at /home/vagrant/.config/sublime-text-2/Packages/SublimeREPL/config/NodeJS/repl.js:5:20
    at Object.<anonymous> (/home/vagrant/.config/sublime-text-2/Packages/SublimeREPL/config/NodeJS/repl.js:38:3)
    at Module._compile (module.js:435:26)
    at Object.Module._extensions..js (module.js:442:10)
    at Module.load (module.js:356:32)
***Repl Closed***

The fix:

Update /home/vagrant/.config/sublime-text-2/Packages/SublimeREPL/config/NodeJS/repl.js

var rep = repl.start({
    prompt:    null, //'> ',  
    source:    null, //process.stdin,
    eval:      null, //require('vm').runInThisContext,
    useGlobal: true, //false
    useColors: false
});

To

var rep = repl.start({
    prompt:    '> ', //null, 
    source:    null, //process.stdin,
    eval:      null, //require('vm').runInThisContext,
    useGlobal: true, //false
    useColors: false
});

Effective database usage with Ruby on Rails

study notes taken from the Effective database usage with Ruby on Rails course

Data Modelling

The unexpected nil

# problem: @book.title.truncate(100) -> NoMethodError
# investigate in rails console
pp Book.all.map {|x| [x.id, x.title]}

# fix #1 at display time in the view
@book.title.to_s.truncate(100)

# fix #2 with validation in the model
validates :title, presence: true, if: ->(record) { record.nil? }
# this solution does not prevent a nil record being created
book = Book.new
book.save(validate: false)

# the right way to do it is to fix with a schema change via migration
class AddNotNullToBlurb < ActiveRecord::Migration
  def change
    Book.update_all({title: ''}, {title: nil})
    change_column :books, :title, :text, null: false, default: ''
  end
end

Missing parent

# in the view, `book.author.name` lead to undefined method `name` for nil:NilClass
# fix #1 in the model
class Author < ActiveRecord::Base
  has_many :books, dependent: :destroy
  # or has_many :books, dependent: :delete_all # with better performance cause it will skip callbacks
end

# fix #2, to prevent associated record be deleted in the first place
class Author < ActiveRecord::Base
  has_many :books, dependent: :restrict_with_error
end

# fix #3, to add foreign key constraint
class AddFkToBooks < ActiveRecord::Migration
  def up
    execute <<-SQL
      ALTER TABLE books
      ADD CONSTRAINT fk_books_on_author_id FOREIGN KEY (author_id)
      REFERENCES authors (id)
    SQL
  end

  def down
    execute <<-SQL
      ALTER TABLE books
      DROP CONSTRAINT fk_books_on_author_id
    SQL
  end
end

Duplicate data

# fix via migration
class AddBookTitleUniqueKey < ActiveRecord::Migration
  def change
    # find existing duplicated data
    dups = Book.find_by_sql <<-SQL
      select * from books where title in
        (select title from books group by title having count(title) > 1);
    SQL

    # remove existing duplicated data
    dups = dups.group_by(&:title)
    dups.each do |title, books|
      books.sort_by(&:created_at).drop(1).each(&:destroy)
    end

    # add unique index
    add_index :books, :title, unique: true
  end
end

# then to update the model class to make it more exception handling friendly
class Book < ActiveRecord::Base
  include RetryMethods

  validates :title, presence: true, uniqueness: true
  belongs_to :author

  def save_with_retry_on_unique(*args)
    retry_on_exception(ActiveRecord::RecordNotUnique) do
      save(*args)
    end
  end
end

# models/concerns/retry_methods.rb
module RetryMethods
  def retry_on_exception(ex, n = 1, &block)
    begin
      count = 1
      block.call
    rescue
      if count <= note
        count += 1
        retry
      else
        raise
      end
    end
  end
end

Reactive integrity tests

# lib/integrity_checker.rb
require 'minitest/autorun'
require File.expand_path('../../config/environment', __FILE__)

class IntegerityChecker < MiniTest::Unit::TestCase
  MAX_ERRORS = 50
  def test_books_are_valid
    errors = []
    Book.find_each do |book|
      next if book.valid?

      errors << [book.id, book.errors.full_messages]
      break if errors.size > MAX_ERRORS
    end
    assert_equal [], errors
  end

  def test_book_title_are_not_nil
    assert_equal 0, Book.where(title: nil).count
  end
end

Concurrency

Optimistic locking with ActiveRecord

# step 1. add the lock_version column
class AddLockVersionToBooks < ActiveRecord::Migration
  def change
    add_column :books, :lock_version, :integer, null: false, default: 0
  end
end
# rake db:migrate

# understand better the sql difference after lock_version added
# UPDATE "books" SET "title" = "new title", "lock_version" = 1 WHERE ("books"."id" = 2 AND "books"."lock_version" = 0)

# step 2. update the UI, to add the hidden_field for lock_version
# views/books/_form.html.erb (removed <%= %> for better markdown formatting)
f.hidden_field :lock_version

# step 3. include lock_version as part of the update in the controller
# controllers/books_controller.rb
def book_params
  params.require(:book).permit(:title, :author_id, :lock_version)
end

# step 4. conflict resolution, to deal with ActiveRecord::StaleObjectError exception
# controllers/books_controller.rb
def update
  if @book.update(book_params)
    redirect_to @book, notice: 'Book was successfully updated.'
  else
    render action: 'edit'
  end
rescue ActiveRecord::StaleObjectError
  @conflicting = Book.find(@book.id)
  # update the lock_version, othewise any further update will still be failed
  @book.lock_version = @conflicting.lock_version
  render action: 'edit'
end

# views/books/_form.html.erb (removed <%= %> for better markdown formatting)
if @conflicting
  <p>The book was changed by someone else! Please confirm your changes</p>
end

Counters

# naive solution
def increment
  @book.increment!(:in_stock)
  # @book.update_attributes!(in_stock: @book.in_stock + 1)
  redirect_to :back
end

def decrement
  @book.decrement!(:in_stock)
  # @book.update_attributes!(in_stock: @book.in_stock - 1)
  redirect_to :back
end

# the sql behind
# SELECT "books" .* FROM "books" WHERE "books"."id" = $1 LIMIT 1 [["id", "2"]]
# there's a dangerous gap between select and update!
# UPDATE "books" SET "in_stock" = $1 ...

# solution with counters
def increment
  Book.increment_counter(:in_stock, @book.id)
  redirect_to :back
end

def decrement
  Book.decrement_counter(:in_stock, @book.id)
  redirect_to :back
end

# the sql behind
# inline operation
# UPDATE "books" SET "in_stock" = COALESCE("in_stock", 0) - 1 WHERE "books"."id" = 2

Pressimistic locking

# models/book.rb
def discontinue_with_lock!
  transaction do
    lock!
    discontinue!
  end
end

# the sql behind Pressimistic locking `FOR UPDATE`
# SELECT id, title FROM books WHERE id = 1 FOR UPDATE

A real-world pressimistic strategy solution

# models/book.rb
class Book < ActiveRecord::Base
  has_many :reservations

  class NoStack < StandardError; end

  def reserve_the_naive_version
    transaction do
      if in_stock > 0
        # there is a gap!!! between check and update
        reservations.create!(expires_at: 1.day.from_now)
        Book.decrement_counter(:in_stock, id)
      end
    end
  end

  def reserve
    transaction do
      rows_updated = Book.
        where(['id = ? AND in_stock > 0', id]).
        update_all('in_stock = in_stock - 1')
      if rows_updated == 1
        reservations.create!(expires_at: 1.day.from_now)
      else
        raise NoStack
      end
    end
  rescue NoStack
    if Book.expire_old_reserverations > 0
      retry
    end
  end

  def pickup(reservation_id)
    reservations.find(reservation_id).destroy
  rescue ActiveRecord::RecordNotFound
  end

  def abandon(reservation_id)
    transaction do
      reservations.find(reservation_id).destroy
      Book.increment_counter(:in_stock, id)
    end
  rescue ActiveRecord::RecordNotFound
  end

  def self.expire_old_reserverations
    expired = 0
    to_expire = Reservation.where(['expires_at < ?', Time.zone.now])
    to_expire.each do |reservation|
      begin
        transaction do
          reservation.destroy
          Book.increment_counter(:in_stock, reservation.book_id)
          expired += 1
        end
      rescue ActiveRecord::RecordNotFound
      end
    end
    expired
  end

end

Reporting

Creating a star schema

# create a new table for reporting
class AddSalesTable < ActiveRecord::Migration
  def change
    create_table :sales do |t|
      t.datetime :placed_at
      t.integer :revenue
      t.integer :unit_price
      t.integer :quantity

      t.integer :order_line_item_id
      t.integer :order_id
      t.integer :book_id
      t.integer :author_id
      t.integer :buyer_id
      t.string :state, limit: 2
    end
  end
end

# model class
class Sale < ActiveRecord::Base
  def self.create_from_order!(order)
    return if order.canceled_at

    order.line_items.each do |line_item|
      create!(
        order_line_item_id: line_item.id,
        order_id: order.id,
        book_id: line_item.book_id,
        author_id: line_item.book.author_id,
        buyer_id: order.buyer_id,
        state: order.shipping_address.state,
        placed_at: order.placed_at,
        revenue: line_item.unit_price * line_item.quantity,
        unit_price: line_item.unit_price,
        quantity: line_item.quantity
      )
    end
  end
end

# populate table with a rake task
task populate_sales: environment do
  Order.find_each do |order|
    Sale.create_from_order!(order)
  end
end
# rake bookstore:populate_sales

Factory pattern

var productFactory = (function() {
    var productFactories = {
        "flight": function() {
            return new Flight();
        },
        "hotel": function() {
            return new Hotel();
        }
    };

    return {
        createProduct: function(productType) {
            return productFactories[productType]();
        }
    };
})();

var Hotel = function() {
    console.log("this is a hotel");
};
var Flight = function() {
    console.log("this is a hotel");
};

var User = function() {
    this.shoppingCart = [];
};

User.prototype = {
    constructor: User,
    order: function(productType) {
        this.shoppingCart.push(productFactory.createProduct(productType));
    }
};

var bob = new User();
bob.order("hotel");

console.log(bob.shoppingCart);
// this is a hotel

ref

Awesome Sublime Text

Reboot with Sublime Text 3

Keyboard shorthands

  • cmd (control)+shift+p : command console
  • cmd (control)+d: select the next instance of the currently highlighted text
  • cmd (control)+t: go to file
  • cmd (control)+r: search method
  • cmd (control)+kb: toggle side bar
  • cmd (control)+option+2: split screen into two columns
  • cmd (control)+g: go to line
  • cmd (control)+```: open console
  • cmd (control)+alt+o: quick file creator
  • cmd (control)+a: select all, then cmd (control)+shift+L, enable multi-cursor on every line

Essentials

Install Package Control more details

Recommended packages to install

  • Vintageous
  • Emmet
  • BracketHighlighter
  • Git
  • GitGutter
  • View in Browser (change the default browser from firefox to Chrome)
  • SublimeLinter (make sure jshint is installed first via npm i -g jshint)
  • SublimeLinter-jshint
  • SideBarEnhancement
  • Terminal
  • LESS
  • AngularJS

Recommended user settings

{
    "font_size": 13,
    "highlight_modified_tabs": true,
    "ignored_packages":
    [
        "Vintage"
    ],
    "tab_size": 2,
    "translate_tabs_to_spaces": true
}

Install Package Controller behind proxy

import urllib.request,os; pf = 'Package Control.sublime-package'; ipp = sublime.installed_packages_path(); urllib.request.install_opener( urllib.request.build_opener( urllib.request.ProxyHandler({"http": "http://proxy.corp:8080"})) ); open(os.path.join(ipp, pf), 'wb').write(urllib.request.urlopen( 'http://sublime.wbond.net/' + pf.replace(' ','%20')).read())

Tricks

  • enable search scope by adding for example , *-dbg.js to the Where field when searching
  • enable vim mode by commenting out the last line "ignored_packages": ["Vintage"] in the Preferences.sublime-settings

Q&A

Where packages are stored on Mac OS X?

/Users/youUserName/Library/Application\ Support/Sublime\ Text\ 2/Packages/

How can I run javascript code in the sublime console?

By creating a new build system for node.js

// mac
{
    "cmd": ["/usr/local/bin/node","$file"]
}

// windows
{
    "cmd": ["C:\\Program Files\\nodejs\\node.exe", "$file"],
    "file_regex": "^(...*?):([0-9]*):?([0-9]*)",
    "selector": "source.coffee"
}

How to create subl symlink in El Capitan

sudo ln -s /Applications/Sublime\ Text.app/Contents/SharedSupport/bin/subl /usr/local/bin/subl

How to install sublime 3 on ubuntu via apt-get install

$ sudo add-apt-repository ppa:webupd8team/sublime-text-3
$ sudo apt-get update
$ sudo apt-get install sublime-text-installer

Boost up your CSS productivity instantly with these 3 SCSS basic syntax

Variables $

$primary-color: #00BCD4;

header {
    background-color: $primary-color;
}

Nested Rules

.hero {
    padding: 80px;
    .btn {
        width: 100px;
        height: 40px;
        background-color: $accent-color;
    }
    &:hover {
        background-color: lighten($accent-color, 10%);
        cursor: pointer;
    }
}

@-Rules

/* sections.scss */
header {
    background-color: $primary-color;
    height: 70px;
}
/* main.scss */
@import "sections"

Lastly, build with gulp and gulp-sass

// gulpfile.js

var gulp = require('gulp');
var sass = require('gulp-sass');

gulp.task('sass', function(){
  gulp.src('src/main.scss')
      .pipe(sass())
      .pipe(gulp.dest('dist/'));
});

gulp.task('copy-assets', function(){
  gulp.src('src/*.html')
      .pipe(gulp.dest('dist/'));
});

gulp.task('default', ['sass', 'copy-assets']);

For more information on SCSS

PostgreSQL essentials

study notes taken from the PostgreSQL essentials and the Meet PostgreSQL course

PostgreSQL Essentials

Install and start the server

# install
$ brew update
$ brew search post
$ brew install postgresql

# initdb
$ initdb /usr/local/var/postgres -E utf8
# or initdb to your home directory
$ initdb -D $HOME/pg-data -E utf-8

# start server at the foreground
$ postgres -D /Users/abc/pg-data
# or start server at the background
$ pg_ctl -D /Users/abc/pg-data -l logfile start
# or export PGDATA
$ export PGDATA=/Users/abc/pg-data
$ postgres

Tour of psql

# start server
$ postgres -D /Users/abc/pg-data
# create database
$ createdb tuts
# connect to db
$ psql tuts

# common commands
=# help
=# \h create table

=# create table authors ( name varchar(100) );
=# \d # find everything about the tables (known as relations in postgres)
#         List of relations
# Schema |  Name   | Type  | Owner
# --------+---------+-------+-------
# public | authors | table | abc
# (1 row)
=# \d authors
#            Table "public.authors"
#  Column |          Type          | Modifiers
# --------+------------------------+-----------
#  name   | character varying(100) |
=# insert into authors(name) values('tuts');
# INSERT 0 1
=# select * from authors;
#  name  
# -------
#  tuts
#  lion
#  pavan
# (3 rows)

# to start the editor
=# \e
=# \q # to quit

# alter table to add primary key
=# alter table authors
=# add column author_id serial primary key;

# launch buffer in editor (vim)
=# \e
  create table tutorials (
    tutorial_id serial primary key,
    title text,
    author_id integer
  );
# new table shall be created when editor exists
=# \d
=# \d tutorials

# run the joint query
=# insert into tutorials(title, author_id) values('my first tutorial', 1);
=# select tutorials.title, authors.name from tutorials join authors on tutorials.author_id = authors.author_id;

Creating and manipulating tables

Lifecycle of a table

  • CREATE
  • manage
    • INSERT
    • UPDATE
    • DELETE
    • ALTER
  • DROP
=# drop table authors, tutorials;
# create table with empty definition
=# create table authors();
=# \e
  alter table authors
  add column author_id serial primary key,
  add column name varchar(100);
# insert 3 rows
=# insert into authors(name) values ('net'), ('tuts'), ('web');
=# select * from authors;
# specify constraints
=# alter table authors add column email varchar(100) not null default '[email protected]';
=# update authors set email='[email protected]' where name = 'net';
# delete
=# delete from authors where name='web';
# add more table
=# create table tutorials();
=# \e
  alter table tutorials
  add column tutorial_id serial primary key,
  add column title text,
  add column author_id integer,
  add constraint unique_title unique(title),
  add foreign key(author_id) references authors(author_id);
=# insert into tutorials(title, author_id) values ('my first article', 1);
=# insert into tutorials(title, author_id) values ('my first article', 2);
# ERROR: duplicate key value violates unique constraint "unique_title"

# to examine system tables
=# \dS
# create a new schema
=# create schema temp;
=# create table temp.test();
# set search_path to include the new schema
=# set search_path=public, temp;
=# select * from test;

Querying data - the Select statement

# import data from csv into table
=# copy authors(name, email) from '/Users/abc/authors.csv' delimiter '|' csv header;
=# copy books(title, price_usd, tags, publish_date, author_id) from '/Users/abc/books.csv' delimiter '|' csv header;
=# copy tutorials(title, author_id) from '/Users/abc/tutorials.csv' delimiter '|' csv header;

# select with join
=# SELECT authors.name, books.title FROM authors JOIN books ON authors.author_id=books.author_id ORDER BY author.name;

# select with alias, group by, order by and the built-in count function
# translate as: select the top 3 authors with the most tutorials in desc order
=# SELECT a.name, count(t.tutorial_id) AS count FROM authors a JOIN tutorials t ON a.author_id=t.author_id GROUP BY a.name ORDER BY count DESC LIMIT 3;

# select with distinct
=# SELECT DISTINCT a.author_id, a.name FROM authors a JOIN tutorials t ON a.author_id=t.author_id;

Organizing queries

# translate as: select the author who's book as well as tutorial author
=# SELECT b.author_id, t.name FROM books b JOIN
=# (SELECT DISTINCT a.author_id, a.name
=# FROM authors a JOIN tutorials t ON a.author_id=t.author_id) AS t
=# ON b.author_id=t.author_id;

# use temporary table (which can be defined only once during a session)
=# CREATE TEMPORARY TABLE tutorial_authors AS
=# SELECT DISTINCT a.author_id, a.name AS author_name
=# FROM authors a JOIN tutorials t ON a.author_id=t.author_id;

=# SELECT t.author_id, t.author_name FROM tutorial_authors t
=# JOIN books ON books.author_id=t.author_id;

# use common table expressions (CTE) which only last the duration of the query
=# WITH tutorial_authors AS (
=# SELECT DISTINCT a.author_id, a.name AS author_name
=# FROM authors a JOIN tutorials t ON a.author_id=t.author_id
=# )

=# SELECT t.author_id, t.author_name FROM tutorial_authors t
=# JOIN books ON books.author_id=t.author_id;

# use table functions
=# CREATE FUNCTION tutorial_authors(INT) RETURNS TABLE(author_id INT, author_name TEXT)
=# AS $$
=# SELECT DISTINCT a.author_id, a.name FROM authors a JOIN tutorials t ON a.author_id=t.author_id LIMIT $1
=# $$ LANGUAGE SQL;

=# SELECT * FROM tutorial_authors(5); # take argument 5
=# DROP FUNCTION tutorial_authors(); # to delete table function (the one with no parameter, the one with parameter still function)
=# DROP FUNCTION tutorial_authors(INT); # to delete the one with parameter

# use view (which is available across sessions) which is lighter and cheaper compare with table
=# CREATE VIEW tutorial_authors(author_id, author_name)
=# AS
=# SELECT DISTINCT a.author_id, a.name FROM authors a JOIN tutorials t ON a.author_id=t.author_id;

=# SELECT * FROM tutorial_authors;
=# DROP VIEW tutorial_authors;

The hstore extension

# to turn on the extension
=# CREATE EXTENSION hstore;

# to add the column
=# ALTER TABLE books
=# ADD COLUMN sales hstore;

# to update the data
=# UPDATE book SET sales='total_sales=>12134, peak_sales=>1234, peak_sales_date=>"12/25/2015"' WHERE book_id=678

# to query the data
=# SELECT sales FROM books WHERE book_id=678
=# SELECT sales->'peak_sales' FROM books WHERE book_id=678
=# SELECT DATE(sales->'peak_sales_date') FROM books WHERE book_id=678 # cast
=# SELECT DATE(sales->'peak_sales_date')+365 FROM books WHERE book_id=678 # calculation

Meet PostgreSQL

Work with PostgreSQL in Rails (3)

Rails setup

# step 1. create project via rails new pg-rocks
# step 2. replace the sqlite with 'pg' gem in Gemfile
# step 3. update the config/database.yml
development: &defaults
  adapter: postgresql
  database: pg_rocks_development
  encoding: unicode
  username: abc
  password: ""

test:
  <<: *defaults
  database: app_test
# step 4. bundle install
# step 5. rake db:create:all
# step 6. dive into the table created, psql pg_rocks_development
# step 7. generate the model via rails g Post title:string body:string
# step 8. create some seed data
Post.find_or_create_by_title('Postgres is awesome')
Post.find_or_create_by_title('How Postgres is different from MySQL')
Post.find_or_create_by_title('Tips for MySQL refugees')
Post.find_or_create_by_title('TOP SECRET', {
  :body => 'Postgres rocks'
})
# step 9. rake db:migrate db:seed

Full text search

# Post.rb model
class Post < ActiveRecord::Base
  def self.search(query)
    conditions = <<-EOS
      to_tsvector('english',
        coalesce(title, '') || ' ' || coalesce(body, '')
      ) @@ to_tsquery('english', ?)
    EOS
    # coalesce function to prevent nil
    where(conditions, query)
  end
  # Post.search("difference | same").map(&:title)
end

Intermediate Ruby on Rails

study notes taken from the thoughtbot Intermediate Ruby on Rails course

PART I. Fundamentals

General Workflow

  1. rails new project_name --skip-bundle --skip-test
  2. add dependencies (gems)
  3. bundle install
  4. scaffold user authentication feature
  5. change application root route root to: 'homes#show', via: :get
  6. add home page controller app/controllers/home_controller and the show method
  7. add the home page template app/views/homes/show.html.erb
  8. allow user to be able to sign in and sign out
  9. generate migration to add username to users, follow by rake db:migrate
  10. add the logic in homes controller to redirect logged in user to dashboard page
  11. create dashboards controller and define the show method
  12. create the app/views/dashboards/show.html.erb template
  13. define a rails form in dashboard/show.html.erb for user to submit shout
  14. render @shouts array collection in the dashboard/show.html.erb template
  15. create the views/shouts/_shout.html.erb partial
  16. generate the shouts model
  17. add the shouts route resources :shouts, only: [:create]
  18. create the shouts controller and define the create method
  19. add some styles to the shout partial
  20. add the links to each shout and user in the _shout partial
  21. add the routes to support showing single shout
  22. define show method in the shouts controller
  23. create the views/shouts/shout.html.erb template to show single shout
  24. do the same to single user as to single shout
  25. add default_scope to shout model, to display shouts in a particular order
  26. add validations to shout model
  27. update create method in the shouts controller to notify user when create failed

Tips and Tricks

A simple user authentication solution

gem 'monban', '0.0.6'

# rails g monban:scaffold

Group gems into groups

group :assets do
  gem 'sass-rails', '~> 3.2.3'
  gem 'coffee-rails', '~> 3.2.1'
end

# so that this is possible: bundle --without assets

To specify the HTTP method when defining the root route

root to: 'homes#show', via: :get

# otherwise the root route can access request coming from all HTTP methods

Simple logic to allow user to be able to sign in and sign out

<% if sign_in? %>
  <%= current_user.username %>
  <%= link_to 'Sign out', session_path, method: :delete %>
<% else %>
  <%= link_to 'Sign in', new_session_path %>
  <%= link_to 'Sign up', new_user_path %>
<% end %>

Migration file naming convention

# rails can pick up the keywords `add` and `users` automatically when following the migration naming convention
# `:index` helps to generate `add_index :users, :username`
rails g migration AddUsernameToUsers username:index

# the generated migration
def change
  add_column :users, :usrname, :string
  add_index :users, :usrname
end

Extract initialization code into initializers

example only applies to Rails 3

# config/initializers/forbidden_attributes_initializer.rb
ActiveRecord::Base.send(:include, ActiveModel::ForbiddenAttributesProtection)
# which will be included to all of our ActiveRecord models

Simple logic to redirect logged in user

# homes_controller.rb
before_filter :check_logged_in_user

private

def check_logged_in_user
  if signed_in?
    redirect_to dashboard_path
  end
end

Difference between resource and resources route

# routes.rb
# resouce for singleton resource
resource :dashboard, only: [:show]

# resources will give you the url /dashboard/:id
resources :dashboard, only: [:show]

# one more thing, it's important to constrain routes with only

Generate model with associations

rails g model Shout body user:belongs_to

# here's the migration file generated
def change
  create_table :shouts do |t|
    t.string :body
    t.belongs_to :user
    t.timestamps
  end
  add_index :shouts, :user_id
end

# here's the shout.rb model class generated
class Shout < ActiveRecord::Base
  belongs_to :user
end

# BUT the other half of the association will need to be added manually
class User < ActiveRecord::Base
  has_many :shouts
end

Difference between .build and .new

# shouts_controller.rb
def create
  shout = current_user.shouts.build(shout_params)
  shout.save
  redirect_to dashboard_path
end

private
def shout_params
  params.require(:shout).permit(:body)
end

# new is for a new instance of a specific model: Shout.new
# build is for creating a new instance within an ActiveRecord association: current_user.shouts.build

What render collection is actually doing

<%= render @shouts %>

# is essentially:
<% @shouts.each do |shout| %>
  <%= render shout %>
<% end %>

Use div_for get the css class for free

# views/shouts/_shout.html.erb
# div_for will add a class named shout automatically
<%= div_for shout do %>
  <%= shout.body %>
<% end %>

Where to put application-wide style definitions

# to create a stylesheet the same name as the application other than put style definitions in application.css
# app/assets/stylesheets/shouter.scss
.shout {
  padding: 10px;
  border-top: 1px solid #EEE;
}

Differences between find, find_by and where

# shouts_controller.rb
def show
  @shout = Shout.find(params[:id])
end

# the find method is usually used to retrieve a row by id
# find_by is used as a helper when you're searching for information within a column
# Model.find_by_name("Bob") is same as Model.find_by(name: 'Bob') in Rails 4, or Model.where(name: 'Bob').first
# find_by is essentially .where
def find_by
  where(*args).take
end

# SQL speaks for itself
# User.find_by_email('[email protected]')
# SELECT  "users".* FROM "users" WHERE "users"."email" = ? LIMIT 1  [["email", "[email protected]"]]
# => nil

# User.find_by(email: '[email protected]')
# SELECT  "users".* FROM "users" WHERE "users"."email" = ? LIMIT 1  [["email", "[email protected]"]]
# => nil

# User.where(email: '[email protected]')
# SELECT "users".* FROM "users" WHERE "users"."email" = ?  [["email", "[email protected]"]]
# => []

Use default_scope for sorting

class Shout < ActiveRecord::Base
  belongs_to :user
  default_scope { order("created_at DESC") }
end

The simple creation pattern

# shouts_controller.rb
def create
  shout = current_user.shouts.build(shout_parameters)
  if shout.save
    redirect_to dashboard_path
  else
    flash.alert = "Could not shout."
    redirect_to dashboard_path
  end
end

# views/layouts/application.html.erb
<% if alert %>
  <p><%= alert %></p>
<% end %>

jQuery basics

  • To get started.
$(document).ready(function() {
  // DOM is now loaded
});
$(function() { 
  // short-hand for DOM is now loaded
});
$(window).load(function() {
  // DOM is loaded, img tags are loaded
});
  • CSS selectors and methods. more can be found here
var $content = $("#content");
$content.css("font-size", "18px").css("color", "#b00b00");
$content.css({
  "font-size": "18px",
  color: "#b00b00"
});
$content.css({
  fontSize: "18px",
  color: "#b00b00"
});

// more examples on selectors
// http://j1wu.github.io/frontend-playground/sandbox/jquery-selectors.html

// Locate all of the list items within the article element using the descendant selector.
$("article li");
// Get the third list item from the article element.
$("article li").eq(2);
// Select the table element. From there, find the table rows that are odd-numbered.
$("table").find("tr").filter(":odd");
// or
$("table").find("tr:odd");
// Find the list item with text ac ante, then find the parent list item.
$("article li li").filter(":contains('ac ante')").parents("li");
// Find the same list item with text ac ante, then find the next element.
$("article li li").filter(":contains('ac ante')").next();
// Get all of the table cells within the table, then obtain the last one in the collection.
$("table td").last();
// or
$("table td").eq(-1);
// Get all of the table cells, then revise your collection to not include cells with a class of "protected".
$("td").not(".protected");
// or
$("td:not('.protected')");
// Find all of the anchor elements that have an href that begins with #.
$("a[href^=#]");
// Find all elements that have a class name that contains "block".
$("[class*=block]");
  • Events.
$(function() {
  var $p = $("p");
  var output = "Your favorite fruit is ";

  $("a").click(function(e) {
    e.preventDefault();
    var $e = $(this);

    $p.text(output + $e.text());
  });

  $("form").submit(function(e) {
    e.preventDefault();
    var $input = $(this).find("input[type='text']");

    $p.text(output + $input.val());
  });
});
  • DOM traversal. more can be found here
var $p = $("p");

$p.parent().css("color", "blue");
$p.parent(".highlight").css("color", "blue");

$("#javascript").closest("ul").addClass("categories");
$("#javascript").parents("ul").addClass("categories");

$("ul#navigation").find("li")
$("#navigation").children()

// Find all list items after the CSS list item and hide them
var $css = $("#css").closest("li");
$css.nextAll().hide();
// Find all list items before the CSS list item and hide them
$css.prevAll().hide();
// Find all sibling lis and show them
$css.siblings().show();

baseConverter with stack

"use strict"

var Stack = require("./Stack");
var assert = require("./assert.js");

assert(baseConverter(100345, 2) === "11000011111111001", "baseConverter should convert decimal number to binary");
assert(baseConverter(100345, 8) === "303771", "baseConverter should convert decimal number to octagonal");
assert(baseConverter(100345, 16) === "187F9", "baseConverter should convert decimal number to hexadecimal");

function baseConverter(number, base) {
    var stack = new Stack();
    var remainder;
    var convertedNumber = "";
    var hexadecimalString = "0123456789ABCDEF";

    while (number > 0) {
        remainder = Math.floor(number % base);
        stack.push(remainder);
        number = Math.floor(number / base);
    }

    while (!stack.isEmpty()) {
        convertedNumber += hexadecimalString[stack.pop()];
    }
    return convertedNumber;
}

Fix nvm command not found

Install nvm with curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.29.0/install.sh | bash

Check to see if .nvm exists with ls -a | grep .nvm

If .nvm does not yet exist, try clone it from the github git clone http://github.com/creationix/nvm.git .nvm

Then add this line to the end of ~/.bash_profile (~/.profile) to fix nvm command not found issue.
[[ -s $HOME/.nvm/nvm.sh ]] && . $HOME/.nvm/nvm.sh # This loads NVM

Continue setup at #7

Observer pattern

function Subject() {
    this.observers = [];
}
Subject.prototype = {
    constructor: Subject,
    subscribe: function (fn) {
        this.observers.push(fn);
        return this;
    },
    unsubscribe: function (fn) {
        this.observers = this.observers.filter(function (item) {
            if (item !== fn) {
                return item;
            }
        });
        return this;
    },
    fire: function (data, context) {
        this.observers.forEach(function (item) {
            item.call(context, data);
        });
        return this;
    }
};

// test
function SideView() { }
SideView.prototype.render = function (data) {
    console.log("Side data:" + data);
}

function MainView() { }
MainView.prototype.render = function (data) {
    console.log("MainView data:" + data);
}

var subject = new Subject();
var sideView = new SideView();
var mainView = new MainView();

subject.subscribe(sideView.render)
subject.subscribe(mainView.render);
subject.fire("test");

ref

Queue implementation

function Queue() {
    var items = [];

    this.enqueue = function(element) {
        items.push(element);
    };

    this.dequeue = function(element) {
        return items.shift();
    };

    this.front = function() {
        return items[0];
    };

    this.isEmpty = function() {
        return items.length === 0;
    };

    this.clear = function() {
        items = [];
    };

    this.size = function() {
        return items.length;
    };

    this.print = function() {
        console.log(items.toString());
    };
}

Singleton pattern

var dateTimeHelper = (function() {
    function init() {
        return {
            now: function() {
                return new Date();
            }
        };
    }
    var instance = null;
    return {
        getInstance: function() {
            if (!instance) {
                instance = init();
            }
            return instance;
        }
    };
})();

console.log(dateTimeHelper.getInstance().now());
// Thu Jan 28 2016 22:33:42 GMT+0800 (CST)

ref

Priority queue implementation

function PriorityQueue() {
    var items = [];

    function QueueElement(element, priority) {
        this.element = element;
        this.priority = priority;
    }

    this.enqueue = function(element, priority) {
        var queueElement = new QueueElement(element, priority);

        if (this.isEmpty()) {
            items.push(queueElement);
        } else {
            var added = false;
            for (var i = 0; i < items.length; i ++) {
                if (queueElement.priority < items[i].priority) {
                    items.splice(i, 0, queueElement);
                    added = true;
                    break;
                }
            }
            if (!added) {
                items.push(queueElement);
            }
        }
    };

    this.dequeue = function(element) {
        return items.shift();
    };

    this.front = function() {
        return items[0];
    };

    this.isEmpty = function() {
        return items.length === 0;
    };

    this.clear = function() {
        items = [];
    };

    this.size = function() {
        return items.length;
    };

    this.print = function() {
        for (var i = 0; i < items.length; i ++) {
            console.log(items[i].element + ': ' + items[i].priority);
        }
    };
}

var priorityQueue = new PriorityQueue();
priorityQueue.enqueue("John", 2);
priorityQueue.enqueue("Jack", 1);
priorityQueue.enqueue("Camila", 1);
priorityQueue.print();

Pass by ref vs. value in Ruby via examples

class Person
    attr_accessor :name
end

def some_method(person)
  # person = 'hi'      # leads to output Bob, rule #1
  person.name = 'John' # leads to output John, rule #2
end

bob = Person.new
bob.name = 'Bob'

some_method(bob)
puts bob.name

# Rules:
# #2. If you invoke a method (person.name is essentially invoking 
  # the setter method person.name=()) that mutates the caller, 
  # then it will modify the original object. (pass by reference)
# #1. If you reassign the object to something else, it will not. (pass by value)

# Another example with Array

def yet_another_method(myarr)
  myarr = [3, 4]
  myarr += [3, 4] # reassignment, pass by value, leads to output [1, 2]
  # myarr << [3, 4] # pass by reference, leads to output [1, 2, [3, 4]]
end

arr = [1, 2] # reassignment, pass by value, leads to output [1, 2]
yet_another_method(arr)

puts arr.inspect

Awesome Vim

Keyboard shorthands

  • y+i+w yank inner word
  • y+i+"+``` yank inner " symbol (or any other symbol)
  • v+i+w visually select inner word
  • /+\+c+searchString escape sequence to do case insensitive search
  • shift+v+n+j select next (down) n lines
  • shift+v+n+k select previous (up) n lines
  • :+++n go to the nth line (down)
  • :+-+n go to the nth line (up)
  • % go to the matching braces, or parenthesis
  • ctrl+w+s to split current file into two windows horizontally
  • ctrl+w+v to split current file into two windows vertically
  • d+0 delete from current backward to beginning of line
  • d+w delete current to end of current word
  • w jump to the beginning of next word
  • b jump to the beginning of the previous word
  • e jump to the end of the word
  • shift+I+#+esc comment out the current (use ctrl+v+up or down to select multi-lines)
  • %s/\<foo\>/bar/gc change only whole words exactly matching 'foo' to 'bar' and ask for confirmation.
  • > indent multiple-lines.

Work with gVim on Windows

How to install pathogen?

  1. put pathogen.vim to C:\Program Files (x86)\Vim\vimfiles\autoload
  2. create the bundle folder at C:\Program Files (x86)\Vim\vimfiles\bundle
  3. extract plugins into the bundle folder, for example C:\Program Files (x86)\Vim\vimfiles\bundle\nerdtree
  4. edit _vimrc file at C:\Program Files (x86)\Vim\_vimrc, to add these 4 lines
call pathogen#infect()
call pathogen#helptags()
" Enable filetype plugins
filetype plugin on

How to install plugin as a pathogen bundle?

  1. cd into c:\Program Files (x86)\Vim\vimfiles\bundle
  2. clone the plugin, for example git clone https://github.com/scrooloose/syntastic.git

How to set the default color scheme, font family and size?

colorscheme desert
set guifont=Lucida\ Sans\ Typewriter:h14

How to set runtimepath?

set runtimepath+=$VIM/vimfiles/bundle/jshint2.vim

How to lint my JavaScript code?

  1. install syntastic as a pathogen bundle
  2. edit _vimrc to add the recommended settings
set statusline+=%#warningmsg#
set statusline+=%{SyntasticStatuslineFlag()}
set statusline+=%*

let g:syntastic_always_populate_loc_list = 1
let g:syntastic_auto_loc_list = 1
let g:syntastic_check_on_open = 1
let g:syntastic_check_on_wq = 0

How to install ctags?

  1. install choco through batch method (there's couple of other ways to install choco, but this batch method is the only one worked for me.)
  2. choco install ctags

All about Linux

How to do sudo gem install...behind a proxy

# step 1. set the environment variable in the ~/.bashrc file
export http_proxy=http://username:[email protected]:80/
# step 2. run sudo visudo and add the env_keep
Defaults        env_reset
Defaults        env_keep += "http_proxy https_proxy ftp_proxy"
# step 3. ctrl + x to exit then Y to save the change
# step 4. verify
$ sudo env | grep http_proxy

ref

How to smooth up your Ubuntu

$ sudo apt-get update
$ sudo apt-get install unity-tweak-tool
$ unity-tweak-tool &
# Click on general and turn desktop magnification to off, set texture quality to fast, set window animations to off.
# Then click on overview and then click on launcher. Turn autohide to off, set Urgent animation and launch animation to No animation, set icon backgrounds to no coloring.
# Click on the search tab and set background blur to off.

$ sudo apt-get install compizconfig-settings-manager
$ ccsm &
# In the effects category, untick all of the boxes.
# In the accessibility tab, untick all of the boxes.

ref

Python essentials

study notes extracted from the Complete Python Bootcamp course

Python Object and Data Structure Basics

Numbers

# division
# ways to get 1.5 out of 3 / 2
3.0 / 2
float(3) / 2
from __future__ import division
3 / 2

#100's square root
100 ** 0.5
#10's square
10 ** 2

Strings

from __future__ import print_function
print('Hello World')

# indexing
str = 'Hello World'
str[1:]   # 'ello World'
str[:3]   # 'Hel'
str[:]    # 'Hello World'
str[-1]   # 'd'
str[:-1]  # 'Hello Worl'
str[::1]  # 'Hello World'
str[::2]  # 'HloWrd'
str[::-1] # 'dlroW olleH'

# string is immutable
str[0] = 'H' # 'str' object does not support item assignment
str = str + ' concat me!' # 'Hello World concat me!'
letter = 'z'
letter * 3 # 'zzz'

# methods
str = 'Hello'
str.upper() # 'HELLO'
str.lower() # 'hello'
str.split() # ['hello']

String formatting

str = 'String'
print 'Place my variable here: %s' %(str)
print '%1.2f' %(13.3432)  # 13.34
print '%10.2f' %(13.3432) #      13.34
print 'Place my variable here: %r' %(123) # %r with repr
print 'First: %s, Second: %s' %('first', 'second')

print 'First: {second}, Second: {first}'.format(first='second', second='first')

from __future__ import print_function
print('One: {x}'.format(x='one'))

Lists

my_list = [1,2,3]
my_list = ['string',23,1.2]
len(my_list) # 3

# indexing
my_list = ['one','two','three',4,5]
my_list[0]  # 'one'
my_list[1:] # ['two','three',4,5]
my_list[:3] # ['one','two','three']
my_list + ['new item'] # ['one','two','three',4,5,'new item']

# methods
lst = [1,2,3]
lst.append('append me!')
lst.pop() # 'append me!' lst.pop(-1) by default
lst # [1,2,3]
lst.pop(0) # 1
lst.reverse()
lst # [3,2]
lst.sort()
lst # [2,3]
lst.append([4,5])
lst[2][0] # 4

# list comprehension
lst = [[1, 2], [3, 4], [5, 6]]
[items[0] for items in lst] # [1,3,5]

Dictionaries

my_dict = {'key1':'value1','key2':123,'key3':{'sub':'value3'}}
my_dict['key1'] # 'value1'
my_dict['key2'] += 100
my_dict['key2'] # 223
my_dict['animal'] = 'dog'

my_dict.keys() # ['key3', 'key2', 'key1']
my_dict.values() # [{'sub': 'value3'}, 123, 'value1']
my_dict.items()
# [('key3', {'sub': 'value3'}), ('key2', 123), ('key1', 'value1')]

Tuples

tup = (1,2,'str')
tup[-1] # 'str'
tup.index('str') # 2
tup.count('str') # 1
tup[2] = 3 # 'tuple' object does not support item assignment

Files

f = open('test.txt')
f.read() # 'This is a line\n'
f.read() # ''
f.seek(0) # set cursor back to 0
f.readlines() # ['This is a line\n']

for line in open('new.txt'):
  print line

Set

my_set = set()
my_set.add(1)
my_set # {1}
my_set.add(1)
my_set # {1}
lst = [1,2,3,3,3]
set(lst) # {1,2,3}

Booleans

a = True
1 > 2 # False
b = None

Python Comparison Operators

Chained comparison operators

1 < 2 < 3 # True
1 < 2 and 2 < 3 # True
1 < 3 > 2 # True
1 == 2 or 2 < 3 # True

Python Statements

if, elif, else Statement

if x:
  print 'x was True'
else:
  print 'x was False'

loc = 'Bank'
if loc == 'Auto Shop':
  print 'Welcome to the Auto Shop'
elif loc == 'Bank':
  print 'Welcome to the Bank'
else:
  print 'Where are you?'

for Loops

# a for loop acts as an iterator in Python
lst = [1,2,3,4,5]
for elem in lst:
  if elem % 2 == 0:
    print elem

new_lst = [1,2]
for elem in lst:
  if elem not in new_lst:
    new_lst.append(elem)

lst = [(2,4),(6,8),(10,12)]
for (tup1,tup2) in lst: # unpack tuple
  print tup1

my_dict = {'k1':1, 'k2':2, 'k3':3}
for item in my_dict:
  print item # k3 k2 k1
for k,v in my_dict.iteritems():
  print k # k3 k2 k1
for k,v in my_dict.items(): # Python 3
  print k # k3 k2 k1

while Loops

x = 0
while x < 10:
  print 'x is currently: ', x
  x += 1
  if x == 3:
    print 'x equals 3!'
    # break
  else:
    print 'continuing...'
    continue

range()

range(1,10,2) # [1, 3, 5, 7, 9]
range(10) # [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
type(range(10)) # list

# range() and xrange(), Python 2 vs. Python 3
# generators: a generator allows the generation of 'generated' objects that are provided at that instance but does not store every instance generated into memory
# Python 2 has a built-in range generator called xrange(). It is recommended to use xrange() for for loops in Python 2. range() outputs a list, xrange() will generate elements but not save them in memory
# Python 3, range() is a generator and no need to worry about using xrange()

type(xrange(10)) # xrange
list(xrange(10)) # [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

List comprehensions

[x for x in 'word'] # ['w', 'o', 'r', 'd']
[x**2 for x in range(11)] # [0, 1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
[x for x in range(11) if x % 2 == 0] # [0, 2, 4, 6, 8, 10]
celsius = [0,10,20.1,34.5]
fahrenheit = [(temp * (9/5.0) + 32) for temp in celsius]
# nested comprehension
[x**2 for x in [x**2 for x in range(3)]] # [0, 1, 16]

Methods and Functions

Methods

lst = [1,2,3,4,5]
lst.append(6)
help(lst.append)

Functions

def name_of_function():
  pass

name_of_function()

def my_addition_func(num1,num2):
  """
  Here is my docstring!
  """
  return num1 + num2

x = my_addition_func(1,2)

def is_prime(num):
  """
  INPUT: A number
  OUTPUT: A print statement whether or not the number is prime
  """
  output_str = ''
  for n in range(2,num):
    if num % n == 0:
      output_str = 'Not Prime'
      break
    else:
      output_str = 'The number is prime'
  print output_str

is_prime(13)

# *args
def foo(*args):
  print args
foo(1,2,3,4) # (1,2,3,4)

# **kwargs
def bar(**kwargs):
  print kwargs
bar(name='one', age=3) # {'age': 3, 'name': 'one'}

Lambda expressions

def square(num):
  return num**2

square = lambda num: num**2
even lambda num: num%2 == 0
first_elem = lambda s: s[0]
rev = lambda s:s[::-1]
lambda x,y: x+y

Nested statements and scope

# LEGB - Local -> Enclosing function locals -> Global (module) -> Built-in (Python)

# Enclosing function locals
name = 'John'
def greet():
  name = 'Doe'
  def hello():
    print 'Hello ' + name
  hello()
greet() # Hello Doe

x = 50
def func():
  global x
  print 'This function is now using the global x!'
  x = 2
print 'x before invoking func() is ', x
func()
print 'x after invoking func() is ', x

Object Oriented Programming

Classes

# create a class that inherit from object 
class Dog(object):
  # class object attribute
  species = 'mammal'

  # special method to initialize the object
  def __init__(self,breed,name):
    self.breed = breed
    self.name = name

# instantiation
sam = Dog(breed='Lab',name='Sammy')
type(sam) # <class '__main__.Dog'>
sam.breed # Lab
Dog.species # mammal
sam.species # mammal

Methods

class Circle(object):
  # class object attributes
  pi = 3.14

  def __init__(self,radius=1):
    self.radius = radius

  def area(self):
    return self.radius**2 * Circle.pi

  def set_radius(self,new_radius):
    """
    This method takes in a radius and resets the current radius of the circle
    """
    self.radius = new_radius

  def get_radius(self):
    return self.radius

c = Circle(radius=100)
c.pi # 3.14
c.area() # 31400.0
c.set_radius(20)
c.get_radius() # 20

Inheritance

class Animal(object):
  def __init__(self):
    print "Animal created"

  def whoAmI(self):
    print "Animal"

  def eat(self):
    print "Eating"

class Dog(Animal):
  def __init__(self):
    Animal.__init__(self)
    print "Dog created"

  def whoAmI(self):
    print "Dog"

  def bark(self):
    print "woof!"

sam = Dog()
# Animal created
# Dog created
sam.eat() # Eating
sam.whoAmI() # Dog

Special methods

class Book(object):
  def __init__(self,title,author,pages):
    print "A book has been created!"
    self.title = title
    self.author = author
    self.pages = pages

  def __str__(self):
    return "Title: %s, Author: %s, Pages: %s" %(self.title, self.author, self.pages)

  def __len__(self):
    return self.pages

  def __del__(self):
    print "A book is gone!"


b = Book('Python','Jose',100)
print b # Title: Python, Author: Jose, Pages: 100
print len(b) # 100
del b

Errors and Exceptions handling

try, except, finally

try:
  2 + 's'
except TypeError:
  print 'There was a type error!'
finally:
  print 'Finally is printed'

try:
  f = open('testfile', 'w')
  f.write('test write this')
except:
  print 'Error in writing to the file!'
else:
  print 'File write was a success'
# File write was a success # cause f.write will create a file for you if it does not exist

try:
  f = open('testfile', 'r')
  f.write('test write this')
except: # except IOError:
  print 'Error in writing to the file!'
else:
  print 'File write was a success'
# Error in writing to the file!

# finally will run regardless there's a exception or not
try:
  f = open('testfile', 'r')
  f.write('test write this')
except: # except IOError:
  print 'Error in writing to the file!'
finally:
  print 'Always execute'

# Error in writing to the file!
# Always execute

def ask_int():
  while True:
    try:
      val = int(raw_input('Please enter an integer: ')) 
    except:
      print 'Looks like you did not enter an integer'
      continue
    else:
      print 'Correct, that is an integer!'
      break

ask_int()

Modules and Packages

Modules, Packages, and Imports

import math
math.sqrt(4) # 2.0

from math import sqrt
sqrt(4)
# install external module via anconda
$ conda install module_name
$ pip install module_nam  e

Built-in Functions

map

def fahrenheit(T):
  return (9.0/5)*T + 32

fahrenheit(0) # 32.0
temp = [0,22.5,40,100]
map(fahrenheit,temp)
map(lambda T: (9.0/5)*T+32, temp)

a = [1,2,3]
b = [4,5,6]
c = [7,8,9]
map(lambda x,y,z: x+y+z, a,b,c) # 12,15,18

map(lambda num: num*-1,a) # -1,-2,-3

reduce

lst = [47,11,42,13]
reduce(lambda x,y: x+y,lst) # 113

lst = [34,23,24,24,100,2333,2,11]
max(lst) # 2333
def max_find(a,b):
  if a > b:
    return a
  else:
    return b
max_find = lambda a,b: a if(a>b) else b
reduce(max_find, lst) # 2333

filter

def even_check(num):
  if num % 2 == 0:
    return True
  else:
    return False

even_check(34) # True
lst = range(10)
filter(even_check, lst) # [0,2,4,6,8]
filter(lambda num: num%2==0, lst)

zip

x = [1,2,3]
y = [4,5,6]
zip(x,y) # [(1,4),(2,5),(3,6)]

a = [1,2,3,4,5]
b = [2,2,10,1,1]
for pair in zip(a,b):
  print max(pair) # 2, 2, 10, 4, 5
map(lambda pair: max(pair),zip(a,b))

x = [1,2,3]
y = [4,5,6,7,8]
zip(x,y) # [(1,4),(2,5),(3,6)]

d1 = {'a':1,'b':2}
d2 = {'c':4,'d':5}
zip(d1,d2) # [('a','c'),('b','d')]
zip(d2,d1.itervalues()) # [('c',1),('d',2)]

def switchcharoo(d1,d2):
  dout = {}
  for d1key,d2val in zip(d1,d2.itervalues()):
    dout[d1key] = d2val
  return dout

switchcharoo(d1,d2) # {'a':4,'b':5}

# to implement zip
def zip(*iterables):
  # zip('ABCD', 'xy') -> Ax By
  sentinel = object()
  iterators = [iter(it) for it in iterables]
  while iterators:
    result = []
    for it in iterators:
      elem = next(it, sentinel)
      if elem is sentinel:
        return
      result.append(elem)
    yield tuple(result)

enumerate()

lst = ['a','b','c']
count = 0
for item in lst:
  print count
  print item
  count += 1

for count,item in enumerate(lst):
  print count
  print item

for i,item in enumerate(lst):
  if i >= 2:
    break
  else:
    print item

# to implement the enumerate
def enumerate(sequence, start=0):
  n = start
  for elem in sequence:
    yield n, elem
    n += 1

all() and any()

lst = [True,True,False,True]
all(lst) # False
any(lst) # True

# to implement all()
def all(iterable):
  for elem in iterable:
    if not elem:
      return False
  return True

Decorators

Warm up

# Decorators can be thought of as functions which modify the functionality of another function
def func():
  return 1

str = 'This is a global variable'
def func():
  # to print out all the local variables within the func scope
  print locals()

print locals().keys()
print globals().keys()
print globals()['str'] # 'This is a global variable'

func() # {}

def hello(name='Joe'):
  return 'Hello Joe'

greet = hello
greet # <function __main__.hello>
greet() # Hello Joe
del hello
hello() # NameError
greet() # Hello Joe

Functions within functions

def hello(name='Joe'):
  print 'The hello() function has been executed'
  def greet():
    return '\t This is inside the greet() function'
  def welcome():
    return '\t This is inside the welcome() function'

  print greet()
  print welcome()
  print 'Now we are back inside the hello() function'

hello()
# The hello() function has been executed
#   This is inside the greet() function
#   This is inside the welcome() function
# Now we are back inside the hello() function

welcome() # NameError

def hello(name='Joe'):
  def greet():
    return '\t This is inside the greet() function'
  def welcome():
    return '\t This is inside the welcome() function'
  if name == 'Joe':
    return greet
  else:
    return welcome

x = hello()
x # <function __main__.greet>

Functions as arguments

def hello():
  return 'Hi Jose!'

def other(func):
  print 'Other code goes here!'
  print func()

other(hello)
# Other code goes here!
# Hi Jose!

Now, here comes the decorator

def new_decorator(func):
  def wrap_func():
    print 'Code here, before executing the func'
    func()
    print 'Code here will execute after the func'
  return wrap_func

def func_needs_decorator():
  print 'This function needs a decorator!'
func_needs_decorator()
# This function needs a decorator!
func_needs_decorator = new_decorator(func_needs_decorator)
func_needs_decorator()
# Code here, before executing the func
# This function needs a decorator!
# Code here will execute after the func

# to rewrite using the @ symbol
@new_decorator
def func_needs_decorator():
  print 'This function needs a decorator!'
func_needs_decorator()
# Code here, before executing the func
# This function needs a decorator!
# Code here will execute after the func

Generators

Iteration vs. generation

  • Before generators come iterables.
  • Everything you can use "for... in..." on is an iterable: lists, strings, files...
  • Iterables are handy because you can read them as much as you wish, but you store all the values in memory and this is not always what you want when you have a lot of values.
  • Generators are iterators, but you can only iterate over them once. It's because they do not store all the values in memory, they generate the values on the fly.
  • Yield is a keyword that is used like return, except the function will return a generator.
  • To master yield, you must understand that when you call the function, the code you have written in the function body does not run. The function only returns the generator object.
  • Using the yield keyword to turn the normal function into generator to save memory for large use cases.
  • The first time the for calls the generator object created from your function, it will run the code in your function from the beginning until it hits yield, then it'll return the first value of the loop. Then, each other call will run the loop you have written in the function one more time, and return the next value, until there is no value to return.
    ref
    ref
    ref

Creating generators

for x in gencubes(100):
  print x

# let's define a normal function that can handle the requirement
def gencubes(n):
  out = []
  for num in range(n):
    out.append(num**3)
  return out # this is kept in memory

# let's rewrite it using generator
def gencubes(n):
  for num in range(n):
    yield num**3 # generators allow us to generate as we go along, instead of holding everything in memory

# another example
def genfibon(n):
  a = 1
  b = 1
  for i in range(n):
    yield a
    a, b = b, a + b

def normalfibon(n):
  a = 1
  b = 1
  out = []
  for i in range(n):
    out.append(a)
    a, b = b, a + b
  return out

for num in genfibon(10):
  print num

next() and iter()

def simple_gen():
  for x in range(3):
    yield x

g = simple_gen()
print next(g) # 0
print next(g) # 1
print next(g) # 2
print next(g) # StopIteration error

s = 'hello'
for let in s:
  print let
# string is iterable but string is not a iterator
next(s) # TypeEror: str object is not an iterator

# to convert iterable into iterator
s_iter = iter(s)
next(s_iter) # h
next(s_iter) # e

Advanced Python Modules

Counter

from collections import Counter

l = [1,1,1,12,2,2,3,4]
print Counter(l) # Counter({1: 3, 2: 2, 3: 1, 12: 1, 4: 1})

s = 'ssddfsddfdsfdfdfd'
print Counter(s) # Counter({'d': 8, 'f': 5, 's': 4})

w = 'How many times does each word show up in this sentense, word, word'
print Counter(w.split())
# Counter({'word': 2, 'show': 1, 'this': 1, 'many': 1, 'in': 1, 'up': 1, 'times': 1, 'How': 1, 'does': 1, 'word,': 1, 'each': 1, 'sentense,': 1})

c = Counter(w.split())
print c.most_common(2) # [('word', 2), ('show', 1)]
print sum(c.values()) # 13 # total of counts
c.clear() # to reset all counts

defaultdict

from collections import defaultdict
# defaultdict is a dictionary like object which provides all methods provided by dictionary but takes first argument (default_factory) as default data type for the dictionary
d = {'k1':1}
d['k1']
# d['k2'] # KeyError

d2 = defaultdict(object)
d2['one'] # <object at ox40df3d>
for item in d:
  print item # one

# to use to set default value
d3 = defaultdict(lambda: 0)
print d3['one'] # 0

OrderedDict

od = {}
od['a'] = 1
od['b'] = 2
od['c'] = 3

for k,v in od.items():
  print k,v
# a 1
# c 3
# b 2

from collections import OrderedDict
od2 = OrderedDict()
od2['a'] = 1
od2['b'] = 2
od2['c'] = 3

for k,v in od2.items():
  print k,v
# a 1
# b 2
# c 3

namedtuple

t = (1,2,3)
t[0] # 1

from collections import namedtuple
# kinda like creating a class
Dog = namedtuple('Dog', 'age breed name')
sam = Dog(age=2, breed='Lab', name='Sammy')
print sam.age # 2
print sam[0] # 2

datetime

import datetime
t = datetime.time(5,25,1)
print t # 05:25:01
print t.hour # 5

print datetime.time.min # 00:00:00
print datetime.time.max # 23:59:59.999999
print datetime.time.resolution # 0:00:00.000001

today = datetime.date.today()
print today # 2016-02-18
print today.timetuple()
# time.struct_time(tm_year=2016, tm_mon=2, tm_mday=18, tm_hour=0, tm_min=0, tm_sec=0, tm_wday=3, tm_yday=49, tm_isdst=-1)
print today.year # 2016
print datetime.date.min # 0001-01-01
print datetime.date.max # 9999-12-31

d1 = datetime.date(2016,2,16)
print d1 # 2016-02-16
d2 = d1.replace(year=1990)
print d2 # 1990-02-16

print d1 - d2 # 9496 days, 0:00:00
print datetime.timedelta(9496) # 9496 days, 0:00:00

Debugger

import pdb

x = [1,3,4]
y = 2
z = 3
result = y + z
pdb.set_trace()
# q to quit
print result

timeit

import timeit

# time the code run for 10 times
timeit.timeit('"-".join(str(n) for n in range(100))', number=100)
#0.004585981369018555
timeit.timeit('"-".join([str(n) for n in range(100)])', number=100 )
#0.003796815872192383
timeit.timeit('"-".join(map(str, range(100)))', number=100 )
#0.003657102584838867

# iPython built-in magic
%timeit "-".join(str(n) for n in range(100))
#10000 loops, best of 3: 32.3 µs per loop

Regular expressions

import re

patterns = ['term1', 'term2']
text = 'This is a string with term1, but not the other term'
match = re.search('hello', 'hello world!') # <_sre.SRE_Match at 0x105e43308>
type(match) # _sre.SRE_Match
match.start() # 22
match.end() # 27

split_term = '@'
phrase = 'What is your email, is it [email protected]?'
re.split(split_term, phrase) # ['What is your email, is it hello', 'gmail.com?']

re.findall('match', 'Here is one match, here is another match')
# ['match', 'match']

def multi_re_find(patterns,phrase):
  '''
  Takes in a list of regex patterns
  Prints a list of all matches
  '''
  for pattern in patterns:
    print 'Searching the phrase using the re check: %r' %pattern
    print re.findall(pattern,phrase)
    print '\n'

test_phrase = 'sdsd..sssddd...sdddsddd...dsds...dsssss...sdddd'

# repetition syntax
test_patterns = [ 'sd*',     # s followed by zero or more d's
              'sd+',          # s followed by one or more d's
              'sd?',          # s followed by zero or one d's
              'sd{3}',        # s followed by three d's
              'sd{2,3}',      # s followed by two to three d's
              ]
multi_re_find(test_patterns,test_phrase)

# charater sets
test_patterns = [ '[sd]',    # either s or d
                  's[sd]+']  # s followed by one or more s or d

# exclusion ^
test_phrase = 'This is a string! But it has punctutation. How can we remove it?'
re.findall('[^!.? ]+',test_phrase)

# charater range [a-f]
test_phrase = 'This is an example sentence. Lets see if we can find some letters.'
test_patterns=[ '[a-z]+',      # sequences of lower case letters
                '[A-Z]+',      # sequences of upper case letters
                '[a-zA-Z]+',   # sequences of lower or upper case letters
                '[A-Z][a-z]+'] # one upper case letter followed by lower case letters
multi_re_find(test_patterns,test_phrase)

# escape codes
# \d    a digit
# \D    a non-digit
# \s    whitespace (tab, space, newline, etc.)
# \S    non-whitespace
# \w    alphanumeric
# \W    non-alphanumeric
test_phrase = 'This is a string with some numbers 1233 and a symbol #hashtag'
test_patterns=[ r'\d+', # sequence of digits ['1233']
                r'\D+', # sequence of non-digits
                r'\s+', # sequence of whitespace
                r'\S+', # sequence of non-whitespace
                r'\w+', # alphanumeric characters
                r'\W+', # non-alphanumeric
                ]
multi_re_find(test_patterns,test_phrase)

StringIO

import StringIO
message = 'This is just a normal string'
f = StringIO.StringIO(message) # to create a file object out of the string

f.write(' Second line')
f.seek()
f.read()

Fix atom unable to install packages behind corporate proxy

Thanks TedThiCo for the solution.

Windows temporary:
set ATOM_NODE_URL=http://gh-contractor-zcbenz.s3.amazonaws.com/atom-shell/dist

Windows permanently:
setx ATOM_NODE_URL http://gh-contractor-zcbenz.s3.amazonaws.com/atom-shell/dist /M

Linux
export ATOM_NODE_URL=http://gh-contractor-zcbenz.s3.amazonaws.com/atom-shell/dist

Fix an error occurred while installing pg (0.18.4) on OS X El Capitan

brew install postgresql

After that, you may run into another problem of:

psql: could not connect to server: No such file or directory
    Is the server running locally and accepting
    connections on Unix domain socket "/tmp/.s.PGSQL.5432"?

And the solution would be to start the server manually, then start your rails app.
pg_ctl -D /usr/local/var/postgres -l /usr/local/var/postgres/server.log start

Object creation

the prototype pattern

function Person() {};

Person.prototype = { // overwrite the prototype object
  constructor: Person, // to restore the 'link', otherwise newInstance.__proto__.constructor points to Object.prototype.constructor
  name: 'Ji Wu',
  age: undefined,
  friends: ['foo', 'bar'], // the bad, properties are shared among all instances
  sayName: function() {
    console.log(this.name);
  }
}

var foo = new Person();
foo.__proto__.constructor // [Function: Person]
foo.friends.push('bob');
var bar = new Person();
bar.friends // [ 'foo', 'bar', 'bob' ]

Development environment setup guide

Install node.js with nvm

  • Install nvm #6
  • Check available node versions with nvm ls-remote
  • Install node with nvm install v5.1.1
  • Make installed node as the default node with nvm alias default 5.1.1

Use overflow: hidden for float clearing

original source

Originally, overflow: hidden was used to hide any content that extends beyond the box.
image

It could also be used for float clearing, meaning, the element with overflow applied (auto or hidden), will extend as large as it needs to encompass child elements inside that are floated (instead of collapsing), assuming that the height isn't declared. Like this:
image

Some other techniques to clear float can be found here

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.