From c67686d7d7a9a9e3cd5efa4034ac5cc193f2676c Mon Sep 17 00:00:00 2001 From: Nicholas Van Doorn Date: Sat, 17 Jul 2021 17:13:52 -0700 Subject: Initial commit --- .ruby-version | 1 + Gemfile | 11 ++++++ Gemfile.lock | 41 +++++++++++++++++++++ Procfile | 1 + app/application.rb | 21 +++++++++++ app/controllers/application_controller.rb | 11 ++++++ app/controllers/home_controller.rb | 13 +++++++ app/views/home/index.html.erb | 1 + config.ru | 4 +++ lib/router.rb | 60 +++++++++++++++++++++++++++++++ lib/spec.rb | 45 +++++++++++++++++++++++ spec/lib/router_spec.rb | 16 +++++++++ 12 files changed, 225 insertions(+) create mode 100644 .ruby-version create mode 100644 Gemfile create mode 100644 Gemfile.lock create mode 100644 Procfile create mode 100644 app/application.rb create mode 100644 app/controllers/application_controller.rb create mode 100644 app/controllers/home_controller.rb create mode 100644 app/views/home/index.html.erb create mode 100644 config.ru create mode 100644 lib/router.rb create mode 100644 lib/spec.rb create mode 100644 spec/lib/router_spec.rb diff --git a/.ruby-version b/.ruby-version new file mode 100644 index 0000000..a4dd9db --- /dev/null +++ b/.ruby-version @@ -0,0 +1 @@ +2.7.4 diff --git a/Gemfile b/Gemfile new file mode 100644 index 0000000..c2a2df8 --- /dev/null +++ b/Gemfile @@ -0,0 +1,11 @@ +# frozen_string_literal: true + +source "https://rubygems.org" +ruby "2.7.4" + +git_source(:github) {|repo_name| "https://github.com/#{repo_name}" } + +gem "rack", "~> 2.2" +gem "puma", "~> 5.3" +gem "rspec", "~> 3.10" +gem "pry", "~> 0.14.1" diff --git a/Gemfile.lock b/Gemfile.lock new file mode 100644 index 0000000..ae0b60e --- /dev/null +++ b/Gemfile.lock @@ -0,0 +1,41 @@ +GEM + remote: https://rubygems.org/ + specs: + coderay (1.1.3) + diff-lcs (1.4.4) + method_source (1.0.0) + nio4r (2.5.7) + pry (0.14.1) + coderay (~> 1.1) + method_source (~> 1.0) + puma (5.3.2) + nio4r (~> 2.0) + rack (2.2.3) + rspec (3.10.0) + rspec-core (~> 3.10.0) + rspec-expectations (~> 3.10.0) + rspec-mocks (~> 3.10.0) + rspec-core (3.10.1) + rspec-support (~> 3.10.0) + rspec-expectations (3.10.1) + diff-lcs (>= 1.2.0, < 2.0) + rspec-support (~> 3.10.0) + rspec-mocks (3.10.2) + diff-lcs (>= 1.2.0, < 2.0) + rspec-support (~> 3.10.0) + rspec-support (3.10.2) + +PLATFORMS + ruby + +DEPENDENCIES + pry (~> 0.14.1) + puma (~> 5.3) + rack (~> 2.2) + rspec (~> 3.10) + +RUBY VERSION + ruby 2.7.4p191 + +BUNDLED WITH + 2.1.4 diff --git a/Procfile b/Procfile new file mode 100644 index 0000000..c3936b2 --- /dev/null +++ b/Procfile @@ -0,0 +1 @@ +web: bundle exec rackup -p $PORT diff --git a/app/application.rb b/app/application.rb new file mode 100644 index 0000000..595ff5b --- /dev/null +++ b/app/application.rb @@ -0,0 +1,21 @@ +require './lib/router' +require './app/controllers/home_controller' + +class Application + def initialize + @router = Router.new + end + + attr_reader :router + + def home_controller + HomeController.new + end + + def call(env) + router.get("/") do |params| + home_controller.index(params) + end + router.call(env) + end +end diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb new file mode 100644 index 0000000..e1b2210 --- /dev/null +++ b/app/controllers/application_controller.rb @@ -0,0 +1,11 @@ +class ApplicationController + def render(action_name) + html = File.open("./app/views/#{controller_namespace.to_s}/#{action_name.to_s}.html.erb").read + template = ERB.new(html) + template.result(binding) + end + + def controller_namespace + '/' + end +end diff --git a/app/controllers/home_controller.rb b/app/controllers/home_controller.rb new file mode 100644 index 0000000..bb2a178 --- /dev/null +++ b/app/controllers/home_controller.rb @@ -0,0 +1,13 @@ +require 'erb' +require "./app/controllers/application_controller" + +class HomeController < ApplicationController + def index(params) + @time = Time.now.to_s + render :index + end + + def controller_namespace + :home + end +end diff --git a/app/views/home/index.html.erb b/app/views/home/index.html.erb new file mode 100644 index 0000000..4f9f70f --- /dev/null +++ b/app/views/home/index.html.erb @@ -0,0 +1 @@ +

