rapid_runty 0.1.2 → 0.1.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 45302d9a8dbbf57572216e3d7decd9a79504fa51
4
- data.tar.gz: 71527a5d37ac8a023a374bfb5b354738f8f61b7a
3
+ metadata.gz: c8e4a685ba91fc4049a3a5382aa56eb5923ebf10
4
+ data.tar.gz: 10d2e2bb3caf6f36d0ae842b83fc63d0a464035b
5
5
  SHA512:
6
- metadata.gz: b0b02e994bb9479b459d5f15aba669b263887508d74cf71c2ba7a08dfe5f7fe707132f1110e21ea981f50515c85f4ee6103afd6904e55333ef68791ee1d713f5
7
- data.tar.gz: 7d63588dc32c587faed2722be2f2bf547c6990c3d33d22b135f6b9b7d4a693ab9c7d11c1f242cc3db3f4095225c724ad62b6294a43f2486ac6fb53a5eda0eb3c
6
+ metadata.gz: 568008def90b41b16a42e9bec335be81811f2d5775e6337529812e820ab016fcc6377d072c2a229abeabf072034f1809fdb534865853999846ef3cf93d487b17
7
+ data.tar.gz: b09e7e72310f766892f19c7675eced90c7ffe7232b7407b67f96412f9c8ff34b9a0bac36379ccda6cc011faf0af96fcd5faa95464f14d3a6b2889acf286f655d
data/Gemfile CHANGED
@@ -3,5 +3,6 @@ source 'https://rubygems.org'
3
3
  gemspec
4
4
 
5
5
  group :development, :test do
6
+ gem 'haml'
6
7
  gem 'poltergeist', git: 'git://github.com/teampoltergeist/poltergeist.git'
7
8
  end
@@ -1,5 +1,5 @@
1
- require 'rapid_runty/routing'
2
- require 'rapid_runty/controller'
1
+ require 'rapid_runty/router/base_route'
2
+ require 'rapid_runty/controller/base_controller'
3
3
 
4
4
  module RapidRunty
5
5
  ##
@@ -18,21 +18,13 @@ module RapidRunty
18
18
  #
19
19
  # @param env [Hash] Rack environment Hash that includes CGI-like headers
20
20
  #
21
- # @return [status, {headers}, [response]] array
21
+ # @return [status, {headers}, [response]]
22
22
  def call(env)
23
23
  request = Rack::Request.new(env)
24
+ response = Rack::Response.new
24
25
 
25
- verb = request.request_method.downcase.to_sym
26
- path = Rack::Utils.unescape(request.path_info)
27
-
28
- return [500, {}, []] if path == '/favicon.ico'
29
-
30
- route = routes.match(verb, path)
31
- if route.nil?
32
- [404, { 'Content-Type' => 'text/html' }, '404 not found']
33
- else
34
- [200, { 'Content-Type' => 'text/html' }, ["Hello RapidRunty"]]
35
- end
26
+ handle(env, request, response)
27
+ response.finish
36
28
  end
37
29
  end
38
30
  end
