Things I learned when studying Sinatra

Reading time ~5 minutes

HTTP

HTTP is a protocol that is allowed you to communicate with other people(computer) through this protocol. Therefore, you have to obey some rules. And every computer has an ip address , but it is difficult for us to remember. Here comes DNS , domain naming system. You can built your own DNS server or use your internet supplier or Google’s server. It can help you to transform naming address to ip address then the computer know where to go. for example, you type in www.google.com, then it will sent to DNS server to identify where the ip address is.

client and server

All websites are built on the server. every computer can be a server. We use the browser to send request to server then it send back to us wiht some response. All the response may includes files, images, web pages. There are name with resources. request needs method and path. header and body are optional. response with status code is required. header and body are optional.

Stateless

server can not deal with lots of states coming from the client; therefore, all the Internet are agreed to use stateless way to handle the data. Everytime client sending request with server back with response is individual. It will sent back all the information we need to do next round to the clients, if the client make some change, then next time, the response will send back the following change to the client. In short, server keeps no information about these state.

URL, uniform resource locator

http://www.example.com:88/home?item=book

  • http is scheme, a protocol
  • www.example.com is host
  • 88 is port
  • /home is the path
  • ?item=book is query parameters

Some thought on Sinatra

What is reloader?

sinatra/reloader is part of Sinatra::Contrib project . It helps user to quick reload pages while developing.

Useful during development, since it will automatically require files defining routes, filters, error handlers and inline templates, with every incoming request, but only if they have been updated.

  require "sinatra"
  require "sinatra/reloader" if development?

  # Your classic application code goes here...

