summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNicholas Van Doorn <vandoorn.nick@gmail.com>2021-07-17 17:13:52 -0700
committerNicholas Van Doorn <vandoorn.nick@gmail.com>2021-07-20 02:22:50 -0700
commitc67686d7d7a9a9e3cd5efa4034ac5cc193f2676c (patch)
tree0cbcd21ce6ca92c5d6fdd40e765286ae4440d84b
Initial commitHEADmain
-rw-r--r--.ruby-version1
-rw-r--r--Gemfile11
-rw-r--r--Gemfile.lock41
-rw-r--r--Procfile1
-rw-r--r--app/application.rb21
-rw-r--r--app/controllers/application_controller.rb11
-rw-r--r--app/controllers/home_controller.rb13
-rw-r--r--app/views/home/index.html.erb1
-rw-r--r--config.ru4
-rw-r--r--lib/router.rb60
-rw-r--r--lib/spec.rb45
-rw-r--r--spec/lib/router_spec.rb16
12 files changed, 225 insertions, 0 deletions
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 @@
+<h1><%= @time %></h1>
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