@@ -0,0 +1,66 @@
1
+ module RapidRunty
2
+ ##
3
+ # Application base controller
4
+ class BaseController
5
+ attr_reader :env, :response
6
+
7
+ def initialize(env, response)
8
+ @env = env
9
+ @response = response
10
+ end
11
+
12
+ ##
13
+ # Fetch request params
14
+ #
15
+ # @return [Hash] Hash of url parameters
16
+ def params
17
+ @params ||= Rack::Utils.parse_nested_query(env['QUERY_STRING'])
18
+ end
19
+
20
+ ##
21
+ # Render the template with a default layout.
22
+ #
23
+ # @param [String] file name for the template
24
+ def render(view = controller_action)
25
+ render_template(layout) do
26
+ render_template(view)
27
+ end
28
+ end
29
+
30
+ ##
31
+ # Tilt method to render specific template
32
+ #
33
+ # @return Rack::Response compatible response [body, status, header]
34
+ def render_template(path, &block)
35
+ Tilt.new(file(path)).render(self, &block)
36
+ end
37
+
38
+ ##
39
+ # Find template file
40
+ #
41
+ # @return [Path] template path
42
+ def file(path)
43
+ Dir[File.join(ROOT_DIR, 'app', 'views', "#{path}.html.*")].first
44
+ end
45
+
46
+ ##
47
+ # Define Layout template location
48
+ #
49
+ # @return [Path] the layout template location
50
+ def layout
51
+ File.join('layouts', 'application')
52
+ end
53
+
54
+ ##
55
+ # Redirect response method
56
+ def redirect_to(path)
57
+ response.redirect path
58
+ end
59
+
60
+ private
61
+
62
+ def controller_action
63
+ File.join(env['controller'], env['action'])
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,68 @@
1
+ require 'rapid_runty/router/routes'
2
+
3
+ module RapidRunty
4
+ class Application
5
+ attr_reader :routes
6
+
7
+ def initialize
8
+ @routes = RapidRunty::Router::Routes.new
9
+ end
10
+
11
+ # Core response method. Process the request and return the correct
12
+ # response or status message.
13
+ #
14
+ # @param env
15
+ # @param [Rack::Request] request
16
+ # @param [Rack::Response] response
17
+ def handle(env, request, response)
18
+ verb, path = route_args(request).values
19
+
20
+ route = routes.find_route(verb, path)
21
+ if route.nil?
22
+ not_found(response, path)
23
+ else
24
+ param = "&#{Rack::Utils.build_nested_query(route.placeholders)}"
25
+ env['QUERY_STRING'] << param
26
+ env.merge!(route.options)
27
+ response.write dispatch(env, route, response)
28
+ end
29
+ end
30
+
31
+ ##
32
+ # Dispatch the Controller and it's action to be rendered
33
+ def dispatch(env, route, response)
34
+ kontroller, action = route.options.values
35
+
36
+ controller = Object.const_get("#{kontroller.camel_case}Controller")
37
+ controller.new(env, response).public_send(action)
38
+ end
39
+
40
+ ##
41
+ # Default 404 error
42
+ #
43
+ # @param [Rack::Response]
44
+ #
45
+ # @return [Rack::Response]
46
+ def not_found(response, path)
47
+ response.status = 404
48
+ response.write "
49
+ <html>
50
+ <head>
51
+ <body>
52
+ <h1>404 Page not found for #{path}</h1>
53
+ </body>
54
+ </head>
55
+ </html>
56
+ "
57
+ end
58
+
59
+ private
60
+
61
+ def route_args(request)
62
+ {
63
+ verb: request.request_method.downcase.to_sym,
64
+ path: Rack::Utils.unescape(request.path_info)
65
+ }
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,50 @@
1
+ require 'rapid_runty/router/route_parser'
2
+
3
+ module RapidRunty
4
+ module Router
5
+ ##
6
+ # Matches passed in path with array of application paths
7
+ class Matcher
8
+ ##
9
+ # Defines the route that matches the path
10
+ #
11
+ # Example:
12
+ #
13
+ # RapidRunty::Router::Matcher.new.match("/foo", [{url: "/", to: "root#index"}, {url: "/bar", to: "bar#index"}, {url: "/foo", to: "foo#index"}]) #=> ["/foo", [], { controller: "foo", action: "index" }]
14
+ # RapidRunty::Router::Matcher.new.match("/04/01/01", [{url: "/:day/:month/:year", to: "date#find"}]) #=> ["/", ["04", "01", "01"], { controller: "date", action: "find" }]
15
+ # @param path [String] path from ENV["PATH_INFO"]
16
+ # @param application routes [Array] Array of Hash application defined routes
17
+ #
18
+ # Currently only supporting ":to" options which defines the "controller#action"
19
+ #
20
+ # @return [matching_route, matched_placeholders, matched_controller_action] array
21
+ #
22
+ def match(path, routes)
23
+ path = route_parser.new(path)
24
+ url_patterns = routes.map { |route| route_parser.new(route) }
25
+
26
+ url_patterns.each do |pattern|
27
+ return [
28
+ pattern.to_s,
29
+ pattern.placeholders,
30
+ controller_action(pattern.options)
31
+ ] if pattern == path
32
+ end
33
+
34
+ [nil, {}, {}]
35
+ end
36
+
37
+ def controller_action(options)
38
+ Hash[
39
+ %w(controller action).zip options.split('#')
40
+ ]
41
+ end
42
+
43
+ private
44
+
45
+ def route_parser
46
+ RapidRunty::Router::RouteParser
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,16 @@
1
+ module RapidRunty
2
+ module Router
3
+ ##
4
+ # Defines a single user defined route.
5
+ class Route
6
+ attr_accessor :verb, :path, :options, :placeholders
7
+
8
+ def initialize(verb, path, options)
9
+ self.verb = verb
10
+ self.path = path
11
+ self.options = options
12
+ self.placeholders = nil
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,62 @@
1
+ module RapidRunty
2
+ module Router
3
+ ##
4
+ # Parses the route, extracts and return the various important parts of the url.
5
+ #
6
+ # @param [String] the request url
7
+ class RouteParser
8
+ attr_accessor :path, :options
9
+
10
+ def initialize(url)
11
+ self.path = split_url(url[:url])
12
+ self.options = url[:to]
13
+ rescue TypeError
14
+ self.path = split_url(url)
15
+ end
16
+
17
+ def to_s
18
+ '/' + path.join('/')
19
+ end
20
+
21
+ ##
22
+ # Return the present placeholders for the url
23
+ #
24
+ # @return [Hash] of the placeholder key and its value.
25
+ def placeholders
26
+ return {} unless @match
27
+
28
+ placeholders = {}
29
+ path.each_with_index do |part, i|
30
+ placeholders[part.delete(':').to_s] = @match.path[i] if part[0] == ':'
31
+ end
32
+ placeholders
33
+ end
34
+
35
+ def ==(other)
36
+ is_match = size_match?(other) && path_match?(other)
37
+ @match = other if is_match
38
+ is_match
39
+ end
40
+
41
+ private
42
+
43
+ def size_match?(url)
44
+ path.size == url.path.size
45
+ end
46
+
47
+ def path_match?(url)
48
+ path.each_with_index do |part, i|
49
+ return false unless part[0] == ':' || url.path[i] == part
50
+ end
51
+ true
52
+ end
53
+
54
+ def split_url(url)
55
+ url = url.to_s
56
+ path_parts = url.split('/').reject(&:empty?)
57
+ path_parts = [''] if url == '/'
58
+ path_parts
59
+ end
60
+ end
61
+ end
62
+ end
@@ -1,4 +1,6 @@
1
- require 'rapid_runty/routes/matcher'
1
+ require 'rapid_runty/router/route_parser'
2
+ require 'rapid_runty/router/route'
3
+ require 'rapid_runty/router/matcher'
2
4
 
