Skip to content

Instantly share code, notes, and snippets.

@tansengming
Last active July 24, 2018 17:24
Show Gist options
  • Save tansengming/1301128 to your computer and use it in GitHub Desktop.
Save tansengming/1301128 to your computer and use it in GitHub Desktop.
Programming Notes
# joins with time range
time_range = (Time.now.midnight - 1.day)..Time.now.midnight
Client.joins(:orders).where(orders: { created_at: time_range })
# List comprehension
foods = ['broccoli', 'spinach', 'chocolate']
eat food for food in foods when food isnt 'chocolate'
// selector with attributes
.option input[type=checkbox] {
}
// go & channels
package main
import "fmt"
func sum(a []int, c chan int) {
sum := 0
for _, v := range a {
sum += v
}
c <- sum // send sum to c
}
func main() {
a := []int{7, 2, 8, -9, 4, 0}
c := make(chan int)
go sum(a[:len(a)/2], c)
go sum(a[len(a)/2:], c)
x, y := <-c, <-c // receive from c
fmt.Println(x, y, x+y)
}
// maps
m := make(map[string]int)
m["Answer"] = 42
// for each
for i, v := range pow {
fmt.Printf("2**%d = %d\n", i, v)
}
// new type declaration. Note curlies on vertex
type Vertex struct {
X int
Y int
}
func main() {
v := Vertex{1, 2}
v.X = 4
fmt.Println(v.X)
}
// if with a statment
if v := math.Pow(x, n); v < lim {
return v
}
// Inside a function, the := short assignment statement can be used in place of a var declaration with implicit type.
// Outside a function, every construct begins with a keyword (var, func, and so on) and the := construct is not available.
// initializers
var i, j int = 1, 2
var c, python, java = true, false, "no!"
// note the return
func split(sum int) (x, y int) {
x = sum * 4 / 9
y = sum - x
return
}
// save on ints
func add(x, y int) int {
return x + y
}
// Useful
fmt.Println(12)
// ES6 Arrows
class MyClass {
constructor() {
this.name = 'Max';
setTimeout(() => {
// This prints "Max" since arrow functions bind to our current "this" context.
console.log(this.name);
});
}
}
/// This is like writing:
var _this = this;
setTimeout(function() {
console.log(_this.name);
});
// Logging Array Data
var langs = [
{ name: "JavaScript", extension: ".js" },
{ name: "HTML", extension: ".html" },
{ name: "CoffeeScript", extension: ".coffee" },
{ name: "SASS", extension: ".sass" }
];
console.table(langs);
# Pure Function as an Object (PFaaO)
## https://kellysutton.com/2017/09/13/embracing-functional-programming-in-ruby.html
class PayrollCalculator
def self.calculate(payroll)
new(payroll).calculate
end
def initialize(payroll)
@payroll = payroll
end
private_class_method :new
def calculate
PayrollResult.new(
payroll: payroll,
paystubs: paystubs,
taxes: taxes,
debits: debits
)
end
# all instance methods implicitly private because
# you can't call new
def paystubs
# ...
end
end
# Tap
## instead of
user = User.new
user.name = "John"
user
## try
User.new.tap { |user| user.name = "John" }
# pry instrospections https://blog.cognitohq.com/five-pry-features-every-ruby-developer-should-know/
find-method xpath Nokogiri
stat Nokogiri::CSS.xpath_for
show-source Nokogiri::CSS.xpath_for
# Ruby 2.3 introduced the "squiggly heredoc" <<~.
# This will remove all the extra spaces introduced by indentation
# To generate a backtrace without raising an exception use the caller method like:
class Project
def foo
puts "====================="
puts caller
end
# quick way to log where a function is getting called
def first_name
log_backtrace(:first_name)
profile.first_name
end
def log_backtrace(name)
filtered_backtrace = caller.select do |item|
item.start_with?(Rails.root.to_s)
end
Rails.logger.warn(<<-END)
A reference to an obsolete attribute #{name} at:
#{filtered_backtrace.join("\n")}
END
end
# Ruby automatically invokes the call method when the method name is omitted
Create.(params) == Create.call(params)
# getting source location of render
def index
p method(:render).source_location
render params[:id]
end
## reading from stdin
echo "bananas!" | ruby -e "puts STDIN.read"
### . If we run our script with the -n flag, Ruby will automatically loop over each line in STDIN.
### The current line is in the global variable $_.
ls | ruby -n -e 'puts $_.split(".").last'
## Splat -> converts arrays to method arguments
### As the argument
def say(what, *people)
people.each{|person| puts "#{person}: #{what}"}
end
say "Hello!", "Alice", "Bob", "Carl"
### to an argument
def add(a,b)
a + b
end
pair = [3,7]
add *pair
## Ruby delegators
class Queue
extend Forwardable
def initialize
@q = [ ] # prepare delegate object
end
# setup preferred interface, enq() and deq()...
def_delegator :@q, :push, :enq
def_delegator :@q, :shift, :deq
# support some general Array methods that fit Queues well
def_delegators :@q, :clear, :first, :push, :shift, :size
end
## Rake Directories
### Rakefile
directory 'output'
task something: ['output'] # will automatically create the output dir
## inject with powers
products.map(&:price).inject(0, &:+)
## Rake options
task :thing, [:foo] do |task, args|
puts args[:foo] # First argument
puts args.extras # The rest of the arguments
end
# $> rake thing[foo]
# foo
# $> rake thing[foo,extra1,extra2]
# foo
# extra1
# extra2
## Rake directories
# Additional rake files (with the file extension “.rake”) may be placed in rakelib directory
# located at the top level of a project (i.e. the same directory that contains the main Rakefile).
## Getting a random string
require 'securerandom'
puts SecureRandom.urlsafe_base64(50)
## Multi-line regexes
regexp = %r{
start # some text
\s # white space char
(group) # first group
(?:alt1|alt2) # some alternation
end
}x
## CSV with headers
visitors = CSV.read('visitors.csv', headers: true)
visitors.count{|v| v['location'] =~ /San Francisco/} # => 168
### Streaming version
CSV.open('visitors.csv', header: true) do |csv|
visitors = csv.each
visitors.count{|v| v['location'] =~ /San Francisco/ }
end
## Use x modifier for complex regexps. This makes them more readable and you can add some useful comments. Just be careful as spaces are ignored.
regexp = %r{
start # some text
\s # white space char
(group) # first group
(?:alt1|alt2) # some alternation
end
}x
## Assignments and ifs
### good - shows intented use of assignment
if (v = array.grep(/foo/)) ...
### bad
if v = array.grep(/foo/) ...
### also good - shows intended use of assignment and has correct precedence.
if (v = self.next_value) == "hello" ...
# https://github.com/styleguide/ruby
## getting only direct methods (ignoring inherited ones)
obj.public_methods(false)
# Single line options split
count, default = options.values_at(:count, :default)
# Pry
# pry("friend":3)> nesting
# Nesting status:
# 0. main (Pry top level)
# 1. Hello
# 2. 100
# 3. "friend"
# pry("friend":3)> jump-to 1
# pry(main)> cd Pry
# pry(Pry)> ls -M --grep re
# Pry#methods: re readline refresh rep repl repl_epilogue repl_prologue retrieve_line
# pry(Pry):1> show-method rep -l
# pry(main)> cd Gem
# pry(Gem):1> show-doc try_activate
# pry(main) ri Array#each
## using in Rails
# pry -r ./config/environment
## In Ruby, &method calls you!
["1", "2", "3"].map(&method(:Integer))
## Defaulting hashes
@filesize = Hash.new do |key, val|
val = calculate key
end
@filesize[arg] # will trigger calculate for keys that are not found
# Exceptions
## raising
def i_must_have_truth(value)
raise TypeError, 'You must give me truth' if value == false
end
## rescuing
begin
raise ZeroDivisionError, "Hello I am a random zero division error"
rescue ZeroDivisionError => e
p e.message
p e.backtrace
ensure
# do something
end
## new exceptions
class MyCrazyError < StandardError # DO NOT inherit from Exception
end
raise MyCrazyError, "I am a crazy new exception"
# ref: http://www.skorks.com/2009/09/ruby-exceptions-and-exception-handling/
# Blocks
def func(x, &block)
block.call(1)
end
# is almost equivalent to
def func(x)
yield 1
end
# yield just saves you the block.call
# Aliasing
class Microwave
def on
puts "The microwave is on"
end
alias :start :on
end
## ActiveSupport::Concern
module M
extend ActiveSupport::Concern
included do
some_class_method
end
module ClassMethods
# ...
end
module InstanceMethods
# ...
end
end
module B
extend ActiveSupport::Concern
include A
included do
class_method_from_module_a
end
end
## rspec
describe 'a feature' do
let(:var) { } # setup lazy vars
let!(:var) { } # setup vars
before { 'always triggers first' } # initialize
subject { } # subject under test
context 'when it is in a certain mode' do
it { should be_eligible_to_vote } # implicit subject
before { 'happens after top before' }
it 'should equal something' do
subject.should == 'something'
end
it 'should increment when incremented' do
expect { Counter.increment }.to change{ Counter.count }.by(1)
expect { Counter.increment }.to change{ Counter.count }.from(0).to(1)
expect {Counter.increment}.to_not change{Counter.count}.by(1)
end
it 'should not have an exception' do
lambda { subject }.should_not raise_error Validation::Error
end
end
context 'when testing controllers' do
before { subject }
subject { get :index }
it 'should be success' do
response.should be_success
end
it 'should render the right template' do
response.should render_template("new")
end
it 'should redirect to the right place' do
response.should redirect_to(menu_items_url)
end
its(:body) { should_not have_selector("#this-week", text: '13') }
end
end
## Explosions
'-' * 5 #=> "------"
['-'] * 5 #=> ['-', '-', '-', '-', '-']
## Formatter
formatter = "%s %s %s %s"
puts formatter % [1, 2, 3, 4]
## Nokogiri
doc = Nokogiri::HTML(open("http://www.threescompany.com/"))
doc.css("dramas name").first # => "The A-Team"
doc.at_css("dramas name") # => "The A-Team"
doc.css('a').first.attributes['href']
## Nokogiri Slop
doc = Nokogiri::Slop <<-EOXML
<employees>
<employee status="active">
<fullname>Dean Martin</fullname>
</employee>
<employee status="inactive">
<fullname>Jerry Lewis</fullname>
</employee>
</employees>
EOXML
# navigate!
doc.employees.employee.last.fullname.content # => "Jerry Lewis"
# access node attributes!
doc.employees.employee.first["status"] # => "active"
# use some css!
doc.employees.employee("[status='active']").fullname.content # => "Dean Martin"
## Compiling gem on other machine
#> gem install rake-compiler
#> gem unpack some-gem-with-native-extensions
#> rake native gem
## obj.present?
obj.present? == !obj.nil? && !obj.empty?
## system vs exec
exec gets out of the current thread. Which is usually not what you want.
## Object Exists?
# to check if object exists or is defined.
defined?(Post)
## Unit Testing
require 'test/unit'
class TC_MyTest < Test::Unit::TestCase
# def setup
# end
# def teardown
# end
def test_fail
assert(false, 'Assertion was false.')
end
end
## urlencode and htmlencode
require 'cgi'
CGI.escape(url)
CGI.unescape(name_encoded)
CGI.escapeHTML(url)
CGI.unescapeHTML(name_encoded)
## Fastercsv
# Reading
FasterCSV.foreach("path/to/file.csv") do |row|
# use row here...
end
arr_of_arrs = FasterCSV.read("path/to/file.csv")
# Writing
FasterCSV.open("path/to/file.csv", "w") do |csv|
csv << ["row", "of", "CSV", "data"]
csv << ["another", "row"]
end
FCSV { |csv_out| csv_out << %w{my data here} } # to $stdout
FCSV(csv = "") { |csv_str| csv_str << %w{my data here} } # to a String
Ref
## Openstruct
require 'ostruct'
record = OpenStruct.new
record.name = "John Smith"
puts record.name # -> "John Smith"
puts record.address # -> nil
## Logger
require 'logger'
Log = Logger.new(STDOUT); Log.level = Logger::INFO
## Stripping HTML
str.gsub(/<\/?[^>]*>/, "")
# Sort on steroids
sort -n -t',' -k3 uniqMovie.csv
# -n to inform its numerical sorting and not lexical sorting
# -t specifies delimiter which is comma is this case
# -k indicates which column, 3rd in our case
# Loop forever
while true; do sleep 5; echo 1; done
# for with ranges
for i in {1..7}
do
#stuff
done
# git grep files
git grep abc -- '*.rb'
# generating random chars
head -c 9 /dev/urandom | base64 -
# pipe std and sterr to a file
some_command 2>&1 | tee -a a.log
// For and If
let individualScores = [75, 43, 103, 87, 12]
var teamScore = 0
for score in individualScores {
if score > 50 {
teamScore += 3
} else {
teamScore += 1
}
}
// Escaping
let apples = 3
let oranges = 5
let fruitSummary = "I have \(apples + oranges) pieces of fruit."
// Casting
let label = "The width is "
let width = 94
let widthLabel = label + String(width)
// Variables and Constants
var myVariable = 42
myVariable = 50
let myConstant = 42
# appending x or f to rspec
xit 'uses `xit` instead of `it` skips the spec' do
end
fit 'appending f makes the spec focus' do
end
# Ranges in AR
User.where(created_at: 1.day.ago..Time.now) # SELECT "users".* FROM "users" WHERE ("users"."created_at" BETWEEN '2016-06-29 15:24:55.565740' AND '2016-06-30 15:24:55.565975')
# Sidekiq
SmsWorker.perform_async(model.id,model.class.to_s)
Services::Notification::Worker.perform_in(DELAY, source.id, source_klass, :ios)
UserMailer.delay.welcome_email(@user.id)
UserMailer.delay_for(DELAY).booking_email(model.id, recipient.id)
# RSpec stubs and mocks
expect_any_instance_of(CondoManager::Resources::Account).to receive(:save)
allow_any_instance_of(CondoManager::Client).to receive(:parse_resource).and_raise(CondoManager::Error)
# Rails load order
# script/rails
# config/boot.rb
# config/application.rb
# config/environment.rb
# config/initializers/*.rb (In alphabetic order)
# stubbing exceptions on rspec
context 'when connection is reset' do
before { Purchase.any_instance.stub(:purchase).and_return{ raise Errno::ECONNRESET } }
its(:body) { should have_content 'payment servers are currently busy' }
end
# end of deploy sanity check
# ./script/rails runner -e staging 'exit Student.first ? 0 : 1'"
## checking for locals within partials
# <% if local_assigns.has_key? :headline %>
# Headline: <%= headline %>
# <% end %>
# http://api.rubyonrails.org/classes/ActionView/Base.html
## Finders with errors when not found
User.find_by_name! 'nonexistent!'
## Rails Delegation
class Greeter < ActiveRecord::Base
def hello
"hello"
end
end
class Foo < ActiveRecord::Base
belongs_to :greeter
delegate :hello, :to => :greeter
end
Foo.new.hello # => "hello"
### Also
Person = Struct.new(:name, :address)
class Invoice < Struct.new(:client)
delegate :name, :address, :to => :client, :prefix => true
end
john_doe = Person.new("John Doe", "Vimmersvej 13")
invoice = Invoice.new(john_doe)
invoice.client_name # => "John Doe"
invoice.client_address # => "Vimmersvej 13"
## Active Record Serialize
class User < ActiveRecord::Base
serialize :preferences
end
user = User.create(:preferences => { "background" => "black", "display" => large })
User.find(user.id).preferences # => { "background" => "black", "display" => large }
# Or, specify a class
class User < ActiveRecord::Base
serialize :preferences, OpenStruct
end
user = User.new
user.preferences.theme_color = "red"
## rescue_from
class SomeController < ApplicationController
rescue_from User::NotAuthorized, :with => :deny_access # self defined exception
rescue_from ActiveRecord::RecordInvalid, :with => :show_errors
rescue_from 'MyAppError::Base' do |exception|
render :xml => exception, :status => 500
end
end
## Migrations
def up
say_with_time "Updating salaries..." do
Person.find(:all).each do |p|
p.update_attribute :salary, SalaryCalculator.compute(p)
end
end
end
## respond_to
respond_to do |format|
format.json { render json: nil, status: :ok }
end
# btw, don't use to_json
# http://jonathanjulian.com/2010/04/rails-to_json-or-as_json/
respond_to do |format|
format.json { render :json => items.as_json(:only => [:id], :methods => [:label, :value])}
end
## Advanced HAML
# %div[@user, :greeting] -> <div class='greeting_crazy_user' id='greeting_crazy_user_15'>
# & I like #{"cheese & crackers"} -> I like cheese &amp; crackers
# != "I feel <strong>!" # unescapes HTML
## ActiveRecord
add_index "subscriptions", ["user_id", "content_id"], :unique => true # migration
validates_uniqueness_of :user_id, :scope => :content_id # model
## Rails Responders
# http://api.rubyonrails.org/classes/ActionController/Responder.html
def create
@user = User.new(params[:user])
flash[:notice] = 'User was successfully created.' if @user.save
respond_with(@user)
end
# custom return
def create
@project = Project.find(params[:project_id])
@task = @project.comments.build(params[:task])
flash[:notice] = 'Task was successfully created.' if @task.save
respond_with(@project, @task, :status => 201)
end
# with a block
def create
@project = Project.find(params[:project_id])
@task = @project.comments.build(params[:task])
respond_with(@project, @task, :status => 201) do |format|
if @task.save
flash[:notice] = 'Task was successfully created.'
else
format.html { render "some_special_template" }
end
end
end
## as_json
User.find(1)
user.as_json # => {"id": 1, "name": "Konata Izumi", "age": 16, "created_at": "2006/08/01", "awesome": true}
user.as_json(:only => [ :id, :name ]) # => {"id": 1, "name": "Konata Izumi"}
user.as_json(:except => [ :id, :created_at, :age ]) # => {"name": "Konata Izumi", "awesome": true}
user.as_json(:methods => :permalink) # => {"id": 1, "name": "Konata Izumi", "age": 16, "created_at": "2006/08/01", "awesome": true, "permalink": "1-konata-izumi"}
user.as_json(:include => :posts)
user.as_json(:include => { :posts => { :include =>
{ :comments => { :only => :body } },
:only => :title }
}
)
## production.rb hint to serve to multiple asset hosts
config.action_controller.asset_host = 'assets%d.example.com'
## content_for (with HAML)
# - content_for :controls do
# %ul
# %li Do this
# %li Do that
# = yield :controls
# %table
# …
# = yield :controls
## Inherited Resources
def create
create! { products_path }
end
class TalksController < InheritedResources::Base
belongs_to :track
respond_to :json, :only => [:index]
def index
respond_with(collection, :methods => [:attachment_type, :rate_average], :include => { :participations => { :include => :speaker }, :attachments => {}, :location => {} })
end
end
# Flash messages in en.yml
# en:
# flash:
# reviews:
# create:
# notice: "Your review has been created!"
## ActiveAdmin
ActiveAdmin.register Event do
menu :if => :super_admin?
belongs_to :account
belongs_to :other, :optional => true
form do |f|
f.inputs do
f.input :name
f.input :start_date, :as => :datepicker
end
# remember to add 'accepts_nested_attributes_for' in user.rb
f.has_many :pets do |p|
p.input :name
p.input :animal, :as => :select, :collection => %w{Cat Dog}
end
f.buttons
end
show do
attributes_table :name, :slug
panel "Logo" do
image_tag(resource.logo.url) if resource.logo.present?
end
attributes_table do
row :trainer do
pretty_format constraint.trainer
end
end
resource.constraints.each do |constraint|
panel 'Constraint' do
attributes_table_for constraint, :trainer
end
end
end
index do
column :name
column(:avatar) { |resource| resource.avatar.present? ? status_tag('YES', :ok) : status_tag('NO', :warning) }
default_actions
end
filter :name
action_item :only => :show do
link_to 'Upload Attendees', new_admin_event_attendee_csv_path(resource)
end
controller do
around_filter :set_timezone, :only => [:create, :update]
private
def set_timezone
orig_timezone = Time.zone
Time.zone = params[:event][:timezone]
yield
ensure
Time.zone = orig_timezone
end
end
end
# With Formtastic
# <%= semantic_form_for resource, :url => resource.new_record? ? collection_path : resource_path, :html => {:multipart => true} do |f| %>
# <%= f.inputs do %>
# <%= f.input :account_id, :input_html => {:value => current_admin_user.id}, :as => :hidden %>
# <%= f.input :start_date, :input_html => {:class => 'datepicker'}, :as => :string %>
# <%= f.input :post_checkin_image, :as => :file %>
# <% end %>
# <%= f.buttons %>
# <% end %>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment