Friday, November 16, 2018

Simple Dockerfile and docker-compose.yml for Rails 5 App

Dockerfile contents:

FROM ruby:2.5

RUN apt-get update -qq && apt-get install -y build-essential libpq-dev nodejs

RUN mkdir /budget
WORKDIR /budget

COPY Gemfile /budget/Gemfile
COPY Gemfile.lock /budget/Gemfile.lock

RUN bundle install
COPY . /budget

LABEL maintainer="Bala Paranj "

CMD puma -C config/puma.rb

docker-compose.yml:

version: '3'
services:
  web:
    build: .
    command: bundle exec rails s -p 3000 -b '0.0.0.0'
    ports:
      - "3000:3000"

Run:

docker-compose build
docker-compose up

Simple CircleCI Configuration File to Build Rails 5 Project

I am working on the landing page for Budget Scape. Here is the simplest circleci/config.yml:

version: 2
jobs:
  build:
    working_directory: ~/budget
    docker:
      - image: circleci/ruby:2.4.1
        environment:
          RAILS_ENV: test
    steps:
      - checkout

      - run: sudo apt-get update && sudo apt-get install nodejs
      # Bundle install dependencies
      - run: bundle install

      # Run the tests
      - run: bundle exec rake

I am using sqlite as the production database.  The home page is a lead capture page with bullet list of benefits for a user.

Wednesday, November 07, 2018

Developing REPL from Scratch in Ruby

Read Evaluate Print Loop

One liner:

loop { p eval gets }

Readable:

loop do
  print "$ "
input = gets.chomp!
result = eval(input)
puts "=> #{result}"
end


Persist Local Variable

myirb_binding = binding()
loop do
  print "$ "
input = gets.chomp!
result = myirb_binding.eval(input)
puts "=> #{result}"
end

Code written by Chris Wanstrath:

loop do
  print ENV['REPL_PROMPT'] || "#{ARGV[0]}>> "

  begin
    line = $stdin.gets.chomp
  rescue NoMethodError, Interrupt
    exit
  end

  if from_stdin
    run = "echo \"%s\" | #{command}" % [ line, nil ]
  else
    run = "#{command} %s" % [ line, nil ]
  end
  puts "$ #{run}" if debug
  system run
  warn "Use Ctrl-D (i.e. EOF) to exit" if line =~ /^(exit|quit)$/
end

Difference Between IRB and Code in Ruby File

One of the differences is that any method defined at the top level in a Ruby file becomes a private method in Object.

def greet
  p 'hi'
end

o = Object.new
o.greet

NoMethodError: private method ‘greet’ called for #. You can verify this:

 def greet
   p 'hi'
 end 

 p self.private_methods.grep(/greet/)

But in IRB it becomes a public method.

$ irb
2.3.3 :001 > def greet
2.3.3 :002?>   p 'hi'
2.3.3 :003?>   end
 => :greet
2.3.3 :004 > o = Object.new
 => # 
2.3.3 :005 > o.greet
"hi"
 => "hi"
 
Hey, you can also use self to call the greet method like this:

self.greet

or just

greet


Tuesday, November 06, 2018

Moving a Repo Quickly from Gitlab to Github

If you don't mind losing the git log in the new repo, you can move a repo easily in three steps:

1. Remove the existing git files in the repo:

rm -rf .git

2. Add a new origin:

git remote add new-origin git@github.com:your-user:your-project.git

3. Push it to the new repo

git push --all new-origin

Managing SSH Keys in Ubuntu

sudo apt-get install keychain

In ~/.bashrc, add:

keychain id_rsa
. ~/.keychain/`uname -n`-sh

In the terminal:

source ~/.bashrc

 * keychain 2.8.2 ~ http://www.funtoo.org
 * Found existing ssh-agent: 5059
 * Known ssh key: /home/bparanj/.ssh/id_rsa

I had already generated the ssh key using ssh-keygen and ran:

$ eval "$(ssh-agent -s)"
Agent pid 5059 
 



Monday, November 05, 2018

kazam on Ubuntu to record screencast

It works. But the size of the files that it creates is huge. It quickly filled up 100 GB hard disk space allocated to the Ubuntu 18.04 running on VirtualBox quickly. Started getting out of disk space errors that I was scratching my head to fix for a few days.

How to find available disk space in Ubuntu

df -h --total

This command will show you:

Filesystem      Size  Used Avail Use% Mounted on
total           105G  8.6G   92G   9% - 
 
 