3
5
  module RapidRunty
4
6
  module Router
@@ -6,7 +8,7 @@ module RapidRunty
6
8
  # This class registers all routes defined by the draw method.
7
9
  class Routes < Array
8
10
  def add(*args)
9
- self << Route.new(*args)
11
+ self << RapidRunty::Router::Route.new(*args)
10
12
  end
11
13
 
12
14
  ##
@@ -18,21 +20,30 @@ module RapidRunty
18
20
  # @return A RapidRunty::Router::Route Instance:
19
21
  #
20
22
  # Example:
21
- # RapidRunty::Router::Routes.match("GET", "/foo/4") = #<RapidRunty::Router::Route options={"controller"=>"foo", "action"=>"bar"}, path="/foo/:id", placeholders=[], verb=:get
22
- def match(verb, path)
23
+ # RapidRunty::Router::Routes.find_route("GET", "/foo/4") => #<RapidRunty::Router::Route options={"controller"=>"foo", "action"=>"bar"}, path="/foo/:id", placeholders=[], verb=:get
24
+ def find_route(verb, path)
23
25
  return nil if empty?
24
26
 
25
27
  verb = verb.to_s.downcase.strip.to_sym
26
-
27
28
  routes = select { |route| route.verb == verb }
28
- paths = routes.map { |route| { url: route.path }.merge route.options }
29
29
 
30
- path, places, action = RapidRunty::Router::Matcher.match(path, paths)
31
- return nil if path.nil?
30
+ urls = select_routes_by_verb(verb, routes)
31
+
32
+ find_matching_route(path, urls, routes)
33
+ end
34
+
35
+ def select_routes_by_verb(_verb, routes)
36
+ urls = routes.map { |route| { url: route.path }.merge route.options }
37
+ urls
38
+ end
39
+
40
+ def find_matching_route(path, urls, routes)
41
+ url, placeholders, controller_action = RapidRunty::Router::Matcher.new.match(path, urls)
42
+ return nil if url.nil?
32
43
 