wat is Tilt?

  • It is an all-inclusive wrapper gem for Ruby template engine, you can view its github page.

  • In the [Erubis User guide](http://www.kuwata-lab.com/erubis/users-guide.html) lists its benefits:
    • Very fast, almost three times faster than ERB and about ten percent faster than eruby (implemented in C)
    • File caching of converted Ruby script support
    • Auto escaping support, etc.
  • So use require tilt/erubis will render much faster than built-in erb.

Partition method and Taking block explicitly

In the course of understanding Sinatra. I learn some new method in this course.

  1. understand Enumerable::partition

  2. understand &block and yield

Although it is the previous course. But there is no enough true example. Only some exercise. So I think it is a good way to practice here.

yield to the block, passing in the current element to the block . Inside the method, The yield keyword executes the block.

  • yield with an argument:

execution is yielded to the block (or the block is called), and we’re passing argument to the block.

Every method, regardless of its method definition, takes an implicit block (though, it may just ignore the implicit block). Sometimes, you’ll want to implement a method that explicitly takes a block.

At first, I am a little confused with &block. If method in Ruby can take block implicitly, why we have to do it with &block ? Until I was working with this project, then I understand the reason why we have to sometimes take block explicitly. This one is very good example that we do have to take block explicitly.

  # partition { |obj| block } → [ true_array, false_array ]
  # partition → an_enumerator

  # Returns two arrays, the first containing the elements of enum for which the block evaluates to true, the second containing the rest.

  # If no block is given, an enumerator is returned instead.

  (1..6).partition { |v| v.even? }  #=> [[2, 4, 6], [1, 3, 5]]
  <ul id="lists">
     <% sort_lists @lists do |list, index| %>
         <li class="<%= list_class(list)%>">
             <a href="/lists/<%= index %>">
                 <h2><%= list[:name] %></h2>
                 <p>
                     <%= todos_remaining_count(list) %> / <%= todos_count(list) %>
                 </p>
             </a>
         </li>
     <% end %>
  </ul>
  • Before using Ruby built-in function partition:
  def sort_lists(list, &block)
    incomplete_lists = {}
    complete_lists = {}

    lists.each_with_index do |list, index| 
      if list_complete?(list)
        complete_lists[list] = index
      else
        incomplete_lists[list] = index
      end

      incomplete_lists.each(&block)
      complete_lists.each(&block)
    end
  end
  • After using partition method:
  def sort_lists(lists, &block)
    complete_list, incomplete_list = lists.partition { |list| list_complete?(list) }
    complete_list.each { |list| yield(list, lists.index(list)) }
    incomplete_list.each { |list| yield(list, lists.index(list)) }
  end

Reading YAML

Ruby versions >= 2.0 have a new YAML implementation provided by a library called Psych. When you require “yaml” to load the YAML object, you are actually getting a handle on Psych

Writing Sinatra in OOP way

for example:

  # my_app.rb
  require 'sinatra/base'
  require 'sinatra/some_helpers'

  class MyApp < Sinatra::Base
    helpers Sinatra::SomeHelpers

    ...

  end

When to use config.ru?

from the Readme Page in Sinatra Documentation:

A config.ru file is recommended if:

  • You want to deploy with a different Rack handler (Passenger, Unicorn, Heroku, …).
  • You want to use more than one subclass of Sinatra::Base.
  • You want to use Sinatra only for middleware, and not as an endpoint.

There is no need to switch to a config.ru simply because you switched to the modular style, and you don’t have to use the modular style for running with a config.ru.

Understand Rack

What is Rack[fn:3]?

Rack is the HTTP interface for Ruby. Rack defines a standard interface for interacting with HTTP and connecting web servers[1]

To get started, all you need is an object that responds to a call method, taking in an environment hash and returning an Array with the HTTP response code, headers, and response body[2]

What is Middleware?

A middleware component sits between the client and the server, processing inbound requests and outbound responses.[3]

Understand Files and Directory

explain the expand_path

this will give you the absolute address of the file


  path = File.expand_path("../public", __FILE__)
  # => "/home/scipio/index/public" 
  path = File.expand_path("../public")
  # => "/home/scipio/public" 

explain the glob

  1. Dir.[] is the same as Dir.glob. If we want to show all the files include the hidden files, we use Dir.entries. If you don’t want the hidden files, using Dir.glob. glob you have to setup the pattern you want. For example, here, we want ALL the files with *. if we want all the ruby file, we should use *.rb
  rbfiles = File.join("**", "*.rb")
  Dir.glob(rbfiles)                   #=> ["main.rb",
                                      #    "lib/song.rb",
                                      #    "lib/song/karaoke.rb"]
  1. File.file? return true if it is a file, and you have to give the absoulute address. File.directory? will return true, if is directory.
  2. File.basename will return the basename of the file.
  Dir.entries(path)
  # => ["chp12.txt", "chp1.txt", "chp11.txt", "toc.txt", "..", "chp5.txt", ".", "chp6.txt", "chp10.txt", "chp2.txt", "chp7.txt", "chp9.txt", "chp3.txt", "chp4.txt", "chp8.txt"] 

  Dir.entries(path).select {|f| !File.directory? f}
  # => ["chp12.txt", "chp1.txt", "chp11.txt", "toc.txt", "chp5.txt", "chp6.txt", "chp10.txt", "chp2.txt", "chp7.txt", "chp9.txt", "chp3.txt", "chp4.txt", "chp8.txt"] 

  Dir[path]

  Dir.glob(path + "/*").select {|f| File.file? f}
  # => ["/home/scipio/ls-pratice/index/public/chp12.txt", "/home/scipio/ls-pratice/index/public/chp1.txt", "/home/scipio/ls-pratice/index/public/chp11.txt", "/home/scipio/ls-pratice/index/public/toc.txt", "/home/scipio/ls-pratice/index/public/chp5.txt", "/home/scipio/ls-pratice/index/public/chp6.txt", "/home/scipio/ls-pratice/index/public/chp10.txt", "/home/scipio/ls-pratice/index/public/chp2.txt", "/home/scipio/ls-pratice/index/public/chp7.txt", "/home/scipio/ls-pratice/index/public/chp9.txt", "/home/scipio/ls-pratice/index/public/chp3.txt", "/home/scipio/ls-pratice/index/public/chp4.txt", "/home/scipio/ls-pratice/index/public/chp8.txt"]

  Dir.glob(path + "/*").select {|f| File.file? f}.map{ |f| File.basename(f) }
  # => ["chp12.txt", "chp1.txt", "chp11.txt", "toc.txt", "chp5.txt", "chp6.txt", "chp10.txt", "chp2.txt", "chp7.txt", "chp9.txt", "chp3.txt", "chp4.txt", "chp8.txt"] 

[1] http://hawkins.io/2012/07/rack_from_the_beginning/

[2] https://blog.engineyard.com/2015/understanding-rack-apps-and-middleware

[3] https://blog.engineyard.com/2015/understanding-rack-apps-and-middleware

to_param in Ruby on Rails

If I want a custom slug=======================I walk through this cutstom slug.1. create migration `add_slug` to add a column inside the...… Continue reading

What is ORM in Rails mean?

Published on July 14, 2017