Sunday, October 28, 2018

Ruby Closure - Outline for Presentation #2


Part 1

Required Concepts 

1. yield
2. yield with value
3. block variable
4. Migration file uses both Object Oriented and Functional style of programming.

In a Rails project the migration file looks like this:

class CreateArticles < ActiveRecord::Migration

  def change
    create_table :articles do |t|
       t.string :title
       t.text :body

       t.timestamps
     end
  end
end


The final solution for the presentation:

module ActiveRecord
  class Migration
    def change
      puts 'change'
    end

    def create_table(name)
      table = Table.new(name)
      yield table
    end
  end
end

class Table

  def initialize(name)
    @name = name
  end

  def string(column_name)
    puts "String column #{column_name} for table #{@name}"
  end
end

class CreateArticles < ActiveRecord::Migration
  def change
    create_table :articles do |t|
      t.string :title
    end
  end
end

c = CreateArticles.new.change

Implementing the text and timestamps are left as exercises for the attendees.

Part 2

Required Concepts

1. Changing the value of self.
2. Executing code in a different context
3. Using instance_eval to change self
4. yield vs instance_eval
5. Taking block in the argument of a method
6. Using ampersand in the argument of a method
7. The significance of &block in the method argument

Routes file looks like this:

Rails.application.routes.draw do
  get '/home' => 'welcome#home'
end


Step 1


module Rails
  def draw
    puts 'routes file' 
  end
end

class Tester
  include Rails
end

t = Tester.new.draw

Step 2

module Rails
  def draw
    yield
  end
end

class Tester
  include Rails
end

Tester.new.draw do
  get '/home' => 'welcome#home'
end

Step 3

module Rails
  class Router
    def get(hash)
      p 'Method to handle HTTP get request'
    end  
  end

  def draw
    router = Router.new
    yield router
  end
end

class Tester
  include Rails
end

Tester.new.draw do |router|
  router.get '/home' => 'welcome#home'
end

The older versions of Rails used the block variable. How to get rid of it and simplify the DSL?

Step 4

Let's move the draw method into the Router class.

module Rails
  class Router
    def get(hash)
      p 'Method to handle HTTP get request'
    end  
    
    def draw
      yield self
    end
  end
end

Rails::Router.new.draw do |router|
  router.get '/home' => 'welcome#home'
end

Step 5

module Rails
  class Router
    def get(hash)
      p 'Method to handle HTTP get request'
    end  
    
    def draw(&block)
      instance_eval(&block)
    end
  end
end

Rails::Router.new.draw do 
  get '/home' => 'welcome#home'
end

We have replaced the yield with instance_eval that evaluates the given block in the context of the Router instance. It switches the value of self from main Object to Router object.

Part 3


Symbol to proc trick, for instance : ['ruby', 'powerful'].each(&:upcase) uses the ampersand colon trick. 

Concepts Required

1. Coercion
2. Using send for sending messages to an object. Why use send?
3. Significance of ampersand as the prefix to an object in a method argument
4. How does to_proc get invoked?
5. *args in the method argument.
6. Providing default value for block variable.
7. Using send to message an object.

1.

result = ['hi', 'how'].map {|x| x.upcase }
p result

2.

#  {|x| x.upcase }
result = ['hi', 'how'].map(&:upcase)
p result

3.

Goal :

map {|x| x.upcase } ----> map(&:upcase)

4.

The & in the argument converts the object to a Proc object by calling to_proc on it. The object is symbol. We need to implement to_proc in Symbol object.

class Symbol
  def to_proc
    Proc.new {|o| o.upcase }
  end
end

result = ['hi', 'how'].map(&:upcase)
p result

5. 
  def to_proc
    Proc.new {|o| o.send(self) }
  end

6. Multiple block variables

output = [1,2,3,4].inject(0) {|result, element| result + element }
p output

===

output = [1,2,3,4].inject(&:+)
p output

will break the existing to_proc implementation.

Fix:

  def to_proc
    Proc.new {|o, args| o.send(self, args) }
  end

But this will break:

result = ['hi', 'how'].map(&:upcase)
p result

Fix:

  def to_proc
    Proc.new {|o, args=nil| o.send(self, *args) }
  end

Now both one block variable and two block variables can be used.

Closure

A closure is in it's simplest form a block of code that can be passed around as a value, and that can reference variables in the scope it was created in even after exiting from that scope.