33
- route = routes.detect { |router| router.path == path }.clone
34
- route.placeholders = places
35
- route.options = action
44
+ route = routes.detect { |router| router.path == url }.clone
45
+ route.placeholders = placeholders
46
+ route.options = controller_action
36
47
  route
37
48
  end
38
49
 
@@ -65,16 +76,5 @@ module RapidRunty
65
76
  end
66
77
  end
67
78
  end
68
-
69
- class Route
70
- attr_accessor :verb, :path, :options, :placeholders
71
-
72
- def initialize(verb, path, options)
73
- self.verb = verb
74
- self.path = path
75
- self.options = options
76
- self.placeholders = nil
77
- end
78
- end
79
79
  end
80
80
  end
@@ -14,4 +14,14 @@ class String
14
14
  downcase!
15
15
  self
16
16
  end
17
+
18
+ ##
19
+ # Returns the CamelCase version of a word
20
+ #
21
+ # Example:
22
+ # "index_controller".camel_case = "IndexController"
23
+ def camel_case
24
+ return self if self !~ /_/ && self =~ /[A-Z]+.*/
25
+ split('_').map(&:capitalize).join
26
+ end
17
27
  end
@@ -1,3 +1,3 @@
1
1
  module RapidRunty
2
- VERSION = '0.1.2'.freeze
2
+ VERSION = '0.1.3'.freeze
3
3
  end
data/rapid_runty.gemspec CHANGED
@@ -42,4 +42,6 @@ Gem::Specification.new do |spec|
42
42
  spec.add_dependency 'rack', '~> 2.0'
43
43
  spec.add_dependency 'bundler', '~> 1.12'
44
44
  spec.add_dependency 'thor', '~> 0.19'
45
+ spec.add_dependency 'tilt', '~> 2.0'
46
+ spec.add_dependency 'sqlite3', '~> 1.3'
45
47
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rapid_runty
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.2
4
+ version: 0.1.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Herbert Kagumba
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2016-08-20 00:00:00.000000000 Z
11
+ date: 2016-08-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: pry
@@ -234,6 +234,34 @@ dependencies:
234
234
  - - "~>"
235
235
  - !ruby/object:Gem::Version
236
236
  version: '0.19'
237
+ - !ruby/object:Gem::Dependency
238
+ name: tilt
239
+ requirement: !ruby/object:Gem::Requirement
240
+ requirements:
241
+ - - "~>"
242
+ - !ruby/object:Gem::Version
243
+ version: '2.0'
244
+ type: :runtime
245
+ prerelease: false
246
+ version_requirements: !ruby/object:Gem::Requirement
247
+ requirements:
248
+ - - "~>"
249
+ - !ruby/object:Gem::Version
250
+ version: '2.0'
251
+ - !ruby/object:Gem::Dependency
252
+ name: sqlite3
253
+ requirement: !ruby/object:Gem::Requirement
254
+ requirements:
255
+ - - "~>"
256
+ - !ruby/object:Gem::Version
257
+ version: '1.3'
258
+ type: :runtime
259
+ prerelease: false
260
+ version_requirements: !ruby/object:Gem::Requirement
261
+ requirements:
262
+ - - "~>"
263
+ - !ruby/object:Gem::Version
264
+ version: '1.3'
237
265
  description: A minimal web framework to get your web project up and running in seconds.
238
266
  email:
239
267
  - herbert.kagumba@andela.com
@@ -259,11 +287,13 @@ files:
259
287
  - gemify.sh
260
288
  - lib/rapid_runty.rb
261
289
  - lib/rapid_runty/application.rb
262
- - lib/rapid_runty/controller.rb
290
+ - lib/rapid_runty/controller/base_controller.rb
263
291
  - lib/rapid_runty/dependencies.rb
264
- - lib/rapid_runty/routes/matcher.rb
265
- - lib/rapid_runty/routes/route.rb
266
- - lib/rapid_runty/routing.rb
292
+ - lib/rapid_runty/router/base_route.rb
293
+ - lib/rapid_runty/router/matcher.rb
294
+ - lib/rapid_runty/router/route.rb
295
+ - lib/rapid_runty/router/route_parser.rb
296
+ - lib/rapid_runty/router/routes.rb
267
297
  - lib/rapid_runty/util.rb
