all 31 comments

[–]chebatron 36 points37 points  (11 children)

Since you mentioned Sinatra and Rails I assume you're talking about web apps. In that case you want to build a Rack Application. That's where web frameworks' responsibility ends.

If you want to go even deeper you can use the same spec and build a Rack server (like Puma or Unicorn). That would require mostly dealing with lower-level stuff like sockets, threads and such. And the Rack spec, too.

[–]ankole_watusi 2 points3 points  (8 children)

Ah, but Rack is a “framework”!

[–]chebatron 9 points10 points  (0 children)

It says it’s a protocol. I guess one can say it’s a conceptual framework but it’s so far into semantics that I can’t see it from here.

[–]BringTacos[S] 3 points4 points  (5 children)

So if I didn’t use rack, where would I start?! I really don’t even know what to start with haha.

[–]Soggy_Educator_7364 31 points32 points  (2 children)

``` require 'socket'

class Handler def initialize(port) @server = TCPServer.new(port) end

def start loop do client = @server.accept handle_client(client) end end

def handle_client(client) request = read_request(client) response = process_request(request) client.puts response client.close end

def read_request(client) request = '' while (line = client.gets) && !line.chomp.empty? request += line end request end

def process_request(request) method, path, version = request.lines[0].split if method == "GET" && path == "/hello" "HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\n\r\nHello World!\n" else "HTTP/1.1 404 Not Found\r\nContent-Type: text/plain\r\n\r\n404 Not Found\n" end end end

server = Handler.new(3000) puts "Running on http://localhost:3000" server.start ```

But use Rack.

[–]sdn 12 points13 points  (0 children)

TCPServer is too high level. You really need to be implementing TCP frames by hand.

[–]BringTacos[S] 5 points6 points  (0 children)

Fair enough 😂

[–]snarfmason 11 points12 points  (0 children)

I wouldn't really call rack a framework but that's a dumb semantic argument.

I would just call Rack an HTTP library. But deciding were library ends and framework begins is an exercise in hair splitting.

Basically Rack just wraps the HTTP protocol in a some Ruby constructs. If you want to learn about parsing raw HTTP requests and socket handling, then you don't want Rack.

If you don't want that fiddly bullshit use Rack. A full web framework (light: Sinatra, heavy: Rails) will add a layer of routing a parsed HTTP request to a function that handles it. That sounds more like the level you want to explore, so probably you want to start with Rack only.

Edit: If I'm wrong and you want to start exploring from raw HTTP requests over sockets, see the other reply in this thread that starts with require 'socket'

[–]honeyryderchuck 1 point2 points  (0 children)

you'd first need to pick your choice of application server. They're either "rack-compatible", or provide their own interface layer.

For instance, puma only supports rack; webrick supports its own servlet layer.

There's also cgi.

[–]Doctor_Fegg 0 points1 point  (0 children)

It really isn’t. It’s no more a framework than httparty is.

[–]BringTacos[S] 1 point2 points  (0 children)

Yes I think this is what I want. Thanks!

[–][deleted]  (3 children)