The variables are allocated on the heap. Because normally local variables live in the stack and are gone after a method returns.

References

How to Implement Closures
Closure in Crystal

Wednesday, October 10, 2018

Find all the Replace by Chaining ack output to sed

From the command line, I was able to replace Bootstrap 3 classes with Bootstrap 4 class using
ack, sed and xargs. 
 
ack "search text" -l --print0 | xargs -0 -n 1 sed -i "s/search text/replacement text/"
 
Reference:
 
Sed recursively with the help of ack and xargs
 

Sunday, October 07, 2018

Top 3 Lessons from Successful Open Source Projects

  1. Every good work of software starts by scratching a developer's personal itch.
  2. Good programmers know what to write. Great ones know what to rewrite (and reuse).
  3. Smart data structures and dumb code works a lot better than the other way around.
Linux was not written from scratch. Linus Torvalds took the Minix as the starting point. It is easier to start from a good partial solution. Minix provided the scaffold and eventually the Minix code was either rewritten or deleted. Read more at Cathedral Bazaar

Sunday, September 30, 2018

Organized Topics for Coding Skills

Big O Notation

Construction of Loops
Establishing Initial Conditions for Loops
Finding the Iterative Construct
Termination of Loops
Iteration Trace Table
Iterative Program Structure
While Loop Structure
For Loop Structure
For Loop Examples
Comparison: Loops vs Recursive Functions

Divide-and-Conquer
Recursion : Algorithmically, Semantically
How to Code Recursively
Stack Overflow Example
Compute a to the power b
Induction and Recursion

Summation Algorithm
Add a sequence of numbers
Recursion
Iteration
Recursive Sum

Multiplication
Iterative Solution
Recursive Solution

Division without divide operator
Trace : Desk Check a solution
Non-Linear Recursion

Factorial
Recursive Solution
Optimized Solution
Factorial Call Stack
Factorial Algorithm
Factorial Implementation

Compute a to the power b
Recursion Solution
Iterative Solution

Compute a % b
Iterative Solution
Efficient Solution

Fibonacci : Multiple Bases Cases - Recursion
Efficient Fibonacci
Fibonacci Runtime
Fibonacci Number Efficiency
Fibonacci Iterative Solution

Dynamic Programming

Square Root Desk Check Table
Binary Recursion
Even Number
Square Root
Linear Recursion

Exponentiation Function
Factorial C
Array C
Binary Search C
Reverse String C
Sum the Digits

Find Repeating Elements
Identical
Unique Characters
Unique Characters with Constraints
Duplicate Elements in Array
Recognize Non-Linear Recursion
Add Adjacent Elements
Runtimes + , *
Powers of 2 from 1 through n
Remove White Spaces
Remove Duplicates in a String
String Segmentation
Palindrome
Palindrome Substrings Diagrams
Palindrome

Tuesday, September 25, 2018

How to override merge conflict

To use the latest git version of the file. We can replace file that has conflict with the latest from repo by running these commands:

git reset -- path/to/file.ext


git checkout path/to/file.ext

Sunday, September 23, 2018

Unable to download data from https://rubygems.org/ - SSL_connect returned=1


gem install rails -v 4.1


ruby -ropen-uri -e 'eval open("https://git.io/vQhWq").read'