268
298
  - lib/rapid_runty/version.rb
269
299
  - rapid_runty.gemspec
@@ -1,12 +0,0 @@
1
- module RapidRunty
2
- # Application controller
3
- #
4
- # TODO: Just saves the env for now
5
- class Controller
6
- def initialize(env)
7
- @env = env
8
- end
9
-
10
- attr_reader :env
11
- end
12
- end
@@ -1,110 +0,0 @@
1
- require 'pathname'
2
-
3
- module RapidRunty
4
- module Router
5
- ##
6
- # Matches passed in path with array of application paths
7
- module Matcher
8
- def self.match(*args)
9
- Base.match(*args)
10
- end
11
-
12
- class Base
13
- ##
14
- # Defines the route that matches the path
15
- #
16
- # Example:
17
- #
18
- # RapidRunty::Router::Matcher.match("/foo", [{url: "/", to: "root#index"}, {url: "/bar", to: "bar#index"}, {url: "/foo", to: "foo#index"}]) #=> ["/foo", [], { controller: "foo", action: "index" }]
19
- # RapidRunty::Router::Matcher.match("/04/01/01", [{url: "/:day/:month/:year", to: "date#find"}]) #=> ["/", ["04", "01", "01"], { controller: "date", action: "find" }]
20
- # @param path [String] path from ENV["PATH_INFO"]
21
- # @param application routes [Array] Array of Hash application defined routes
22
- #
23
- # Currently only supporting ":to" options which defines the "controller#action"
24
- #
25
- # @return [matching_route, matched_placeholders, matched_controller_action] array
26
- #
27
- def self.match(path, routes)
28
- path = Path.new(path)
29
- url_patterns = routes.map { |route| URLPattern.new(route) }
30
-
31
- url_patterns.each do |pattern|
32
- return [
33
- pattern.to_s,
34
- pattern.placeholders,
35
- ControllerSetup.controller_action(pattern.options)
36
- ] if pattern == path
37
- end
38
-
39
- [nil, [], {}]
40
- end
41
- end
42
-
43
- class Path
44
- attr_accessor :parts, :ext, :options
45
-
46
- def initialize(path)
47
- path = Pathname(path)
48
- self.parts, self.ext = split_path(path)
49
- rescue TypeError
50
- self.parts, self.ext = split_path(path[:url])
51
- self.options = path[:to]
52
- end
53
-
54
- def to_s
55
- '/' + parts.join('/') + ext
56
- end
57
-
58
- private
59
-
60
- def split_path(path)
61
- path = path.to_s
62
- ext = Pathname(path).extname
63
- path = path.sub(/#{ext}$/, '')
64
- parts = path.split('/').reject(&:empty?)
65
- parts = [''] if path == '/'
66
- [parts, ext]
67
- end
68
- end
69
-
70
- class URLPattern < Path
71
- def placeholders
72
- return [] unless @match
73
-
74
- vars = []
75
- parts.each_with_index do |part, i|
76
- vars << @match.parts[i] if part[0] == ':'
77
- end
78
- vars
79
- end
80
-
81
- def ==(other)
82
- is_match = size_match?(other) && parts_match?(other)
83
- @match = other if is_match
84
- is_match
85
- end
86
-
87
- private
88
-
89
- def size_match?(path)
90
- parts.size == path.parts.size
91
- end
92
-
93
- def parts_match?(path)
94
- parts.each_with_index do |part, i|
95
- return true if part[0] == ':' || path.parts[i] == part
96
- end
97
- false
98
- end
99
- end
100
-
101
- class ControllerSetup
102
- def self.controller_action(options)
103
- Hash[
104
- %w(controller action).zip options.split('#')
105
- ]
106
- end
107
- end
108
- end
109
- end
110
- end
@@ -1,11 +0,0 @@
1
- require 'rapid_runty/routes/route'
2
-
3
- module RapidRunty
4
- class Application
5
- attr_reader :routes
6
-
7
- def initialize
8
- @routes = RapidRunty::Router::Routes.new
9
- end
10
- end
11
- end