From 8e98d41aa3e656637b8750d408fa5f120287f382 Mon Sep 17 00:00:00 2001 From: Tobi1246 Date: Thu, 5 Oct 2023 17:58:59 +0300 Subject: [PATCH 1/3] task --- .gitignore | 1 + app/controllers/tests_controller.rb | 6 ++++ app/views/tests/index.html.erb | 5 +++ app/views/tests/show.html.erb | 11 +++++++ config.ru | 2 ++ config/environment.rb | 1 + config/routes.rb | 1 + db/test_guru.sqlite | Bin 12288 -> 12288 bytes lib/simpler/application.rb | 18 +++++++++-- lib/simpler/controller.rb | 32 +++++++++++++++++-- lib/simpler/router.rb | 19 ++++++++++-- lib/simpler/router/route.rb | 46 +++++++++++++++++++++++++++- lib/simpler/view.rb | 11 +++++-- middleware/logger.rb | 31 +++++++++++++++++++ 14 files changed, 172 insertions(+), 12 deletions(-) create mode 100644 .gitignore create mode 100644 app/views/tests/show.html.erb create mode 100644 middleware/logger.rb diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..ba91883d --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +log/app.log diff --git a/app/controllers/tests_controller.rb b/app/controllers/tests_controller.rb index 1526a689..d71f6eaa 100644 --- a/app/controllers/tests_controller.rb +++ b/app/controllers/tests_controller.rb @@ -2,10 +2,16 @@ class TestsController < Simpler::Controller def index @time = Time.now + @tests = Test.all end def create + render plain: "Test create!" + end + def show + @test = Test.find(params[:id]) + @id = params[:id] end end diff --git a/app/views/tests/index.html.erb b/app/views/tests/index.html.erb index 39fce580..ad52ab43 100644 --- a/app/views/tests/index.html.erb +++ b/app/views/tests/index.html.erb @@ -8,5 +8,10 @@

Simpler framework at work!

<%= @time %>

+ \ No newline at end of file diff --git a/app/views/tests/show.html.erb b/app/views/tests/show.html.erb new file mode 100644 index 00000000..f09cf727 --- /dev/null +++ b/app/views/tests/show.html.erb @@ -0,0 +1,11 @@ + + + + + Show | Simpler application + + +

Simpler framework at work!

+

<%= @id %>