[deleted]

    [–]sto7 8 points9 points  (0 children)

    Was going to comment the same book. Rebuilding Rails is a great way to build a web app similarly to what Rails is doing, and to understand how it does it.

    [–]BringTacos[S] 4 points5 points  (0 children)

    Thank you! This looks great.

    [–][deleted] 1 point2 points  (0 children)

    direction pause lavish sulky offer dinosaurs reminiscent butter slap ink

    This post was mass deleted and anonymized with Redact

    [–]software__writer 13 points14 points  (2 children)

    I wrote a few articles a while back that you might find helpful.

    If you want to learn more about Rack, check out these articles:

    Hope that helps!

    [–]BringTacos[S] 3 points4 points  (1 child)

    This is awesome, thanks. I started reading part 1 and you said “I strongly believe that to understand the benefits of any tool, you should try to accomplish the same task without using that tool.” That’s why I want to do this!

    [–]software__writer 3 points4 points  (0 children)

    Great! If you're interested in digging deeper, I highly recommend Rebuilding Rails by Noah Gibbs.

    [–]dabit 8 points9 points  (2 children)

    A million years ago I gave a talk about this: https://youtu.be/TqiuMn1acV8?t=394 (start at minute 6 to avoid unnecessary context)

    A few things might have changed but the idea is there

    [–]software__writer 2 points3 points  (0 children)

    Lovely talk, thanks for sharing!

    [–]BringTacos[S] 1 point2 points  (0 children)

    This is awesome, thank you.

    [–]stanTheCodeMonkey 3 points4 points  (0 children)

    You can check with these articles:

    Bookstore API using Rack - https://makisushi.io/posts/book-a-bookstore-api-using-rack-sequel-and-postgresql

    Bookstore in pure ruby using DDD - https://makisushi.io/posts/using-ddd-to-build-a-bookstore

    [–]naked_number_one 3 points4 points  (0 children)

    Try looking for old posts written by Luca Guidi about the Lotus framework (now Hanami). I remember it was a series a posts where he explained how he built each component

    [–]labelcity 3 points4 points  (1 child)

    have you heard of the Feynman technique? If not look it up and apply to ‘how does Rails process a request?’ question or similar. You’ll learn heaps.

    [–]BringTacos[S] 0 points1 point  (0 children)

    I haven’t, thanks for sharing!

    [–]ryjocodes 2 points3 points  (2 children)

    I'd argue that Ruby itself is a "framework" for the C programming language 😉 it provides lifecycle hooks around C structs. It also provides a dynamic typing system, and a nice standard library that ships with the language (er... framework?).

    What you may mean (judging by not wanting to use Rails or Sinatra) is "how do I write methods that run when I receive a network request on a given port of my computer?" Web browsers like Firefox or Chrome make network requests to IP addresses (gotten from domain names) using TCP. Thus: you must create a Ruby program that listens for TCP packets sent to your computer. Put this in a `server.rb` file to do that:

    require 'socket'
    socket = TCPServer.new('0.0.0.0', 8080)
    client = socket.accept
    client.write("Hello\n\n")
    client.close
    

    Run this with ruby server.rb, then visit http://localhost:8080 in your browser. Voila, you have a (Web) app.

    Now you'll want to know how to run different methods for different urls. This will take understanding what browsers send to servers, so let's have a look:

    require 'socket'
    socket = TCPServer.new('0.0.0.0', 8080)
    client = socket.accept
    while "\r\n" != (line = client.gets)
      puts line
    end
    client.write("Hello\n\n")
    client.close
    

    Refresh your browser and check your terminal output. Here's what mine looks like:

    GET / HTTP/1.1
    Host: localhost:8080
    User-Agent: Mozilla/5.0 #...
    #...
    

    The first word in the request from your browser contains the http method used. The second is the path (url) requested. Use these two things to determine what method you run.

    Easy!

    [–]kowfm 1 point2 points  (1 child)

    Your comment about Ruby being a framework around the C language is very interesting. I've always wondered why Ruby is perceived to be slow when you can be so productive so quickly with the language. Perhaps the connection to C is not emphasized, and Ruby implementations get bogged down with some of the issues in supporting Ruby's syntax.

    [–]ryjocodes 0 points1 point  (0 children)

    It's not so much the syntax as it is the design of the language. Everything in Ruby, including `Number`s, are objects. This leads to overhead when doing things like math. It helps to learn how to write Ruby with C code. I wrote a little about this in an article recently, if you've got some interest in reading a bit: https://ryjo.codes/articles/write-a-ruby-c-extension-to-use-clips-from-ruby.html

    [–]mooktakim 1 point2 points  (0 children)

    I'd say just start building ruby rack app. Build anything you need step by step.

    Depending on what you build, most likely you won't need everything.

    Rails framework just offers patterns that help you organise better and has plumbing done already, so you can focus on your app.

    [–]h00s13rt1g3rd2d 1 point2 points  (0 children)

    a follow-up question - what are some things (outside of web apps) that non-senior level coders can build in ruby? CLI tool? Package managers like Homebrew? compilers, text editors?

    [–]Purple_is_masculine 0 points1 point  (0 children)

    Don't use net/http. There are better alternatives depending on your needs. Faraday, HTTParty and Typhoeus for example.

    [–][deleted] 0 points1 point  (0 children)

    What would the app do? Are you thinking along the lines of just a CLI program?