<%= @time %>

diff --git a/config.ru b/config.ru new file mode 100644 index 0000000..1d1b31a --- /dev/null +++ b/config.ru @@ -0,0 +1,4 @@ +require './app/application' + +use(Rack::Reloader, 0) +run(Application.new) diff --git a/lib/router.rb b/lib/router.rb new file mode 100644 index 0000000..3597dfd --- /dev/null +++ b/lib/router.rb @@ -0,0 +1,60 @@ +require 'pry' + +class Router + def initialize + @routes = [] + end + + def call(env) + path = env["REQUEST_PATH"] + method = env["REQUEST_METHOD"] + @routes.each do |route| + next if method != route[:method] + params = match_route(path, route[:path]) + if params + return respond_html(route[:block].call(params)) + end + end + respond_html("not found", status: 404) + end + + def match_route(incoming_path, path) + params = {} + incoming_parts = incoming_path.split("/") + path_parts = path.split("/") + + incoming_parts.each_with_index do |incoming_part, index| + path_part = path_parts[index] + if path_part&.start_with?(":") + params[path_part[1..-1]] = incoming_part + else + if path_part != incoming_part + return false + end + end + end + params + end + + def get(path, &block) + @routes.push({ method: "GET", path: path, block: block }) + end + + def post(path, &block) + @routes.push({ method: "POST", path: path, block: block }) + end + + def put(path, &block) + @routes.push({ method: "PUT", path: path, block: block }) + end + + def delete(path, &block) + @routes.push({ method: "DELETE", path: path, block: block }) + end + + private + + def respond_html(content, status: 200) + [status, {'Content-Type' => 'text/html'}, [content]] + end +end diff --git a/lib/spec.rb b/lib/spec.rb new file mode 100644 index 0000000..d9c7d96 --- /dev/null +++ b/lib/spec.rb @@ -0,0 +1,45 @@ +class Spec + class << self + @@contexts = [] + + def context(description, &block) + @@contexts.push({ description: description, block: block }) + end + + def expect(value) + Result.new(value) + end + + def eq(value) + Proc.new do |actual| + if actual != value + raise AssertionError.new("Expected #{value.to_s}, got #{actual.to_s}") + end + end + end + + def call + @@contexts.each do |context| + puts name + puts " #{context[:description]}" + context[:block].call + end + end + end + + class Result + def initialize(value) + @value = value + end + + attr_reader :value + + def to(matcher) + matcher.call(value) + puts " Passed!" + end + end + + class AssertionError < RuntimeError + end +end diff --git a/spec/lib/router_spec.rb b/spec/lib/router_spec.rb new file mode 100644 index 0000000..ef56c97 --- /dev/null +++ b/spec/lib/router_spec.rb @@ -0,0 +1,16 @@ +require './lib/spec' +require './lib/router' + +class RouterSpec < Spec + context "#call" do + router = Router.new + env = { "REQUEST_PATH" => "/home/5", "REQUEST_METHOD" => "GET" } + router.get("/home/:id") do |params| + "test content 5" + end + + expect(router.call(env)).to eq [200, {"Content-Type"=>"text/html"}, ["test content 5"]] + end + + call +end -- cgit v1.2.3