+ + diff --git a/config.ru b/config.ru index 3060cc20..213519bb 100644 --- a/config.ru +++ b/config.ru @@ -1,3 +1,5 @@ require_relative 'config/environment' +require_relative 'middleware/logger' +use AppLogger, logdev: File.expand_path('log/app.log', __dir__) run Simpler.application diff --git a/config/environment.rb b/config/environment.rb index 7a0d38c3..e4c2c71f 100644 --- a/config/environment.rb +++ b/config/environment.rb @@ -1,3 +1,4 @@ +require 'rack' require_relative '../lib/simpler' Simpler.application.bootstrap! diff --git a/config/routes.rb b/config/routes.rb index 4a751251..da59b495 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1,4 +1,5 @@ Simpler.application.routes do get '/tests', 'tests#index' + get '/tests/:id', 'tests#show' post '/tests', 'tests#create' end diff --git a/db/test_guru.sqlite b/db/test_guru.sqlite index 8624a03ab149d27f007f699649e9822c446f66e1..e09e2f3b7c7cbbe27e5a5b3177753f317ad5f807 100644 GIT binary patch delta 70 zcmZojXh@hK&B!rP##xYqK`-qUF9QPu6Tc7xe+s|QW<`NTe2azn8JYMe0@)4x0>bJX ZL8VER3Qno%nR$7sMVpt%M+-2r0RTjI5mW#G delta 50 zcmZojXh@hK&B!)U##xY!K~LfYF9QPu6Tc7xe+s|QW<`NTe2azn88-_mOyb|XL_S)8 Gkre 'text/plain' }, + ['404 page is not faund'] + ] + end + def require_app Dir["#{Simpler.root}/app/**/*.rb"].each { |file| require file } end diff --git a/lib/simpler/controller.rb b/lib/simpler/controller.rb index 9383b035..858317e6 100644 --- a/lib/simpler/controller.rb +++ b/lib/simpler/controller.rb @@ -14,6 +14,7 @@ def initialize(env) def make_response(action) @request.env['simpler.controller'] = self @request.env['simpler.action'] = action + @request.env['simpler.handler'] = "#{self.class.name}##{action}" set_default_headers send(action) @@ -22,14 +23,34 @@ def make_response(action) @response.finish end + def params + @params = route_info.merge! + end + + def request_params + @request.params + end + + def route_info + @request.env['simpler.route_info'] + end + private + def headers(content_type, type) + @response[content_type] = type + end + + def status(code) + @response.status = code + end + def extract_name self.class.name.match('(?.+)Controller')[:name].downcase end def set_default_headers - @response['Content-Type'] = 'text/html' + @response['Content-Type'] ||= 'text/html' end def write_response @@ -42,11 +63,16 @@ def render_body View.new(@request.env).render(binding) end - def params - @request.params + def redirect_to(uri) + [302, { "Location" => uri }, []] end + + def render(template) + if Hash(template)[:plain] + @response['Content-Type'] = 'text/plain' + end @request.env['simpler.template'] = template end diff --git a/lib/simpler/router.rb b/lib/simpler/router.rb index 14b3415c..691ff6e6 100644 --- a/lib/simpler/router.rb +++ b/lib/simpler/router.rb @@ -19,20 +19,35 @@ def route_for(env) method = env['REQUEST_METHOD'].downcase.to_sym path = env['PATH_INFO'] - @routes.find { |route| route.match?(method, path) } - end + route = @routes.find { |route| route.match?(method, path) } + env['simpler.route_info'] = route.route_info(env) if route + route + end private def add_route(method, path, route_point) + route_point = route_point.split('#') controller = controller_from_string(route_point[0]) action = route_point[1] + route = Route.new(method, path, controller, action) @routes.push(route) + end + def controller_name + "#{route_info[:resource].capitalize}Controller" + end + + def controller_class + Object.const_get(controller_name) + rescue NameError + nil + end + def controller_from_string(controller_name) Object.const_get("#{controller_name.capitalize}Controller") end diff --git a/lib/simpler/router/route.rb b/lib/simpler/router/route.rb index 4c66b4b7..7aabc9f2 100644 --- a/lib/simpler/router/route.rb +++ b/lib/simpler/router/route.rb @@ -9,12 +9,56 @@ def initialize(method, path, controller, action) @path = path @controller = controller @action = action + @path_regexp = make_path_regexp end def match?(method, path) - @method == method && path.match(@path) + @method == method && match_path(path) end + def route_info(env) + path = env['PATH_INFO'] + @route_info ||= begin + resource = path_fragments(path)[0] || "base" + id, action = find_id_and_action(path_fragments(path)[1]) + { resource: resource, action: action, id: id } + end + end + + def find_id_and_action(fragment) + case fragment + when "new" + [nil, :new] + when nil + action = @request.get? ? :index : :create + [nil, action] + else + [fragment, :show] + end + end + + def match_path(path) + path.match(@path_regexp) + end + + def make_path_regexp + path_parts = @path.split('/') + path_parts.map! do |part| + if part[0] == ":" + part.delete!(':') + part = "(?<#{part}>\\w+)" + else + part + end + end + str_regexp = path_parts.join("\\/") + /#{str_regexp}$/ + end + + def path_fragments(path) + @fragments ||= path.split("/").reject { |s| s.empty? } + end + end end end diff --git a/lib/simpler/view.rb b/lib/simpler/view.rb index 19a73b34..ba0fd8ad 100644 --- a/lib/simpler/view.rb +++ b/lib/simpler/view.rb @@ -10,9 +10,14 @@ def initialize(env) end def render(binding) - template = File.read(template_path) - - ERB.new(template).result(binding) + plain = Hash(template)[:plain] + if plain + "#{plain}\n" + else + template = File.read(template_path) + + ERB.new(template).result(binding) + end end private diff --git a/middleware/logger.rb b/middleware/logger.rb new file mode 100644 index 00000000..8fe2a755 --- /dev/null +++ b/middleware/logger.rb @@ -0,0 +1,31 @@ +require 'logger' + +class AppLogger + + def initialize(app, **options) + @logger = Logger.new(options[:logdev] || STROUT) + @app = app + end + + def call(env) + request_line = "\nRequest: #{env["REQUEST_METHOD"]} " + request_line << env["PATH_INFO"] + request_line << "/?#{env["QUERY_STRING"]}" unless env["QUERY_STRING"].empty? + @logger.info request_line + + status, headers, body = @app.call(env) + + if env['simpler.controller'] + @logger.info "\nParameters: #{env['simpler.controller'].params}" + end + @logger.info "\nHandler: #{env['simpler.handler']}" + + response_line = "\nResponse: #{status} " + response_line << "[#{headers['Content-Type']}]" + response_line << " #{env['simpler.template']}" + @logger.info response_line + + [status, headers, body] + end + +end From 3c3c39d73432fef0a8b5dbfea436f0b24aab4fe1 Mon Sep 17 00:00:00 2001 From: Tobi1246 Date: Thu, 5 Oct 2023 18:03:46 +0300 Subject: [PATCH 2/3] readme --- README.md | 34 ++++++++++++++++++++++++++++++---- app/views/tests/index.html.erb | 2 +- app/views/tests/list.html.erb | 2 +- lib/simpler/controller.rb | 2 -- 4 files changed, 32 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index e9b8235c..5775ad51 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,33 @@ -# Simpler +Создайте на гитхабе форк учебного проекта из скринкаста (ссылки в дополнительных материалах), в полученном новом репозитории, в новой ветке выполните следующие задания: -**Simpler** is a little web framework written in [Ruby](https://www.ruby-lang.org) language. It's compatible with [Rack](https://rack.github.io) interface and intended to **learn** how web frameworks work in general. +Реализуйте расширенные возможности метода render которые позволят возвращать ответ в других форматах, например: +render plain: "Plain text response" + +Реализуйте возможность устанавливать в методе контроллера статус ответа, например: +status 201 + +Реализуйте возможность устанавливать в методе контроллера заголовки, например: +headers['Content-Type'] = 'text/plain' + +Реализуйте механизм обработки исключения когда маршрут для запрашиваемого URL не был найден. В этом случае клиенту должен отдаваться ответ со статусом 404 -## The application overview -Simpler application is a singleton instance of the `Simpler::Application` class. For convenience it can be obtained by calling `Simpler.application` method. This instance holds all the routes and responds to `call` method which is required by the Rack interface. +Напишите механизм разбора route-параметров. Например, при добавлении маршрута +get '/tests/:id', 'tests#show' + + а) Маршрут должен корректно обрабатывать GET запрос +/tests/101 + + b) В методе show контроллера при вызове метода params должен быть доступен параметр :id со значением 101 + +Напишите middleware для логирования HTTP-запросов и ответов: + a) Лог должен записываться в файл log/app.log + b) Для запросов необходимо записывать HTTP-метод запроса, URL, контроллер и метод который будет обрабатывать запрос, хэш параметров который будет доступен при вызове метода params + c) Для ответов необходимо записывать код статуса ответа, тип тела ответа и название шаблона (если ответ рендерился с помощью шаблона представления) + +Пример: + +Request: GET /tests?category=Backend +Handler: TestsController#index +Parameters: {'category' => 'Backend'} +Response: 200 OK [text/html] tests/index.html.erb diff --git a/app/views/tests/index.html.erb b/app/views/tests/index.html.erb index ad52ab43..7ef02c33 100644 --- a/app/views/tests/index.html.erb +++ b/app/views/tests/index.html.erb @@ -14,4 +14,4 @@ <% end %> - \ No newline at end of file + diff --git a/app/views/tests/list.html.erb b/app/views/tests/list.html.erb index 0d430491..33894ed7 100644 --- a/app/views/tests/list.html.erb +++ b/app/views/tests/list.html.erb @@ -9,4 +9,4 @@

