Skip to content
This repository was archived by the owner on May 1, 2018. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
sudo: false
language: ruby
rvm:
- 2.3.1
- 2.3.0
script:
- bash check.sh
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# kottans_2016_homeworks

gem https://github.com/lysenko-sergei-developer/lysenko_kottans_rack
travis https://travis-ci.org/lysenko-sergei-developer/lysenko_kottans_rack
18 changes: 18 additions & 0 deletions hw1/fibonacci.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
class Fibonacci
include Enumerable

def initialize( n )
@n = n
end

def each
x, y = 0, 1

@n.times do
z = (x + y)
x = y
y = z
yield x
end
end
end
1 change: 1 addition & 0 deletions hw2/Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ source "https://rubygems.org"

gem "rack"
gem "rspec"
gem "oj"
4 changes: 3 additions & 1 deletion hw2/Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ GEM
remote: https://rubygems.org/
specs:
diff-lcs (1.2.5)
oj (2.17.5)
rack (2.0.1)
rspec (3.5.0)
rspec-core (~> 3.5.0)
Expand All @@ -21,8 +22,9 @@ PLATFORMS
ruby

DEPENDENCIES
oj
rack
rspec

BUNDLED WITH
1.13.5
1.13.6
25 changes: 22 additions & 3 deletions hw2/app/app.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,23 @@
Application = Router.new do
get '/test', ->(env) { [200, {}, ['get test']] }
post '/test', ->(env) { [200, {}, ['post test']] }
class TestController < Controller #inherit Controller class
def show # method show for return params
response(:json, params)
end

def test # method test for return request method
response(:text, "Request method: #{request.request_method}") # params = "Request method: #{request.request_method}",
end
end

Application = Router.new do # create new instance of Router

# get '/test', ->(env) { [200, {}, ['get test']] }
# post '/test', ->(env) { [200, {}, ['post test']] }

get '/post/:name/:other_one', 'test#show'
get '/test', 'test#test' # "#{request.request_method} = get"

#get '/users/:id', ->(env) { [200, {}, ['post /users/:id']] }
# get '/users/:id/comments/:comment/rating/:rating', ->(env) { [200, {}, ['post with users comment rating']] }
# get '/users/articles/:title', ->(env) { [200, {}, ['post with user articles title']] }

end
36 changes: 36 additions & 0 deletions hw2/lib/controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
class Controller
RESPONSE_TYPES = { # mini cheat, for work with response
text: ['text/plain', ->(c) { c.to_s }], # key where stored text params data
json: ['application/json', ->(c) { Oj.dump(c) }] # key where stored json
}.freeze # freeze this constant, for avoid random changing

def call(env) # env standart Rack params
@env = env # writed env into instance @env
@request = Rack::Request.new(env) # writed new rack request into instance @request
@request.params.merge!(env['router.params'] || {}) # merge with router.params if it exist
send(@action_name) # send @action_name

[200, @response_headers, [@response_body]] # return array with route
end

def self.action(action_name) # call action method for self object, action_name = call method name
proc { |env| new(action_name).call(env) } # proc create new action and call it
end

private
attr_reader :request # create getter for request

def initialize(action_name) # init with, call method name
@action_name = action_name # writed action_name into instance @action_name
end

def params # params return request params
request.params
end

def response(type, content) #response in header and body
@response_headers ||= {} # if @response_headers empty assign hash
@response_headers.merge!('Content-Type' => RESPONSE_TYPES[type][0]) # merge @response_headers with 'Content-Type' => RESPONSE_TYPES[text]['some text']
@response_body = RESPONSE_TYPES[type][1].call(content) # assign @response_body to RESPONSE_TYPES[json][some json] and call content arguments
end
end
65 changes: 55 additions & 10 deletions hw2/lib/router.rb
Original file line number Diff line number Diff line change
@@ -1,25 +1,70 @@
class Router
def call(env)
@routes[env['REQUEST_METHOD']][env['REQUEST_PATH']].call(env)
def call(env) # call method with env params
find_route(env).call(env) # call env
end

private

def initialize(&block)
@routes = {}
instance_exec(&block)
def initialize(&block) # initialize of code blok
@routes = [] # set to null @routes
instance_exec(&block) #call &block
end

def get(path, rack_app)
def find_route(env) # check if route exist
@routes.each do |route| # in @routes all route
# check if requst method of call and requst method of route matche
# and requst path of call math with route path
if env['REQUEST_METHOD'] == route[:method] && env['REQUEST_PATH'] =~ route[:regexp]
# if all matches, assing to router.params extract params
env['router.params'] = extract_params(route[:pattern], env['REQUEST_PATH'])
return route[:app] # return applocation
end
end