-e:1:in `eval': uninitialized constant OpenSSL::OPENSSL_LIBRARY_VERSION (NameError)

ruby -v -e 'require "openssl"; p OpenSSL'

ruby 2.1.2p95 (2014-05-08 revision 45877) [x86_64-darwin13.0]
OpenSSL


brew rm openssl
brew cleanup openssl
brew install openssl

Thursday, September 20, 2018

Monday, September 17, 2018

Copy / Paste terminal utility for Ubuntu

1. sudo apt-get update
2. sudo apt-get install xclip

Add an alias to the .bashrc file:

alias pbcopy='xclip -sel clip'

I am using the same command that is used on a Mac as the alias. I also have open alias to open a directory from a terminal:

alias open='xdg-open'

Wednesday, July 25, 2018

no implicit conversion of nil into String

This can happen when you have not defined the required configuration in secrets.yml. For instance, you are using http basic auth and the credentials are not defined in the config file.

Wednesday, July 18, 2018

simplehttpserver npm



npm install simplehttpserver -g
simplehttpserver .
simplehttpserver . -p 8081

Tuesday, July 17, 2018

Converting .avi file to .mp4

Install ffmpeg:

On Mac 10.10.5:


brew install ffmpeg



Thursday, July 12, 2018

Sprockets::FileNotFound: couldn't find file 'fingerprintjs2' with type 'application/javascript'

jquery_ujs Uncaught TypeError: $.ajaxPrefilter is not a function

This happened when I copied the started template from Bootstrap 4.1 version. It gives you the slim version of jQuery by default. Use the regular jQuery. https://code.jquery.com/jquery-3.3.1.min.js

In style.scss, include
@import bootstrap

Copy the bootstrap.js to vendor/assets/javascripts directory. Copy bootstrap.css to vendor/assets/css directory.

Sunday, July 08, 2018

NeverBounce API



s3 images





Overcoming Mental Hurdles to Software Development

Facing Too Many Unknowns 


Facing many unknowns and working on a new API can be overwhelming. Even if you have the physical and mental energy to work, you can get stuck. I faced this challenge in a recent project. I decided to tackle this by doing an easy task. I copied the basic Bootstrap 4.1 table with hard-coded data and rendered the view in the web app. I was able to see something real, think through vague requirements and asked the stake holder the right questions. If you have a client who only has a vague idea of what they need, it becomes a challenge to gain understanding with minimum amount of code.

Gaining Momentum


I was able to gain momentum by tackling simple tasks related to that feature. Refined the requirements and the user's flow over a few days to come up with more followup questions to finalize the requirements. Once the requirements became clear, I was not coding based on some phantom requirements and designing the complicated database structure that was not even required. The time spent on solving problems that did not exist was very energy draining. I had already spent time on analyzing the flow that could vary due to three variables. This made the solution very complex due to the amount of variations. The code was becoming a big mess.

Focusing on the Core


I drew simple diagrams with boxes and arrows to show the user's flow for different use cases. Discussion with the stakeholder had a structure because we focused only on one use case at a time.  There was no discussion of technology during this conversation. Only golden path scenario was discussed to clarify the requirements. We can add the alternate scenarios later. We can ask questions based on the existing diagrams, reason about what should happen and draw the alternate scenarios separately.

Gaining Business Context


I made the mistake of copying the similar features of other existing products. I realized it was a mistake later because the business context was different. During the conversation based on simple diagrams I was able to understand the business context. I had narrowed the scope of the problem to be solved.  I also pushed back on some requirements and asked the stakeholder to justify why it should be included in version 1. Some of the things might happen once every 3 months does not justify automation and was removed from the stated requirements.

Building a Prototype First


I did not build a prototype because it was a lot easy to use Bootstrap 4.1 with Rails to build the screens with hard coded data. I saved the time to learn a prototyping tool. I was able to focus on learning new AWS APIs that was required to build the product.

Being Agile and Lean


The client was remote and was able to chat via What's app and email few times a week. The requirements were in the emails and were not well thought out to write the test first. Clarify First, Test Later. I did not automate the infrastructure management because at this point I am not sure if I can get 99 clients who will find this product useful without any customization. It has been custom built for this particular client. Reading the lean startup articles, I was confident that I was targeting the right segment in the adoption curve.

Lessons Learned


  • Do not write production level code before understanding the business. 
  • Draw simple diagrams with technical details to gain business context first.
  • Narrow down the scope of the problem before starting to code.
  • It's ok to start the first few versions of the screen with existing products from similar domains.
  • Remember, these screens need to refined once the business context knowledge is acquired.
  • If the complexity of the solution is getting out of control, go back and see if you can push back on the requirements.


Friday, July 06, 2018

Web Apps and MVC

These diagrams explain the flow of the web app for different use cases. These diagrams can easily be understood by stakeholders with no technical background. The conversation based on these diagrams are useful to understand the requirements and clarify any vague requirements.

This flow is also useful when developing a MVC based Web app. Because these use cases can span across different controllers and each controller can be shared by different use cases. It provides a structure and minimizes the rework required in later stages after the app is deployed.

Tuesday, July 03, 2018

Running Jobs in the Background

1. Active Job Async

Configure queue_adapter in config/application.rb:

config.active_job.queue_adapter = ActiveJob::QueueAdapters::AsyncAdapter.new 
  min_threads: 1,
  max_threads: 2 * Concurrent.processor_count,
  idletime: 600.seconds

2. Use perform_later when you send the email.

3. Linode $5 box has one core:

$ grep -c ^processor /proc/cpuinfo   

1

References

Automatic Renewal LetsEncrypt SSL Certificate



sudo certbot renew --dry-run

If this does not show any errors, your SSL will be renewed automatically. Reference: 

How To Secure Apache with Let's Encrypt on Ubuntu 16.04


Install Wild Card SSL using LetsEncrypt on Apache

Monday, July 02, 2018

Run commands on server using Capistrano 3

Add :

require 'capistrano/console'

to Capfile

Now you can run:


bundle exec cap production console


This allows you to run commands on the server terminal. Useful to run commands like: uptime.

How to tail production log in Capistrano 3

1. Add:

to lib/capistrano/tasks/tail.rake.

namespace :logs do
  desc "tail rails logs. Usage cap production logs:tail_rails"
  task :tail_rails do
    on roles(:app) do
      execute "tail -f #{shared_path}/log/#{fetch(:rails_env)}.log"
    end
  end
end

2. You can now tail the production log from your local machine:

cap production logs:tail_rails

How to configure Capistrano 3 to play with Rails staging / production console

1. Add:

gem 'capistrano-rails-console', require: false

to Gemfile and bundle.

2. Add:

require 'capistrano/rails/console'

to Capfile.

3. Run:

cap production rails:console

to play in production rails console.

Sunday, July 01, 2018

Make Capistrano Run Migration on Deploy

Make sure you have the db role in the 

config/deploy/production.rb file as follows:

:

server 'ip-address-goes-here', user: 'deploy-user', roles: %w{app web db}

Sending email in production in Rails apps

In controller:

PurchaseNotifierMailer.send_purchase_confirmation_email(@user).deliver!

In production.rb:

config.action_mailer.smtp_settings = {
  user_name: 'sendgridusername',
  password: 'sendgridpassword',
  domain: 'yourdomain.com',
  address: 'smtp.sendgrid.net',
  port: 587,
  authentication: :plain,
  enable_starttls_auto: true
}

Automatically Signin a User

sign_in(:user, @user)

Device Finger Printing





Thursday, June 28, 2018

Errata for Articles on www.rubyplus.com

DK Smith has offered me his time to point out some errors, spelling mistakes etc. This page will document his findings.

Saturday, June 23, 2018

Linode Box Images










git prompts for passphrase after mac os upgrade

Solution
  1. Create (or edit if it exists) the following ~/.ssh/config file:
    Host *
      UseKeychain yes
      AddKeysToAgent yes
      IdentityFile ~/.ssh/id_rsa
  2. eval "$(ssh-agent -s)" 
  3. ssh-add -K ~/.ssh/id_rsa

Installing Rugged on Mac OS

Check if Mac is 64 bit: 

getconf LONG_BIT

ERROR: CMake is required to build Rugged
cat /Users/bparanj/.rvm/gems/ruby-2.3.1@headache/extensions/x86_64-darwin-17/2.3.0/rugged-0.25.1.1/gem_make.out
ERROR: CMake is required to build Rugged.
brew install cmake

Must be superuser to create this extension.

ALTER ROLE SUPERUSER;

createuser --superuser postgres2

gpg: keyserver receive failed: No route to host

Solution:

gpg-connect-agent --dirmngr 'keyserver --hosttable'

BYE

gpg --keyserver hkp://b4ckbone.de --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3 7D2BAF1CF37B13E2069D6956105BD0E739499BDB

Friday, June 22, 2018

When to Apply Memoization

Apply memoization, when two conditions are met:

1. Optimal sub structure
2. Overlapping sub problems

Tuesday, June 19, 2018

Make sure that `gem install libv8 -v '3.16.14.19' --source 'https://rubygems.org/'` succeeds before bundling.

This happened on Mac OS 10.10.5. I needed a specific version of libv8, so I used the -v flag in gem install.

Resolution


gem install libv8 -v 3.16.14.19 -- --with-system-v8
bundle config build.libv8 --with-system-v8


Monday, June 18, 2018

SSL Notes

git clone https://github.com/letsencrypt/letsencrypt
cd letsencrypt
./letsencrypt-auto --apache --rsa-key-size 4096


./letsencrypt-auto --apache -d example.com -d www.example.com -d foo.example.com -d bar.example.com -d baz.example.com


SSL with Let's Encrypt in Apache

Monday, April 23, 2018

Skill vs Challenge

When you work on improving your coding skill, be aware that you will experience these feelings that depends on your current skill level and the challenge level of the problem. Our goal is to be able to take on high challenges at a high skill level so that we can experience the Flow.