From f7ec6dcade405b5661c96897ad159bc3cad895d4 Mon Sep 17 00:00:00 2001 From: superedriver Date: Thu, 10 Nov 2016 17:48:35 +0200 Subject: [PATCH 01/10] Made home task #1 refactor --- hw1/fibonacci.rb | 24 ++++++++++++++++++++++++ hw2/Gemfile | 1 + hw2/Gemfile.lock | 8 ++++++++ hw2/app/app.rb | 1 + hw2/lib/router.rb | 13 +++++++++++-- hw2/main.rb | 1 + hw2/spec/lib/router_spec.rb | 30 ++++++++++++++++++++++++++++++ 7 files changed, 76 insertions(+), 2 deletions(-) diff --git a/hw1/fibonacci.rb b/hw1/fibonacci.rb index e69de29..2511830 100644 --- a/hw1/fibonacci.rb +++ b/hw1/fibonacci.rb @@ -0,0 +1,24 @@ +class Fibonacci + attr_reader :result_array + include Enumerable + + def each + result_array.each{ |item| yield item } + self + end + + private + + def initialize(length) + raise TypeError, "Expected argument to be Integer" unless [Fixnum, Bignum].include? length.class + raise ArgumentError, "Expected argument >= 1. Got #{length}" if length < 1 + + previous_item = next_item = 1 + @result_array = (1..length).inject([]) do |result| + result << previous_item + previous_item, next_item = next_item, previous_item + next_item += previous_item + result + end + end +end diff --git a/hw2/Gemfile b/hw2/Gemfile index f8bf844..404a782 100644 --- a/hw2/Gemfile +++ b/hw2/Gemfile @@ -3,3 +3,4 @@ source "https://rubygems.org" gem "rack" gem "rspec" +gem "pry" diff --git a/hw2/Gemfile.lock b/hw2/Gemfile.lock index ec73d13..ffd0352 100644 --- a/hw2/Gemfile.lock +++ b/hw2/Gemfile.lock @@ -1,7 +1,13 @@ GEM remote: https://rubygems.org/ specs: + coderay (1.1.1) diff-lcs (1.2.5) + method_source (0.8.2) + pry (0.10.4) + coderay (~> 1.1.0) + method_source (~> 0.8.1) + slop (~> 3.4) rack (2.0.1) rspec (3.5.0) rspec-core (~> 3.5.0) @@ -16,11 +22,13 @@ GEM diff-lcs (>= 1.2.0, < 2.0) rspec-support (~> 3.5.0) rspec-support (3.5.0) + slop (3.6.0) PLATFORMS ruby DEPENDENCIES + pry rack rspec diff --git a/hw2/app/app.rb b/hw2/app/app.rb index 2be87a8..7fd7f69 100644 --- a/hw2/app/app.rb +++ b/hw2/app/app.rb @@ -1,4 +1,5 @@ Application = Router.new do get '/test', ->(env) { [200, {}, ['get test']] } post '/test', ->(env) { [200, {}, ['post test']] } + get '/post/:name', ->(env) { [200, {}, ['post show page']] } end diff --git a/hw2/lib/router.rb b/hw2/lib/router.rb index eb6e53d..2210e28 100644 --- a/hw2/lib/router.rb +++ b/hw2/lib/router.rb @@ -1,6 +1,10 @@ class Router def call(env) - @routes[env['REQUEST_METHOD']][env['REQUEST_PATH']].call(env) + if nested_post? env + @routes[env['REQUEST_METHOD']]['/post/:name'].call(env) + else + @routes[env['REQUEST_METHOD']][env['REQUEST_PATH']].call(env) + end end private @@ -19,7 +23,12 @@ def post(path, rack_app) end def match(http_method, path, rack_app) - @routes[http_method] ||= {} + @routes[http_method] ||= Hash.new(->(env) { [404, {}, ['not found']] }) @routes[http_method][path] = rack_app end + + def nested_post?(env) + path_arr = env['REQUEST_PATH'][1..-1].split('/') + env['REQUEST_METHOD'] == 'GET' && path_arr.size == 2 && path_arr[0] == 'post' + end end diff --git a/hw2/main.rb b/hw2/main.rb index acfd4b3..0b84eca 100644 --- a/hw2/main.rb +++ b/hw2/main.rb @@ -1,2 +1,3 @@ require './lib/router' require './app/app' +require 'pry' diff --git a/hw2/spec/lib/router_spec.rb b/hw2/spec/lib/router_spec.rb index e53a275..5e742a4 100644 --- a/hw2/spec/lib/router_spec.rb +++ b/hw2/spec/lib/router_spec.rb @@ -19,14 +19,44 @@ context 'when request is GET' do let(:env) { { 'REQUEST_PATH' => '/test', 'REQUEST_METHOD' => 'GET'} } + it 'returns 404 error for missing path' do + expect(subject.call({ 'REQUEST_PATH' => '/not_found_path', 'REQUEST_METHOD' => 'GET'})).to eq [404, {}, ['not found']] + end + it 'matches request' do expect(subject.call(env)).to eq [200, {}, ['get test']] end + + context 'when request is nested "post"' do + it 'matches request if nested' do + env['REQUEST_PATH'] = '/post/some_string' + expect(subject.call(env)).to eq [200, {}, ['post show page']] + end + + it 'matches request if nested and ends on /' do + env['REQUEST_PATH'] = '/post/some_string/' + expect(subject.call(env)).to eq [200, {}, ['post show page']] + end + + it 'not matches request if deep nested post url' do + env['REQUEST_PATH'] = '/post/some_string/string' + expect(subject.call(env)).to eq [404, {}, ['not found']] + end + + it 'not matches request if url is not nested but "post"' do + env['REQUEST_PATH'] = '/post/' + expect(subject.call(env)).to eq [404, {}, ['not found']] + end + end end context 'when request is POST' do let(:env) { { 'REQUEST_PATH' => '/test', 'REQUEST_METHOD' => 'POST'} } + it 'returns 404 error for missing path' do + expect(subject.call({ 'REQUEST_PATH' => '/not_found_path', 'REQUEST_METHOD' => 'POST'})).to eq [404, {}, ['not found']] + end + it 'matches request' do expect(subject.call(env)).to eq [200, {}, ['post test']] end From 0db20ef3e470bb361c83cdb4990f0a0f00d86a85 Mon Sep 17 00:00:00 2001 From: superedriver Date: Thu, 10 Nov 2016 17:52:10 +0200 Subject: [PATCH 02/10] made the 2-nd hw --- .idea/kottans_2016_homeworks.iml | 14 + .idea/misc.xml | 4 + .idea/modules.xml | 8 + .idea/vcs.xml | 6 + .idea/workspace.xml | 614 +++++++++++++++++++++++++++++++ 5 files changed, 646 insertions(+) create mode 100644 .idea/kottans_2016_homeworks.iml create mode 100644 .idea/misc.xml create mode 100644 .idea/modules.xml create mode 100644 .idea/vcs.xml create mode 100644 .idea/workspace.xml diff --git a/.idea/kottans_2016_homeworks.iml b/.idea/kottans_2016_homeworks.iml new file mode 100644 index 0000000..3abe68e --- /dev/null +++ b/.idea/kottans_2016_homeworks.iml @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..918884f --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..5bdee32 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/workspace.xml b/.idea/workspace.xml new file mode 100644 index 0000000..77d87b4 --- /dev/null +++ b/.idea/workspace.xml @@ -0,0 +1,614 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + true + DEFINITION_ORDER + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + project + + + + + + + + + + + + + + + + + + + + + 1478503382746 + + + 1478536872543 + + + 1478600629291 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file From 638ba45a5530ee5882987b37673c12fa52051caa Mon Sep 17 00:00:00 2001 From: superedriver Date: Thu, 10 Nov 2016 17:57:13 +0200 Subject: [PATCH 03/10] made hw2 --- .idea/kottans_2016_homeworks.iml | 14 - .idea/misc.xml | 4 - .idea/modules.xml | 8 - .idea/vcs.xml | 6 - .idea/workspace.xml | 614 ------------------------------- 5 files changed, 646 deletions(-) delete mode 100644 .idea/kottans_2016_homeworks.iml delete mode 100644 .idea/misc.xml delete mode 100644 .idea/modules.xml delete mode 100644 .idea/vcs.xml delete mode 100644 .idea/workspace.xml diff --git a/.idea/kottans_2016_homeworks.iml b/.idea/kottans_2016_homeworks.iml deleted file mode 100644 index 3abe68e..0000000 --- a/.idea/kottans_2016_homeworks.iml +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml deleted file mode 100644 index 918884f..0000000 --- a/.idea/misc.xml +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml deleted file mode 100644 index 5bdee32..0000000 --- a/.idea/modules.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml deleted file mode 100644 index 94a25f7..0000000 --- a/.idea/vcs.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/.idea/workspace.xml b/.idea/workspace.xml deleted file mode 100644 index 77d87b4..0000000 --- a/.idea/workspace.xml +++ /dev/null @@ -1,614 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - true - DEFINITION_ORDER - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - project - - - - - - - - - - - - - - - - - - - - - 1478503382746 - - - 1478536872543 - - - 1478600629291 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file From 33d231c815475627867eaf7d08a3dc3179165693 Mon Sep 17 00:00:00 2001 From: superedriver Date: Mon, 14 Nov 2016 16:36:34 +0200 Subject: [PATCH 04/10] Made router not static for routes --- hw2/lib/router.rb | 50 ++++++++++++++++++++++++++++++------- hw2/spec/lib/router_spec.rb | 50 +++++++++++++++++++++++++++++++++++-- 2 files changed, 89 insertions(+), 11 deletions(-) diff --git a/hw2/lib/router.rb b/hw2/lib/router.rb index 2210e28..1e499eb 100644 --- a/hw2/lib/router.rb +++ b/hw2/lib/router.rb @@ -1,10 +1,18 @@ class Router def call(env) - if nested_post? env - @routes[env['REQUEST_METHOD']]['/post/:name'].call(env) - else - @routes[env['REQUEST_METHOD']][env['REQUEST_PATH']].call(env) + current_path, current_method = env['REQUEST_PATH'], env['REQUEST_METHOD'] + return @routes[current_method]['direct'][current_path].call(env) if direct_path?(current_path, current_method) + + @routes[current_method]['nested'].keys.each do |path| + path_array = path.split('/') + current_path_array = current_path.split('/') + + next if different_path_size?(path_array, current_path_array) || different_pathes?(path_array, current_path_array) + + return @routes[current_method]['nested'][path].call(env) end + + @routes[env['REQUEST_METHOD']]['404'][env['REQUEST_PATH']].call(env) end private @@ -23,12 +31,36 @@ def post(path, rack_app) end def match(http_method, path, rack_app) - @routes[http_method] ||= Hash.new(->(env) { [404, {}, ['not found']] }) - @routes[http_method][path] = rack_app + @routes[http_method] ||= Hash.new { |h,k| h[k] = Hash.new(->(env) { [404, {}, ['not found']] }) } + + if path =~ /\/:\w/ + @routes[http_method]['nested'][path] = rack_app + else + @routes[http_method]['direct'][path] = rack_app + end + end + + def direct_path?(current_path, current_method) + @routes[current_method]['direct'].keys.each do |path| + return true if current_path == path + end + + false + end + + def different_path_size?(path_array, current_path_array) + path_array.size != current_path_array.size + end + + def different_pathes?(path_array, current_path_array) + path_array.each_with_index do |_,index| + return true unless same_items_of_path?(path_array[index], current_path_array[index]) + end + + false end - def nested_post?(env) - path_arr = env['REQUEST_PATH'][1..-1].split('/') - env['REQUEST_METHOD'] == 'GET' && path_arr.size == 2 && path_arr[0] == 'post' + def same_items_of_path?(path_item, current_path_item) + path_item == current_path_item || (path_item =~ /:\w/ && current_path_item =~ /\w/) end end diff --git a/hw2/spec/lib/router_spec.rb b/hw2/spec/lib/router_spec.rb index 5e742a4..78704fb 100644 --- a/hw2/spec/lib/router_spec.rb +++ b/hw2/spec/lib/router_spec.rb @@ -13,6 +13,8 @@ # Cover this with tests. # get '/post/:name', ->(env) { [200, {}, ['post show page']] } + get '/post/:name/:name', ->(env) { [200, {}, ['nested in a row post show page']] } + get '/post/:name/:name/comments/:name', ->(env) { [200, {}, ['nested in a row and not in a row post show page']] } end end @@ -27,7 +29,7 @@ expect(subject.call(env)).to eq [200, {}, ['get test']] end - context 'when request is nested "post"' do + context 'when request is nested /post/:name' do it 'matches request if nested' do env['REQUEST_PATH'] = '/post/some_string' expect(subject.call(env)).to eq [200, {}, ['post show page']] @@ -39,15 +41,59 @@ end it 'not matches request if deep nested post url' do - env['REQUEST_PATH'] = '/post/some_string/string' + env['REQUEST_PATH'] = '/post/some_string/string/string' expect(subject.call(env)).to eq [404, {}, ['not found']] end + it 'not matches request if url has //' do + env['REQUEST_PATH'] = '/post//some_string' + expect(subject.call(env)).to eq [404, {}, ['not found']] + end + end + + context 'when request is nested /post/:name/:name' do + it 'matches request if nested' do + env['REQUEST_PATH'] = '/post/some_path/some_path' + expect(subject.call(env)).to eq [200, {}, ['nested in a row post show page']] + end + + it 'matches request if nested and ends on /' do + env['REQUEST_PATH'] = '/post/some_path/some_path/' + expect(subject.call(env)).to eq [200, {}, ['nested in a row post show page']] + end + it 'not matches request if url is not nested but "post"' do env['REQUEST_PATH'] = '/post/' expect(subject.call(env)).to eq [404, {}, ['not found']] end end + + context 'when request is nested /post/:name/:name/comments/:name' do + it 'matches request if nested' do + env['REQUEST_PATH'] = '/post/some_path/some_path/comments/some_path' + expect(subject.call(env)).to eq [200, {}, ['nested in a row and not in a row post show page']] + end + + it 'matches request if nested and ends on /' do + env['REQUEST_PATH'] = '/post/some_path/some_path/comments/some_path' + expect(subject.call(env)).to eq [200, {}, ['nested in a row and not in a row post show page']] + end + + it 'not matches request if url is not nested but "post" and "comments"' do + env['REQUEST_PATH'] = '/post/:name/:name/comments/' + expect(subject.call(env)).to eq [404, {}, ['not found']] + end + + it 'not matches request if url has not "comments"' do + env['REQUEST_PATH'] = '/post/:name/:name/some_path/:name' + expect(subject.call(env)).to eq [404, {}, ['not found']] + end + + it 'not matches request if url is nested more than need ' do + env['REQUEST_PATH'] = '/post/:name/:name/some_path/:name/path' + expect(subject.call(env)).to eq [404, {}, ['not found']] + end + end end context 'when request is POST' do From 2368cce84d77556f6816b2a9eda058f9d0cf4b24 Mon Sep 17 00:00:00 2001 From: superedriver Date: Mon, 14 Nov 2016 17:26:26 +0200 Subject: [PATCH 05/10] Added some description --- hw2/lib/router.rb | 60 ++++++++++++++++++++++++++++--------- hw2/spec/lib/router_spec.rb | 13 ++++++++ 2 files changed, 59 insertions(+), 14 deletions(-) diff --git a/hw2/lib/router.rb b/hw2/lib/router.rb index 1e499eb..45dcd76 100644 --- a/hw2/lib/router.rb +++ b/hw2/lib/router.rb @@ -1,21 +1,43 @@ +=begin +@routes[REQUEST_METHOD] has two hashes "direct" and "nested" +"direct" - to storage routes without ":" "/test/some_path" +"nested" - to storage routes with ":" ""/test/:name"" + +@routes = { + "GET": + "direct": { + "/test": RACK_APP_1 + } + "nested": { + "/test/:name": RACK_APP_3 + "/test/:name/:name": RACK_APP_4 + } + "POST": { + "direct": { + "/test": RACK_APP_2 + "/test/some_path": RACK_APP_5 + } + } +} +=end + class Router def call(env) - current_path, current_method = env['REQUEST_PATH'], env['REQUEST_METHOD'] - return @routes[current_method]['direct'][current_path].call(env) if direct_path?(current_path, current_method) + current_method, current_path = env['REQUEST_METHOD'], env['REQUEST_PATH'] - @routes[current_method]['nested'].keys.each do |path| - path_array = path.split('/') - current_path_array = current_path.split('/') + # direct routes handling + return routes[current_method]['direct'][current_path].call(env) if direct_path?(current_path, current_method) - next if different_path_size?(path_array, current_path_array) || different_pathes?(path_array, current_path_array) + # nested routes handling + path = nested_path?(current_path, current_method) + return routes[current_method]['nested'][path].call(env) if path - return @routes[current_method]['nested'][path].call(env) - end - - @routes[env['REQUEST_METHOD']]['404'][env['REQUEST_PATH']].call(env) + # 404 routes handling + routes[current_method]['404'][current_path].call(env) end private + attr_reader :routes def initialize(&block) @routes = {} @@ -31,23 +53,33 @@ def post(path, rack_app) end def match(http_method, path, rack_app) - @routes[http_method] ||= Hash.new { |h,k| h[k] = Hash.new(->(env) { [404, {}, ['not found']] }) } + routes[http_method] ||= Hash.new { |k,v| k[v] = Hash.new(->(env) { [404, {}, ['not found']] }) } if path =~ /\/:\w/ - @routes[http_method]['nested'][path] = rack_app + routes[http_method]['nested'][path] = rack_app else - @routes[http_method]['direct'][path] = rack_app + routes[http_method]['direct'][path] = rack_app end end def direct_path?(current_path, current_method) - @routes[current_method]['direct'].keys.each do |path| + routes[current_method]['direct'].keys.each do |path| return true if current_path == path end false end + def nested_path?(current_path, current_method) + routes[current_method]['nested'].keys.each do |path| + path_array, current_path_array = path.split('/'), current_path.split('/') + + next if different_path_size?(path_array, current_path_array) || different_pathes?(path_array, current_path_array) + + return path + end + end + def different_path_size?(path_array, current_path_array) path_array.size != current_path_array.size end diff --git a/hw2/spec/lib/router_spec.rb b/hw2/spec/lib/router_spec.rb index 78704fb..84dc303 100644 --- a/hw2/spec/lib/router_spec.rb +++ b/hw2/spec/lib/router_spec.rb @@ -15,6 +15,7 @@ get '/post/:name', ->(env) { [200, {}, ['post show page']] } get '/post/:name/:name', ->(env) { [200, {}, ['nested in a row post show page']] } get '/post/:name/:name/comments/:name', ->(env) { [200, {}, ['nested in a row and not in a row post show page']] } + post '/test/some_path', ->(env) { [200, {}, ['post some_path page']] } end end @@ -106,5 +107,17 @@ it 'matches request' do expect(subject.call(env)).to eq [200, {}, ['post test']] end + + context 'when request is direct /test/some_path' do + it 'matches request "/test/some_path"' do + env['REQUEST_PATH'] = '/test/some_path' + expect(subject.call(env)).to eq [200, {}, ['post some_path page']] + end + + it 'not matches request "/test/some_path/path"' do + env['REQUEST_PATH'] = '/test/some_path/path' + expect(subject.call(env)).to eq [404, {}, ['not found']] + end + end end end From a2359eb29e4d6cc9564ae82f96acd57369877402 Mon Sep 17 00:00:00 2001 From: superedriver Date: Wed, 16 Nov 2016 11:52:19 +0200 Subject: [PATCH 06/10] Modified some description --- hw2/lib/router.rb | 44 +++++++++++++++++++++----------------------- 1 file changed, 21 insertions(+), 23 deletions(-) diff --git a/hw2/lib/router.rb b/hw2/lib/router.rb index 45dcd76..ef6b0eb 100644 --- a/hw2/lib/router.rb +++ b/hw2/lib/router.rb @@ -1,19 +1,19 @@ =begin -@routes[REQUEST_METHOD] has two hashes "direct" and "nested" -"direct" - to storage routes without ":" "/test/some_path" -"nested" - to storage routes with ":" ""/test/:name"" +@routes[REQUEST_METHOD] has two hashes "simple" and "complex" +"simple" - to storage routes without ":" "/test/some_path" +"complex" - to storage routes with ":" "/test/:name @routes = { "GET": - "direct": { + "simple": { "/test": RACK_APP_1 } - "nested": { + "complex": { "/test/:name": RACK_APP_3 "/test/:name/:name": RACK_APP_4 } "POST": { - "direct": { + "simple": { "/test": RACK_APP_2 "/test/some_path": RACK_APP_5 } @@ -24,16 +24,13 @@ class Router def call(env) current_method, current_path = env['REQUEST_METHOD'], env['REQUEST_PATH'] - - # direct routes handling - return routes[current_method]['direct'][current_path].call(env) if direct_path?(current_path, current_method) - - # nested routes handling - path = nested_path?(current_path, current_method) - return routes[current_method]['nested'][path].call(env) if path - + # simple routes handling + return routes[current_method]['simple'][current_path].call(env) if simple_path?(current_path, current_method) + # complex routes handling + path = complex_path?(current_path, current_method) + return routes[current_method]['complex'][path].call(env) if path.is_a? String # 404 routes handling - routes[current_method]['404'][current_path].call(env) + ->(env) { [404, {}, ['not found']] }.call(env) end private @@ -53,27 +50,28 @@ def post(path, rack_app) end def match(http_method, path, rack_app) - routes[http_method] ||= Hash.new { |k,v| k[v] = Hash.new(->(env) { [404, {}, ['not found']] }) } + routes[http_method] ||= {} + routes[http_method]['complex'] ||= {} + routes[http_method]['simple'] ||= {} if path =~ /\/:\w/ - routes[http_method]['nested'][path] = rack_app + routes[http_method]['complex'][path] = rack_app else - routes[http_method]['direct'][path] = rack_app + routes[http_method]['simple'][path] = rack_app end end - def direct_path?(current_path, current_method) - routes[current_method]['direct'].keys.each do |path| + def simple_path?(current_path, current_method) + routes[current_method]['simple'].keys.each do |path| return true if current_path == path end false end - def nested_path?(current_path, current_method) - routes[current_method]['nested'].keys.each do |path| + def complex_path?(current_path, current_method) + routes[current_method]['complex'].keys.each do |path| path_array, current_path_array = path.split('/'), current_path.split('/') - next if different_path_size?(path_array, current_path_array) || different_pathes?(path_array, current_path_array) return path From 0633d16756be43188b7ef379a71f9d9f424fac41 Mon Sep 17 00:00:00 2001 From: superedriver Date: Wed, 16 Nov 2016 12:41:54 +0200 Subject: [PATCH 07/10] Remade structure --- hw2/lib/router.rb | 78 +++++++++++------------------------------------ 1 file changed, 18 insertions(+), 60 deletions(-) diff --git a/hw2/lib/router.rb b/hw2/lib/router.rb index ef6b0eb..8ce95ca 100644 --- a/hw2/lib/router.rb +++ b/hw2/lib/router.rb @@ -3,41 +3,26 @@ "simple" - to storage routes without ":" "/test/some_path" "complex" - to storage routes with ":" "/test/:name -@routes = { - "GET": - "simple": { - "/test": RACK_APP_1 - } - "complex": { - "/test/:name": RACK_APP_3 - "/test/:name/:name": RACK_APP_4 - } - "POST": { - "simple": { - "/test": RACK_APP_2 - "/test/some_path": RACK_APP_5 - } +@routes = [ + { + pattern: path, + app: rack_app, + regexp: path_to_regexp(path) } -} +] + =end class Router def call(env) - current_method, current_path = env['REQUEST_METHOD'], env['REQUEST_PATH'] - # simple routes handling - return routes[current_method]['simple'][current_path].call(env) if simple_path?(current_path, current_method) - # complex routes handling - path = complex_path?(current_path, current_method) - return routes[current_method]['complex'][path].call(env) if path.is_a? String - # 404 routes handling - ->(env) { [404, {}, ['not found']] }.call(env) + find_route(env).call(env) end private attr_reader :routes def initialize(&block) - @routes = {} + @routes = [] instance_exec(&block) end @@ -50,47 +35,20 @@ def post(path, rack_app) end def match(http_method, path, rack_app) - routes[http_method] ||= {} - routes[http_method]['complex'] ||= {} - routes[http_method]['simple'] ||= {} - - if path =~ /\/:\w/ - routes[http_method]['complex'][path] = rack_app - else - routes[http_method]['simple'][path] = rack_app - end - end - - def simple_path?(current_path, current_method) - routes[current_method]['simple'].keys.each do |path| - return true if current_path == path - end - - false - end - - def complex_path?(current_path, current_method) - routes[current_method]['complex'].keys.each do |path| - path_array, current_path_array = path.split('/'), current_path.split('/') - next if different_path_size?(path_array, current_path_array) || different_pathes?(path_array, current_path_array) - - return path - end - end - - def different_path_size?(path_array, current_path_array) - path_array.size != current_path_array.size + routes << { pattern: path, app: rack_app, regexp: path_to_regexp(path), method: http_method} end - def different_pathes?(path_array, current_path_array) - path_array.each_with_index do |_,index| - return true unless same_items_of_path?(path_array[index], current_path_array[index]) + def find_route(env) + routes.each do |route| + if env['REQUEST_METHOD'] == route[:method] && env['REQUEST_PATH'] =~ route[:regexp] + return route[:app] + end end - false + ->(_env) { [404, {}, ['not found']] } end - def same_items_of_path?(path_item, current_path_item) - path_item == current_path_item || (path_item =~ /:\w/ && current_path_item =~ /\w/) + def path_to_regexp(path) + Regexp.new('\A' + path.gsub(/:[\w-]+/, '[\w-]+') + '\Z') end end From 39352745c17a4b49b33758e86b5e6ef1b0dca394 Mon Sep 17 00:00:00 2001 From: superedriver Date: Wed, 16 Nov 2016 12:42:50 +0200 Subject: [PATCH 08/10] Remade structure --- hw2/lib/router.rb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/hw2/lib/router.rb b/hw2/lib/router.rb index ef6b0eb..382eace 100644 --- a/hw2/lib/router.rb +++ b/hw2/lib/router.rb @@ -28,7 +28,7 @@ def call(env) return routes[current_method]['simple'][current_path].call(env) if simple_path?(current_path, current_method) # complex routes handling path = complex_path?(current_path, current_method) - return routes[current_method]['complex'][path].call(env) if path.is_a? String + return routes[current_method]['complex'][path].call(env) if path # 404 routes handling ->(env) { [404, {}, ['not found']] }.call(env) end @@ -76,6 +76,8 @@ def complex_path?(current_path, current_method) return path end + + nil end def different_path_size?(path_array, current_path_array) From cc8ed7fe7199019355be7e88a09e58c3aaf2daa5 Mon Sep 17 00:00:00 2001 From: superedriver Date: Wed, 30 Nov 2016 14:34:54 +0200 Subject: [PATCH 09/10] Added hw3 and hw4 --- .gitignore | 1 + hw2/Gemfile | 3 +- hw2/Gemfile.lock | 2 + hw2/app/app.rb | 15 ++- hw2/lib/controller.rb | 35 ++++++ hw2/lib/router.rb | 40 ++++--- hw2/main.rb | 5 +- hw2/spec/lib/controller_spec.rb | 89 ++++++++++++++ hw2/spec/lib/router_spec.rb | 51 +++++--- hw2/spec/spec_helper.rb | 7 +- hw3/web_router | 1 + hw4/try_web_router/.gitignore | 3 + hw4/try_web_router/.rspec | 2 + hw4/try_web_router/.travis.yml | 8 ++ hw4/try_web_router/Gemfile | 6 + hw4/try_web_router/Gemfile.lock | 40 +++++++ hw4/try_web_router/Readme.md | 3 + hw4/try_web_router/config.ru | 3 + hw4/try_web_router/config/routes.rb | 9 ++ hw4/try_web_router/controllers/home.rb | 13 +++ hw4/try_web_router/main.rb | 5 + .../spec/controllers/home_spec.rb | 61 ++++++++++ .../spec/features/features_spec.rb | 11 ++ hw4/try_web_router/spec/spec_helper.rb | 109 ++++++++++++++++++ hw4/try_web_router/views/index.html.erb | 90 +++++++++++++++ 25 files changed, 572 insertions(+), 40 deletions(-) create mode 100644 .gitignore create mode 100644 hw2/lib/controller.rb create mode 100644 hw2/spec/lib/controller_spec.rb create mode 160000 hw3/web_router create mode 100644 hw4/try_web_router/.gitignore create mode 100644 hw4/try_web_router/.rspec create mode 100644 hw4/try_web_router/.travis.yml create mode 100644 hw4/try_web_router/Gemfile create mode 100644 hw4/try_web_router/Gemfile.lock create mode 100644 hw4/try_web_router/Readme.md create mode 100644 hw4/try_web_router/config.ru create mode 100644 hw4/try_web_router/config/routes.rb create mode 100644 hw4/try_web_router/controllers/home.rb create mode 100644 hw4/try_web_router/main.rb create mode 100644 hw4/try_web_router/spec/controllers/home_spec.rb create mode 100644 hw4/try_web_router/spec/features/features_spec.rb create mode 100644 hw4/try_web_router/spec/spec_helper.rb create mode 100644 hw4/try_web_router/views/index.html.erb diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..62c8935 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +.idea/ \ No newline at end of file diff --git a/hw2/Gemfile b/hw2/Gemfile index 404a782..0b878ff 100644 --- a/hw2/Gemfile +++ b/hw2/Gemfile @@ -1,6 +1,7 @@ # frozen_string_literal: true source "https://rubygems.org" +gem "pry" gem "rack" gem "rspec" -gem "pry" +gem "oj" diff --git a/hw2/Gemfile.lock b/hw2/Gemfile.lock index ffd0352..62ddc10 100644 --- a/hw2/Gemfile.lock +++ b/hw2/Gemfile.lock @@ -4,6 +4,7 @@ GEM coderay (1.1.1) diff-lcs (1.2.5) method_source (0.8.2) + oj (2.17.5) pry (0.10.4) coderay (~> 1.1.0) method_source (~> 0.8.1) @@ -28,6 +29,7 @@ PLATFORMS ruby DEPENDENCIES + oj pry rack rspec diff --git a/hw2/app/app.rb b/hw2/app/app.rb index 7fd7f69..fb9339a 100644 --- a/hw2/app/app.rb +++ b/hw2/app/app.rb @@ -1,5 +1,14 @@ +class TestsController < Controller + def show + response(:json, params) + end + + def test + response(:text, "Required method #{request.request_method}") + end +end + Application = Router.new do - get '/test', ->(env) { [200, {}, ['get test']] } - post '/test', ->(env) { [200, {}, ['post test']] } - get '/post/:name', ->(env) { [200, {}, ['post show page']] } + get '/post/:name/:other_one', 'tests#show' + get '/test', 'tests#test' end diff --git a/hw2/lib/controller.rb b/hw2/lib/controller.rb new file mode 100644 index 0000000..255a674 --- /dev/null +++ b/hw2/lib/controller.rb @@ -0,0 +1,35 @@ +class Controller + RESPONSE_TYPES = { + text: ['text/plain', -> (c) { c.to_s }], + json: ['application/json', -> (c) { Oj.dump(c) }], + } + + def call(env) + @env = env + @request = Rack::Request.new(env) + @request.params.merge!(env['router.params'] || {}) + send(@action_name) + [200, @response_headers, [@response_body]] + end + + def self.action(action_name) + proc { |env| new(action_name).call(env)} + end + +private + attr_reader :request + + def initialize(action_name) + @action_name = action_name + end + + def params + request.params + end + + def response(type, content) + @response_headers ||= {} + @response_headers.merge!('Content-Type' => RESPONSE_TYPES[type][0] ) + @response_body = RESPONSE_TYPES[type][1].call(content) + end +end diff --git a/hw2/lib/router.rb b/hw2/lib/router.rb index 8ce95ca..2311c0b 100644 --- a/hw2/lib/router.rb +++ b/hw2/lib/router.rb @@ -1,18 +1,3 @@ -=begin -@routes[REQUEST_METHOD] has two hashes "simple" and "complex" -"simple" - to storage routes without ":" "/test/some_path" -"complex" - to storage routes with ":" "/test/:name - -@routes = [ - { - pattern: path, - app: rack_app, - regexp: path_to_regexp(path) - } -] - -=end - class Router def call(env) find_route(env).call(env) @@ -35,12 +20,27 @@ def post(path, rack_app) end def match(http_method, path, rack_app) + rack_app = get_controller_action(rack_app) if rack_app.is_a? String routes << { pattern: path, app: rack_app, regexp: path_to_regexp(path), method: http_method} end + def get_controller_action(str) + controller_name, action_name = str.split('#') # tests#show => ['tests', 'show'] + controller_name = to_upper_camel_case(controller_name) + Kernel.const_get(controller_name).send(:action, action_name) + end + + def to_upper_camel_case(str) + str # 'public_pages/tests' => PublicPages::TestsController + .split('/') # ['public_pages', 'test'] + .map { |part| part.split('_').map(&:capitalize).join } # ['PublicPages', 'Test'] + .join('::') + 'Controller' + end + def find_route(env) routes.each do |route| if env['REQUEST_METHOD'] == route[:method] && env['REQUEST_PATH'] =~ route[:regexp] + env['router.params'] = extract_params(route[:pattern], env['REQUEST_PATH']) return route[:app] end end @@ -51,4 +51,14 @@ def find_route(env) def path_to_regexp(path) Regexp.new('\A' + path.gsub(/:[\w-]+/, '[\w-]+') + '\Z') end + + # pattern: "post/:name", route: "post/about_ruby" + def extract_params(pattern, path) + pattern + .split('/') # ['post', ':name'] + .zip(path.split('/')) # [['post', 'post'],[':name', 'post']] + .reject { |e| e.first == e.last } # [[':name', 'post']] + .map { |e| [e.first[1..-1], e.last] } # [['name', 'post']] + .to_h + end end diff --git a/hw2/main.rb b/hw2/main.rb index 0b84eca..907934e 100644 --- a/hw2/main.rb +++ b/hw2/main.rb @@ -1,3 +1,6 @@ +require 'pry' +require 'rack' +require 'oj' +require './lib/controller' require './lib/router' require './app/app' -require 'pry' diff --git a/hw2/spec/lib/controller_spec.rb b/hw2/spec/lib/controller_spec.rb new file mode 100644 index 0000000..e6e1d3b --- /dev/null +++ b/hw2/spec/lib/controller_spec.rb @@ -0,0 +1,89 @@ +require 'spec_helper' + +RSpec.describe Controller do + let(:controller) do + Class.new(described_class) do + def test_action + response(:text, 'simple test') + end + + def text_action + response(:text, params.inspect) + end + + def json_action + response(:json, params) + end + end + end + + describe '#action' do + it 'returns proc' do + expect(controller.action(:test)).to be_a(Proc) + end + + it 'generated proc calls action' do + expect(controller.action(:test_action).call(Rack::MockRequest.env_for('/'))) + .to eq([200, { 'Content-Type' => 'text/plain' }, ['simple test']]) + end + end + + describe 'request processing' do + subject do + controller + .action(action) + .call(Rack::MockRequest.env_for('/?a=b&e=r').merge!(router_params)) + end + + let(:router_params) { {} } + + context 'when text response' do + context 'response with simple text' do + let(:action) { :test_action } + + it 'successfully responds' do + expect(subject) + .to eq([200, {'Content-Type'=>'text/plain'}, ['simple test']]) + end + end + + context 'response with params' do + let(:action) { :text_action } + + it 'successfully responds' do + expect(subject) + .to eq([200, {"Content-Type"=>"text/plain"}, ["{\"a\"=>\"b\", \"e\"=>\"r\"}"]]) + end + end + let(:action) { :test_action } + + it 'successfully responds' do + expect(subject) + .to eq([200, {"Content-Type"=>"text/plain"}, ["simple test"]]) + end + end + + context 'when json response' do + let(:action) { :json_action } + + it 'successfully responds' do + expect(subject) + .to eq([200, {"Content-Type"=>"application/json"}, ["{\"a\":\"b\",\"e\":\"r\"}"]]) + end + end + + context 'when has router params' do + let(:router_params) { { 'router.params' => { 'param' => 'value' } } } + let(:action) { :json_action } + + it 'successfully responds' do + expect(subject) + .to eq([ + 200, + {"Content-Type"=>"application/json"}, + ["{\"a\":\"b\",\"e\":\"r\",\"param\":\"value\"}"]] + ) + end + end + end +end diff --git a/hw2/spec/lib/router_spec.rb b/hw2/spec/lib/router_spec.rb index 84dc303..80c79ae 100644 --- a/hw2/spec/lib/router_spec.rb +++ b/hw2/spec/lib/router_spec.rb @@ -1,26 +1,33 @@ RSpec.describe Router do + before(:all) do + class TestsController < Controller + def show + response(:json, params) + end + + def test + response(:text, "Required method #{request.request_method}") + end + end + end + subject do Router.new do get '/test', ->(env) { [200, {}, ['get test']] } post '/test', ->(env) { [200, {}, ['post test']] } - ## - # TODO: router should match path by pattern like - # Pattern: /posts/:name - # Paths: - # /post/about_ruby - # /post/43 - # Cover this with tests. - # get '/post/:name', ->(env) { [200, {}, ['post show page']] } get '/post/:name/:name', ->(env) { [200, {}, ['nested in a row post show page']] } get '/post/:name/:name/comments/:name', ->(env) { [200, {}, ['nested in a row and not in a row post show page']] } post '/test/some_path', ->(env) { [200, {}, ['post some_path page']] } + + get '/comments/:name/:other_one', 'tests#show' + get '/testing', 'tests#test' end end context 'when request is GET' do - let(:env) { { 'REQUEST_PATH' => '/test', 'REQUEST_METHOD' => 'GET'} } + let(:env) { { 'REQUEST_PATH' => '/test', 'REQUEST_METHOD' => 'GET', 'params' => {} } } it 'returns 404 error for missing path' do expect(subject.call({ 'REQUEST_PATH' => '/not_found_path', 'REQUEST_METHOD' => 'GET'})).to eq [404, {}, ['not found']] @@ -36,11 +43,6 @@ expect(subject.call(env)).to eq [200, {}, ['post show page']] end - it 'matches request if nested and ends on /' do - env['REQUEST_PATH'] = '/post/some_string/' - expect(subject.call(env)).to eq [200, {}, ['post show page']] - end - it 'not matches request if deep nested post url' do env['REQUEST_PATH'] = '/post/some_string/string/string' expect(subject.call(env)).to eq [404, {}, ['not found']] @@ -58,11 +60,6 @@ expect(subject.call(env)).to eq [200, {}, ['nested in a row post show page']] end - it 'matches request if nested and ends on /' do - env['REQUEST_PATH'] = '/post/some_path/some_path/' - expect(subject.call(env)).to eq [200, {}, ['nested in a row post show page']] - end - it 'not matches request if url is not nested but "post"' do env['REQUEST_PATH'] = '/post/' expect(subject.call(env)).to eq [404, {}, ['not found']] @@ -95,6 +92,22 @@ expect(subject.call(env)).to eq [404, {}, ['not found']] end end + + context 'when request is "/testing" -> "tests#test"' do + it 'matches request' do + env['REQUEST_PATH'] = '/testing' + env['rack.input'] = Rack::Request.new({}) + expect(subject.call(env)).to eq [200, {'Content-Type'=>'text/plain'}, ['Required method GET']] + end + end + + context 'when request is "/post/:name/:other_one" -> "tests#show"' do + it 'matches request' do + env['REQUEST_PATH'] = '/comments/comment/other' + env['rack.input'] = Rack::Request.new({}) + expect(subject.call(env)).to eq [200, {'Content-Type'=>'application/json'}, ["{\"name\":\"comment\",\"other_one\":\"other\"}"]] + end + end end context 'when request is POST' do diff --git a/hw2/spec/spec_helper.rb b/hw2/spec/spec_helper.rb index ef0fca6..36a4edf 100644 --- a/hw2/spec/spec_helper.rb +++ b/hw2/spec/spec_helper.rb @@ -1,4 +1,9 @@ -require './lib/router' +require 'pry' +require 'rack' +require 'oj' +require './web_router/router' +require './web_router/controller' + RSpec.configure do |config| config.expect_with :rspec do |expectations| diff --git a/hw3/web_router b/hw3/web_router new file mode 160000 index 0000000..229c604 --- /dev/null +++ b/hw3/web_router @@ -0,0 +1 @@ +Subproject commit 229c6048bb1499e5fc86e493c7a34ddc98ca165b diff --git a/hw4/try_web_router/.gitignore b/hw4/try_web_router/.gitignore new file mode 100644 index 0000000..98c4096 --- /dev/null +++ b/hw4/try_web_router/.gitignore @@ -0,0 +1,3 @@ +/.idea +/.bundle +vendor/ \ No newline at end of file diff --git a/hw4/try_web_router/.rspec b/hw4/try_web_router/.rspec new file mode 100644 index 0000000..83e16f8 --- /dev/null +++ b/hw4/try_web_router/.rspec @@ -0,0 +1,2 @@ +--color +--require spec_helper diff --git a/hw4/try_web_router/.travis.yml b/hw4/try_web_router/.travis.yml new file mode 100644 index 0000000..9eb8762 --- /dev/null +++ b/hw4/try_web_router/.travis.yml @@ -0,0 +1,8 @@ +language: ruby +rvm: + - 2.3.1 +script: bundle exec rspec spec +deploy: + provider: heroku + api_key: $HEROKU_STAGING_API_KEY + app: try-web-router-gem \ No newline at end of file diff --git a/hw4/try_web_router/Gemfile b/hw4/try_web_router/Gemfile new file mode 100644 index 0000000..e76d35c --- /dev/null +++ b/hw4/try_web_router/Gemfile @@ -0,0 +1,6 @@ +# frozen_string_literal: true +source 'https://rubygems.org' + +gem 'web_router' +gem 'pry' +gem 'rspec' diff --git a/hw4/try_web_router/Gemfile.lock b/hw4/try_web_router/Gemfile.lock new file mode 100644 index 0000000..86b156d --- /dev/null +++ b/hw4/try_web_router/Gemfile.lock @@ -0,0 +1,40 @@ +GEM + remote: https://rubygems.org/ + specs: + coderay (1.1.1) + diff-lcs (1.2.5) + method_source (0.8.2) + oj (2.17.5) + pry (0.10.4) + coderay (~> 1.1.0) + method_source (~> 0.8.1) + slop (~> 3.4) + rack (2.0.1) + rspec (3.5.0) + rspec-core (~> 3.5.0) + rspec-expectations (~> 3.5.0) + rspec-mocks (~> 3.5.0) + rspec-core (3.5.4) + rspec-support (~> 3.5.0) + rspec-expectations (3.5.0) + diff-lcs (>= 1.2.0, < 2.0) + rspec-support (~> 3.5.0) + rspec-mocks (3.5.0) + diff-lcs (>= 1.2.0, < 2.0) + rspec-support (~> 3.5.0) + rspec-support (3.5.0) + slop (3.6.0) + web_router (0.3.0) + oj (~> 2.17) + rack (~> 2.0) + +PLATFORMS + ruby + +DEPENDENCIES + pry + rspec + web_router + +BUNDLED WITH + 1.13.5 diff --git a/hw4/try_web_router/Readme.md b/hw4/try_web_router/Readme.md new file mode 100644 index 0000000..ad0620b --- /dev/null +++ b/hw4/try_web_router/Readme.md @@ -0,0 +1,3 @@ +[![Build Status](https://travis-ci.org/superedriver/try_web_router.svg?branch=master)](https://travis-ci.org/superedriver/try_web_router) + +The simplest site to show how gem "web_router" works. \ No newline at end of file diff --git a/hw4/try_web_router/config.ru b/hw4/try_web_router/config.ru new file mode 100644 index 0000000..98d2c8a --- /dev/null +++ b/hw4/try_web_router/config.ru @@ -0,0 +1,3 @@ +require './main' + +run WebRouter::Router.new.configure &ROUTES \ No newline at end of file diff --git a/hw4/try_web_router/config/routes.rb b/hw4/try_web_router/config/routes.rb new file mode 100644 index 0000000..1b35d07 --- /dev/null +++ b/hw4/try_web_router/config/routes.rb @@ -0,0 +1,9 @@ +ROUTES = Proc.new { + get '/test', ->(env) { [200, {}, ['get test']] } + post '/test', ->(env) { [200, {}, ['post test']] } + put '/test', ->(env) { [200, {}, ['put test']] } + delete '/test', ->(env) { [200, {}, ['delete test']] } + get '/posts/:name', 'home#test' + get '/testing', 'home#show' + get '/', 'home#root' +} diff --git a/hw4/try_web_router/controllers/home.rb b/hw4/try_web_router/controllers/home.rb new file mode 100644 index 0000000..bf3bd0b --- /dev/null +++ b/hw4/try_web_router/controllers/home.rb @@ -0,0 +1,13 @@ +class HomeController < WebRouter::Controller + def show + response(:json, params) + end + + def test + response(:text, "Name is: #{params['name']}" ) + end + + def root + response(:html, erb(:'views/index.html.erb') ) + end +end diff --git a/hw4/try_web_router/main.rb b/hw4/try_web_router/main.rb new file mode 100644 index 0000000..4c813dc --- /dev/null +++ b/hw4/try_web_router/main.rb @@ -0,0 +1,5 @@ +require 'pry' +require 'web_router' + +require_relative 'controllers/home' +require_relative 'config/routes' diff --git a/hw4/try_web_router/spec/controllers/home_spec.rb b/hw4/try_web_router/spec/controllers/home_spec.rb new file mode 100644 index 0000000..9dfc09d --- /dev/null +++ b/hw4/try_web_router/spec/controllers/home_spec.rb @@ -0,0 +1,61 @@ +RSpec.describe HomeController do + describe '#action' do + it 'returns proc' do + expect(described_class.action(:show)).to be_a(Proc) + end + + it 'generated proc calls action' do + expect(described_class.action(:show).call(Rack::MockRequest.env_for('/'))) + .to eq([200, {"Content-Type"=>"application/json"}, ["{}"]]) + end + end + + + describe 'request processing' do + subject do + described_class + .action(action) + .call(Rack::MockRequest.env_for('/?a=b').merge!(router_params)) + end + + let(:router_params) { {} } + + context '#show' do + let(:action) { :show } + + it 'successfully responds' do + expect(subject) + .to eq([ + 200, + { 'Content-Type' => 'application/json' }, + ['{"a":"b"}'] + ]) + end + end + + context '#test' do + let(:action) { :test } + let(:router_params) { {'router.params' => {"name" => "qwerty"}} } + + it 'successfully responds' do + + expect(subject) + .to eq([ + 200, + { 'Content-Type' => 'text/plain' }, + ['Name is: qwerty'] + ]) + end + end + + context '#root' do + let(:action) { :root } + + it 'successfully responds' do + expect(subject[0]).to eq(200) + expect(subject[1]).to eq({ "Content-Type"=>"text/html" }) + expect(subject[2]).to eq([File.read("./views/index.html.erb")]) + end + end + end +end diff --git a/hw4/try_web_router/spec/features/features_spec.rb b/hw4/try_web_router/spec/features/features_spec.rb new file mode 100644 index 0000000..5ca5ef8 --- /dev/null +++ b/hw4/try_web_router/spec/features/features_spec.rb @@ -0,0 +1,11 @@ +# require "spec_helper" + +# RSpec.describe "the signin process", type: :feature do +# it "root page" do +# # session = Capybara::Session.new(:rack_test, WebRouter::Router.new.configure(&ROUTES)) +# visit '/' +# +# # binding.pry +# expect(page).to have_content 'The simplest site to show how gem "web_router" works.' +# end +# end \ No newline at end of file diff --git a/hw4/try_web_router/spec/spec_helper.rb b/hw4/try_web_router/spec/spec_helper.rb new file mode 100644 index 0000000..ccdf896 --- /dev/null +++ b/hw4/try_web_router/spec/spec_helper.rb @@ -0,0 +1,109 @@ +require 'web_router' +require_relative '../main' + +# This file was generated by the `rspec --init` command. Conventionally, all +# specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`. +# The generated `.rspec` file contains `--require spec_helper` which will cause +# this file to always be loaded, without a need to explicitly require it in any +# files. +# +# Given that it is always loaded, you are encouraged to keep this file as +# light-weight as possible. Requiring heavyweight dependencies from this file +# will add to the boot time of your test suite on EVERY test run, even for an +# individual file that may not need all of that loaded. Instead, consider making +# a separate helper file that requires the additional dependencies and performs +# the additional setup, and require it from the spec files that actually need +# it. +# +# The `.rspec` file also contains a few flags that are not defaults but that +# users commonly want. +# +# See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration +RSpec.configure do |config| + # rspec-expectations config goes here. You can use an alternate + # assertion/expectation library such as wrong or the stdlib/minitest + # assertions if you prefer. + config.expect_with :rspec do |expectations| + # This option will default to `true` in RSpec 4. It makes the `description` + # and `failure_message` of custom matchers include text for helper methods + # defined using `chain`, e.g.: + # be_bigger_than(2).and_smaller_than(4).description + # # => "be bigger than 2 and smaller than 4" + # ...rather than: + # # => "be bigger than 2" + expectations.include_chain_clauses_in_custom_matcher_descriptions = true + end + + # rspec-mocks config goes here. You can use an alternate test double + # library (such as bogus or mocha) by changing the `mock_with` option here. + config.mock_with :rspec do |mocks| + # Prevents you from mocking or stubbing a method that does not exist on + # a real object. This is generally recommended, and will default to + # `true` in RSpec 4. + mocks.verify_partial_doubles = true + end + + # This option will default to `:apply_to_host_groups` in RSpec 4 (and will + # have no way to turn it off -- the option exists only for backwards + # compatibility in RSpec 3). It causes shared context metadata to be + # inherited by the metadata hash of host groups and examples, rather than + # triggering implicit auto-inclusion in groups with matching metadata. + config.shared_context_metadata_behavior = :apply_to_host_groups + +# The settings below are suggested to provide a good initial experience +# with RSpec, but feel free to customize to your heart's content. + + # This allows you to limit a spec run to individual examples or groups + # you care about by tagging them with `:focus` metadata. When nothing + # is tagged with `:focus`, all examples get run. RSpec also provides + # aliases for `it`, `describe`, and `context` that include `:focus` + # metadata: `fit`, `fdescribe` and `fcontext`, respectively. + config.filter_run_when_matching :focus + + # Allows RSpec to persist some state between runs in order to support + # the `--only-failures` and `--next-failure` CLI options. We recommend + # you configure your source control system to ignore this file. + # config.example_status_persistence_file_path = "spec/examples.txt" + + # Limits the available syntax to the non-monkey patched syntax that is + # recommended. For more details, see: + # - http://rspec.info/blog/2012/06/rspecs-new-expectation-syntax/ + # - http://www.teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/ + # - http://rspec.info/blog/2014/05/notable-changes-in-rspec-3/#zero-monkey-patching-mode + config.disable_monkey_patching! + + # This setting enables warnings. It's recommended, but in some cases may + # be too noisy due to issues in dependencies. + config.warnings = true + + # Many RSpec users commonly either run the entire suite or an individual + # file, and it's useful to allow more verbose output when running an + # individual spec file. + if config.files_to_run.one? + # Use the documentation formatter for detailed output, + # unless a formatter has already been configured + # (e.g. via a command-line flag). + config.default_formatter = 'doc' + end + + # Print the 10 slowest examples and example groups at the + # end of the spec run, to help surface which specs are running + # particularly slow. + config.profile_examples = 10 + + # Run specs in random order to surface order dependencies. If you find an + # order dependency and want to debug it, you can fix the order by providing + # the seed, which is printed after each run. + # --seed 1234 + config.order = :random + + # Seed global randomization in this process using the `--seed` CLI option. + # Setting this allows you to use `--seed` to deterministically reproduce + # test failures related to randomization by passing the same `--seed` value + # as the one that triggered the failure. + Kernel.srand config.seed +end + +# def app +# Sinatra::Application +# end diff --git a/hw4/try_web_router/views/index.html.erb b/hw4/try_web_router/views/index.html.erb new file mode 100644 index 0000000..9335f9d --- /dev/null +++ b/hw4/try_web_router/views/index.html.erb @@ -0,0 +1,90 @@ + + + + + + + Web_Router + + + +

The simplest site to show how gem "web_router" works.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Path pattern + Method + Controller + Action + Returns + Description +
/GETHomerootviews/index.html.erbStart page
/testingGETHomeshowrequest params in Hash formParses query string "?q=w&a=s" to {"q":"w","a":"s"}
/posts/:nameGETHometest:name parameterName is: :name
/testGET"get test"with status 200
/testPOST"post test"with status 200
/testPUT"put test"with status 200
/testDELETE"delete test"with status 200
+ + + From 6878b48edb87770442adab2d46c4b917c88862d8 Mon Sep 17 00:00:00 2001 From: superedriver Date: Wed, 30 Nov 2016 14:48:59 +0200 Subject: [PATCH 10/10] Fixed pathes for require --- hw2/spec/spec_helper.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hw2/spec/spec_helper.rb b/hw2/spec/spec_helper.rb index 36a4edf..7ded7cc 100644 --- a/hw2/spec/spec_helper.rb +++ b/hw2/spec/spec_helper.rb @@ -1,8 +1,8 @@ require 'pry' require 'rack' require 'oj' -require './web_router/router' -require './web_router/controller' +require_relative '../lib/router' +require_relative '../lib/controller' RSpec.configure do |config|