return ->(_env) { [404, {}, ['not found']] } # if not exist return -> 404
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we can omit return here

end

def get(path, rack_app) # get request
match('GET', path, rack_app)
end

def post(path, rack_app)
def post(path, rack_app) # post request
match('POST', path, rack_app)
end

def match(http_method, path, rack_app)
@routes[http_method] ||= {}
@routes[http_method][path] = rack_app
def match(http_method, path, rack_app) # match
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)# ['tests', 'show'] => ['TestsController', 'show']
Kernel.const_get(controller_name).send(:action, action_name)
end

def to_upper_camel_case(str) # up
str # 'public_pages/tests' => PublicPages::TestsController
.split('/') # ['public_pages', 'test']
.map { |part| part.split('_').map(&:capitalize).join } # ['PublicPages', 'Test']
.join('::') + 'Controller'
end


# /post/:name
def path_to_regexp(path) # return processing path
Regexp.new('\A' + path.gsub(/:[\w-]+/, '[\w-]+') + '\Z')
end

# /post/:name
# /post/test_one
# { name: 'test_one' }
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 # { name = > post }
end
end
4 changes: 4 additions & 0 deletions hw2/main.rb
Original file line number Diff line number Diff line change
@@ -1,2 +1,6 @@
require 'rack'
require 'oj'

require './lib/controller'
require './lib/router'
require './app/app'
35 changes: 35 additions & 0 deletions hw2/spec/lib/controller_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
RSpec.describe Controller do
let(:controller) do

Class.new(Controller) do
def text_action
response(:text, 'test text')
end

def json_action
response(:json, params)
end

def data_params
response(:json, some_key: params['some_info'])
end
end
end

context 'shows request status' do
it 'for action with text type' do
expect(controller.action(:text_action).call(Rack::MockRequest.env_for('/test_in_text')))
.to eq([200, { 'Content-Type' => 'text/plain' }, ['test text']])
end

it 'for action with json type' do
expect(controller.action(:json_action).call(Rack::MockRequest.env_for('/test_in_json')))
.to eq([200, { 'Content-Type' => 'application/json' }, ["{}"]])
end
end

it 'shows readed param from address line to params hash' do
expect(controller.action(:data_params).call(Rack::MockRequest.env_for('/message?some_info=key')))
.to eq([200, { 'Content-Type' => 'application/json' }, ["{\":some_key\":\"key\"}"]])
end
end
48 changes: 38 additions & 10 deletions hw2/spec/lib/router_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,10 @@
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 '/users/5', ->(env) { [200, {}, ['get /users/:id']] }
get '/users/5/comments/2/rating/4', ->(env) { [200, {}, ['get /users/:id/comments/:comment/rating/:rating']] }
get '/users/articles/14', ->(env) { [200, {}, ['get /users/articles/:title']]}
get '/', ->(env) { [404, {}, ['page not found']] }
end
end

Expand All @@ -31,4 +26,37 @@
expect(subject.call(env)).to eq [200, {}, ['post test']]
end
end
end

context 'router by pattern /users/:id' do
let(:env) { { 'REQUEST_PATH' => "/users/5", 'REQUEST_METHOD' => 'GET'} }

it 'matches request' do
expect(subject.call(env)).to eq [200, {}, ['get /users/:id']]
end
end

context 'router by pattern /users/:id/comments/:comment/rating/:rating' do
let(:env) { { 'REQUEST_PATH' => "/users/5/comments/2/rating/4", 'REQUEST_METHOD' => 'GET'} }

it 'matches request' do
expect(subject.call(env)).to eq [200, {}, ['get /users/:id/comments/:comment/rating/:rating']]
end
end

context 'router by pattern /users/articles/:title' do
let(:env) { { 'REQUEST_PATH' => "/users/articles/14", 'REQUEST_METHOD' => 'GET'} }

it 'matches request' do
expect(subject.call(env)).to eq [200, {}, ['get /users/articles/:title']]
end
end

context 'when path has parameter' do
let(:env) { { 'REQUEST_PATH' => "/", 'REQUEST_METHOD' => 'GET'} }

it 'returns 404' do
expect(subject.call(env)).to eq [404, {}, ['page not found']]
end
end

end
3 changes: 3 additions & 0 deletions hw2/spec/spec_helper.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
require 'rack'
require 'oj' #optimized json
require './lib/controller'
require './lib/router'

RSpec.configure do |config|
Expand Down
1 change: 1 addition & 0 deletions hw3
Submodule hw3 added at fd37b1