<%= @time %>

- \ No newline at end of file + diff --git a/lib/simpler/controller.rb b/lib/simpler/controller.rb index 858317e6..0d68893f 100644 --- a/lib/simpler/controller.rb +++ b/lib/simpler/controller.rb @@ -67,8 +67,6 @@ def redirect_to(uri) [302, { "Location" => uri }, []] end - - def render(template) if Hash(template)[:plain] @response['Content-Type'] = 'text/plain' From 2d9fbb6fefecb8527d4d560352397718a2abb913 Mon Sep 17 00:00:00 2001 From: Tobi1246 Date: Wed, 11 Oct 2023 16:03:44 +0300 Subject: [PATCH 3/3] fix --- app/controllers/tests_controller.rb | 1 - lib/simpler/controller.rb | 2 +- lib/simpler/router/route.rb | 5 +---- 3 files changed, 2 insertions(+), 6 deletions(-) diff --git a/app/controllers/tests_controller.rb b/app/controllers/tests_controller.rb index d71f6eaa..30031d17 100644 --- a/app/controllers/tests_controller.rb +++ b/app/controllers/tests_controller.rb @@ -10,7 +10,6 @@ def create end def show - @test = Test.find(params[:id]) @id = params[:id] end diff --git a/lib/simpler/controller.rb b/lib/simpler/controller.rb index 0d68893f..f2714374 100644 --- a/lib/simpler/controller.rb +++ b/lib/simpler/controller.rb @@ -24,7 +24,7 @@ def make_response(action) end def params - @params = route_info.merge! + @params ||= route_info.merge(request_params) end def request_params diff --git a/lib/simpler/router/route.rb b/lib/simpler/router/route.rb index 7aabc9f2..121be64e 100644 --- a/lib/simpler/router/route.rb +++ b/lib/simpler/router/route.rb @@ -29,9 +29,6 @@ def find_id_and_action(fragment) case fragment when "new" [nil, :new] - when nil - action = @request.get? ? :index : :create - [nil, action] else [fragment, :show] end @@ -54,7 +51,7 @@ def make_path_regexp str_regexp = path_parts.join("\\/") /#{str_regexp}$/ end - + def path_fragments(path) @fragments ||= path.split("/").reject { |s| s.empty? } end