jeanine 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 8d88a21a82401395ddca515402a07e3155939eb0
4
+ data.tar.gz: e6edce8a4097864466149cf6769765332a868c76
5
+ SHA512:
6
+ metadata.gz: 17f7d684adeefc7ec56e7244c6c53fddeafb9d037e4a1ee9aab94d8925193a39a95d0a079ba2aad85ae3f5a64b972315a7893f6ced6d07ba7e693923be9cc67e
7
+ data.tar.gz: 82082d64a1620c947e51aa84d9ada5701825c0525061cd930022b8ef68611338570fc64f20038a4605e48bf1d27578c668ff2923a0ef7d88bc3b55435792877d
@@ -0,0 +1,26 @@
1
+ require 'forwardable'
2
+ require 'logger'
3
+
4
+ require "jeanine/version"
5
+ require 'jeanine/core_ext'
6
+ require 'jeanine/router'
7
+ require 'jeanine/app'
8
+ require 'tilt'
9
+
10
+ module Jeanine
11
+ def self.tilt_cache
12
+ @title_cache ||= Tilt::Cache.new
13
+ end
14
+
15
+ def self.logger
16
+ @logger ||= Logger.new(STDOUT)
17
+ end
18
+
19
+ def logger=(val)
20
+ @logger = val
21
+ end
22
+
23
+ def self.router
24
+ @router ||= Router.new
25
+ end
26
+ end
@@ -0,0 +1,68 @@
1
+ require 'jeanine/callbacks'
2
+ require 'jeanine/mimes'
3
+ require 'jeanine/request'
4
+ require 'jeanine/response'
5
+ require 'jeanine/renderer'
6
+ require 'jeanine/routing'
7
+
8
+ module Jeanine
9
+ class App
10
+ include Routing::Evaluation
11
+ attr_reader :request, :response
12
+ class << self
13
+ include Routing::DSL
14
+ include Callbacks
15
+
16
+ alias :_new :new
17
+ def new(*args, &block)
18
+ initialize!
19
+ stack.run _new(*args, &block)
20
+ stack
21
+ end
22
+
23
+ def initialize!
24
+ Mimes.load!
25
+ end
26
+
27
+ def stack
28
+ @stack ||= Rack::Builder.new
29
+ end
30
+
31
+ def router
32
+ Jeanine.router
33
+ end
34
+
35
+ def call(env)
36
+ new.call env
37
+ end
38
+ end
39
+
40
+ def call(env)
41
+ @env = env
42
+ @request = Jeanine::Request.new(env)
43
+ @response = Jeanine::Response.new
44
+ catch(:halt) { route_eval }
45
+ end
46
+
47
+ private
48
+
49
+ def params
50
+ @params ||= if @request.format
51
+ @request.params.merge({ format: @request.format })
52
+ else
53
+ @request.params
54
+ end
55
+ end
56
+
57
+ def render(*args)
58
+ @response.action_variables = instance_variables_cache
59
+ Renderer.new(@response).render(*args)
60
+ end
61
+
62
+ def instance_variables_cache
63
+ instance_variables.each_with_object({}) do |var, obj|
64
+ obj[var] = instance_variable_get(var)
65
+ end
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,28 @@
1
+ module Jeanine
2
+ module Callbacks
3
+ def _callbacks
4
+ @_callbacks ||= {
5
+ before: [],
6
+ after: [],
7
+ before_all: [],
8
+ after_all: []
9
+ }
10
+ end
11
+
12
+ def _register_callback(type, paths = [], &block)
13
+ if paths == []
14
+ _callbacks["#{type}_all".to_sym] << { block: block }
15
+ else
16
+ _callbacks[type] << { paths: paths, block: block }
17
+ end
18
+ end
19
+
20
+ def before(*paths, &block)
21
+ _register_callback(:before, paths, &block)
22
+ end
23
+
24
+ def after(*paths, &block)
25
+ _register_callback(:after, paths, &block)
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,4 @@
1
+ require 'jeanine/core_ext/array'
2
+ require 'jeanine/core_ext/hash'
3
+ require 'jeanine/core_ext/nil_class'
4
+ require 'jeanine/core_ext/string'
@@ -0,0 +1,5 @@
1
+ class Array
2
+ def extract_options!
3
+ last.is_a?(::Hash) ? pop : {}
4
+ end
5
+ end
@@ -0,0 +1,8 @@
1
+ class Hash
2
+ def reverse_merge(other_hash)
3
+ other_hash.merge(self)
4
+ end
5
+ def reverse_merge!(other_hash)
6
+ replace(reverse_merge(other_hash))
7
+ end
8
+ end
@@ -0,0 +1,5 @@
1
+ class NilClass
2
+ def presence
3
+ nil
4
+ end
5
+ end
@@ -0,0 +1,6 @@
1
+ class String
2
+ def presence
3
+ return nil if self.empty?
4
+ self
5
+ end
6
+ end
@@ -0,0 +1,18 @@
1
+ module Broding
2
+ module Environment
3
+ def env
4
+ @_env ||= (ENV["RACK_ENV"].presence || "development")
5
+ end
6
+
7
+ def groups(*groups)
8
+ hash = groups.extract_options!
9
+ env = Jeanine.env
10
+ groups.unshift(:default, env)
11
+ groups.concat ENV["BRODY_GROUPS"].to_s.split(",")
12
+ groups.concat hash.map { |k, v| k if v.map(&:to_s).include?(env) }
13
+ groups.compact!
14
+ groups.uniq!
15
+ groups
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,76 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Jeanine
4
+ class Headers
5
+ CGI_VARIABLES = Set.new(%W[
6
+ AUTH_TYPE
7
+ CONTENT_LENGTH
8
+ CONTENT_TYPE
9
+ GATEWAY_INTERFACE
10
+ HTTPS
11
+ PATH_INFO
12
+ PATH_TRANSLATED
13
+ QUERY_STRING
14
+ REMOTE_ADDR
15
+ REMOTE_HOST
16
+ REMOTE_IDENT
17
+ REMOTE_USER
18
+ REQUEST_METHOD
19
+ SCRIPT_NAME
20
+ SERVER_NAME
21
+ SERVER_PORT
22
+ SERVER_PROTOCOL
23
+ SERVER_SOFTWARE
24
+ ]).freeze
25
+
26
+ HTTP_HEADER = /\A[A-Za-z0-9-]+\z/
27
+
28
+ include Enumerable
29
+
30
+ def initialize(request)
31
+ @req = request
32
+ end
33
+
34
+ def [](key)
35
+ @req.get_header env_name(key)
36
+ end
37
+
38
+ def key?(key)
39
+ @req.has_header? env_name(key)
40
+ end
41
+ alias :include? :key?
42
+
43
+ DEFAULT = Object.new
44
+
45
+ def fetch(key, default = DEFAULT)
46
+ @req.fetch_header(env_name(key)) do
47
+ return default unless default == DEFAULT
48
+ return yield if block_given?
49
+ raise KeyError, key
50
+ end
51
+ end
52
+
53
+ def each(&block)
54
+ @req.each_header(&block)
55
+ end
56
+
57
+ def to_h
58
+ obj = {}
59
+ each do |k,v|
60
+ obj[k] = v
61
+ end
62
+ obj
63
+ end
64
+
65
+ private
66
+
67
+ def env_name(key)
68
+ key = key.to_s
69
+ if HTTP_HEADER.match?(key)
70
+ key = key.upcase.tr("-", "_")
71
+ key = "HTTP_" + key unless CGI_VARIABLES.include?(key)
72
+ end
73
+ key
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,33 @@
1
+ module Jeanine
2
+ class Mimes
3
+ MimeTypeNotFound = Class.new(StandardError)
4
+ MIME_TYPES_INVERTED = Rack::Mime::MIME_TYPES.invert
5
+
6
+ def self.load!
7
+ register(:json, Rack::Mime::MIME_TYPES[".json"])
8
+ register(:html, Rack::Mime::MIME_TYPES[".html"])
9
+ register(:text, Rack::Mime::MIME_TYPES[".text"])
10
+ register(:plain, self.for(:text))
11
+ end
12
+
13
+ def self.register(type, header)
14
+ mime_types[type] = header
15
+ end
16
+
17
+ def self.for(type)
18
+ mime_types.fetch(type) do
19
+ raise(MimeTypeNotFound, "Mime #{type} not registered")
20
+ end
21
+ end
22
+
23
+ def self.mime_types
24
+ @mime_types ||= {}
25
+ end
26
+
27
+ private_class_method :mime_types
28
+
29
+ def initialize(*)
30
+ raise "Should not be initialiazed"
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,73 @@
1
+ module Jeanine
2
+ class PathProxy
3
+ def initialize(context, pathname, options = {})
4
+ @context = context
5
+ @pathname = pathname
6
+ @options = options
7
+ end
8
+
9
+ def get(path = nil, options = {}, &block)
10
+ @options.reverse_merge!(options)
11
+ @context.get(merged_path(path), options, &block)
12
+ end
13
+
14
+ def post(path = nil, options = {}, &block)
15
+ @options.reverse_merge!(options)
16
+ @context.post(merged_path(path), options, &block)
17
+ end
18
+
19
+ def patch(path = nil, options = {}, &block)
20
+ @options.reverse_merge!(options)
21
+ @context.patch(merged_path(path), options, &block)
22
+ end
23
+
24
+ def put(path = nil, options = {}, &block)
25
+ @options.reverse_merge!(options)
26
+ @context.put(merged_path(path), options, &block)
27
+ end
28
+
29
+ def options(path = nil, options = {}, &block)
30
+ @options.reverse_merge!(options)
31
+ @context.options(merged_path(path), options, &block)
32
+ end
33
+
34
+ def head(path = nil, options = {}, &block)
35
+ @options.reverse_merge!(options)
36
+ @context.head(merged_path(path), options, &block)
37
+ end
38
+
39
+ def delete(path = nil, options = {}, &block)
40
+ @options.reverse_merge!(options)
41
+ @context.delete(merged_path(path), options, &block)
42
+ end
43
+
44
+ def path(path = nil, options = {}, &block)
45
+ @options.reverse_merge!(options)
46
+ @context.path(merged_path(path), options, &block)
47
+ end
48
+
49
+ def match(path = nil, options = {}, &block)
50
+ @options.reverse_merge!(options)
51
+ @context.match(merged_path(path), options, &block)
52
+ end
53
+
54
+ def root(path = '/', options = {}, &block)
55
+ @options.reverse_merge!(options)
56
+ @context.root(merged_path(path), options, &block)
57
+ end
58
+
59
+ def before(*paths, &block)
60
+ @context.before(*paths, &block)
61
+ end
62
+
63
+ def after(*paths, &block)
64
+ @context.after(*paths, &block)
65
+ end
66
+
67
+ private
68
+
69
+ def merged_path(path)
70
+ [@pathname, path].join
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,130 @@
1
+ require 'jeanine/view'
2
+
3
+ module Jeanine
4
+ class Renderer
5
+ def self._renderers
6
+ @_renderers ||= Set.new
7
+ end
8
+
9
+ def self.add(key, &block)
10
+ define_method(_render_with_renderer_method_name(key), &block)
11
+ _renderers << key.to_sym
12
+ end
13
+
14
+ def _render_with_renderer_method_name(key)
15
+ self.class._render_with_renderer_method_name(key)
16
+ end
17
+
18
+ def self._render_with_renderer_method_name(key)
19
+ "_render_with_renderer_#{key}"
20
+ end
21
+
22
+ def initialize(response)
23
+ @response = response
24
+ end
25
+
26
+ def render(*args)
27
+ options = _normalize_render(*args)
28
+ _render_to_body_with_renderer(options)
29
+ end
30
+
31
+ private
32
+
33
+ def _normalize_render(*args, &block)
34
+ options = _normalize_args(*args, &block)
35
+ _normalize_options(options)
36
+ options
37
+ end
38
+
39
+ def _normalize_args(action = nil, options = {})
40
+ if action.is_a?(Hash)
41
+ action
42
+ else
43
+ options
44
+ end
45
+ end
46
+
47
+ def _normalize_options(options)
48
+ options
49
+ end
50
+
51
+ def _render_to_body_with_renderer(options)
52
+ self.class._renderers.each do |name|
53
+ if options.key?(name)
54
+ _process_options(options)
55
+ method_name = _render_with_renderer_method_name(name)
56
+ return send(method_name, options.delete(name), options)
57
+ end
58
+ end
59
+ nil
60
+ end
61
+
62
+ def _process_options(options)
63
+ status, content_type, location = options.values_at(:status, :content_type, :location)
64
+ @response.status = status if status
65
+ @response.content_type = content_type if content_type
66
+ @response.headers["Location"] = location if location
67
+ end
68
+
69
+ add :json do |json, options|
70
+ json = json.to_json(options) unless json.is_a?(String)
71
+
72
+ if options[:callback]
73
+ "/**/#{options[:callback]}(#{json})"
74
+ else
75
+ @response.content_type = Mimes.for(:json)
76
+ json
77
+ end
78
+ end
79
+
80
+ def cache
81
+ Thread.current[:tilt_cache] ||= Tilt::Cache.new
82
+ end
83
+
84
+ def html(engine, template_name, options = {}, locals = {}, &block)
85
+ locals = options.delete(:locals) || locals || {}
86
+ layout = options[:layout]
87
+ scope = options.delete(:scope) || self
88
+ options.delete(:layout)
89
+ options[:outvar] ||= '@_out_buf'
90
+ options[:default_encoding] ||= "UTF-8"
91
+ template = compile_template(engine, template_name, options)
92
+ output = template.render(scope, locals, &block)
93
+ if layout
94
+ unless layout.include?("layouts/")
95
+ layout = "layouts/#{layout}"
96
+ end
97
+ options = options.merge(layout: false, scope: scope)
98
+ catch(:layout_missing) { return html(engine, layout, options, locals) { output } }
99
+ end
100
+ output
101
+ end
102
+
103
+ def compile_template(engine, template_name, options)
104
+ Tilt::Cache.new.fetch engine, template_name, options do
105
+ template = Tilt[engine]
106
+ raise "Template engine not found: #{engine}" if template.nil?
107
+ template.new("views/#{template_name}", options)
108
+ end
109
+ end
110
+
111
+ add :template do |template, options|
112
+ view = Jeanine::View.new
113
+ @response.action_variables.each do |k,v|
114
+ view.instance_variable_set(k, v.dup)
115
+ end
116
+ options[:scope] = view
117
+ html(:erb, template, options)
118
+ end
119
+
120
+ add :text do |text, _options|
121
+ @response.content_type = Mimes.for(:text)
122
+ text
123
+ end
124
+
125
+ add :plain do |text, _options|
126
+ @response.content_type = Mimes.for(:plain)
127
+ text
128
+ end
129
+ end
130
+ end
@@ -0,0 +1,64 @@
1
+ require 'rack/request'
2
+ require 'jeanine/headers'
3
+
4
+ module Jeanine
5
+ class Request < Rack::Request
6
+ FORMAT_REGEX = %r{\.(\w+)\z}
7
+
8
+ def initialize(env)
9
+ env['PATH_INFO'] = '/' if env['PATH_INFO'].empty?
10
+ if env['PATH_INFO'].include?(".")
11
+ format = env['PATH_INFO'].match(FORMAT_REGEX)
12
+ if format
13
+ @format = format.captures[0]
14
+ env['PATH_INFO'].gsub!(FORMAT_REGEX, '')
15
+ end
16
+ end
17
+ super
18
+ end
19
+
20
+ def headers
21
+ @headers ||= Jeanine::Headers.new(self)
22
+ end
23
+
24
+ def post?
25
+ request_method == 'POST'
26
+ end
27
+
28
+ def get?
29
+ request_method == 'GET'
30
+ end
31
+
32
+ def delete?
33
+ request_method == 'DELETE'
34
+ end
35
+
36
+ def put?
37
+ request_method == 'PUT'
38
+ end
39
+
40
+ def patch?
41
+ request_method == 'PATCH'
42
+ end
43
+
44
+ def options?
45
+ request_method == 'options'
46
+ end
47
+
48
+ def head?
49
+ request_method == 'head'
50
+ end
51
+
52
+ def json?
53
+ format == 'json'
54
+ end
55
+
56
+ def mime_type
57
+ @mime_type ||= Mimes::MIME_TYPES_INVERTED[content_type]
58
+ end
59
+
60
+ def format
61
+ @format || Rack::Mime::MIME_TYPES[content_type]
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,49 @@
1
+ require 'forwardable'
2
+ require 'json'
3
+
4
+ module Jeanine
5
+ class Response
6
+ attr_accessor :action_variables
7
+ attr_reader :headers, :body
8
+ attr_accessor :status
9
+
10
+ def initialize(body = [], status = 200, headers = { 'Content-Type' => 'text/html; charset=utf-8' })
11
+ @body = body
12
+ @status = status
13
+ @headers = headers
14
+ @length = 0
15
+
16
+ return if body == []
17
+ if body.respond_to? :to_str
18
+ write body.to_str
19
+ elsif body.respond_to? :each
20
+ body.each { |i| write i.to_s }
21
+ else
22
+ raise TypeError, 'body must #respond_to? #to_str or #each'
23
+ end
24
+ end
25
+
26
+ def complete!
27
+ unless (100..199).include?(status) || status == 204
28
+ headers['Content-Length'] = @length.to_s
29
+ end
30
+ [status, headers, body]
31
+ end
32
+
33
+ def content_type=(type)
34
+ headers['Content-Type'] = type
35
+ end
36
+
37
+ def redirect_to(target, status = 302)
38
+ self.status = status
39
+ headers['Location'] = target
40
+ end
41
+
42
+ def write(string)
43
+ s = string.to_s
44
+ @length += s.bytesize
45
+
46
+ body << s
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,38 @@
1
+ require 'forwardable'
2
+
3
+ module Jeanine
4
+ class Router
5
+ extend Forwardable
6
+
7
+ def_delegators :@routes, :[]
8
+
9
+ attr_reader :routes
10
+ def initialize
11
+ @routes = {
12
+ GET: [],
13
+ POST: [],
14
+ PATCH: [],
15
+ PUT: [],
16
+ DELETE: [],
17
+ OPTIONS: [],
18
+ HEAD: [],
19
+ }
20
+ end
21
+
22
+ def add(verb, path, options = {}, &block)
23
+ routes[verb] << build_route("#{path}", options, &block)
24
+ end
25
+
26
+ private
27
+
28
+ def build_route(path, options = {}, &block)
29
+ route = { path: "#{path}", compiled_path: nil, params: [], block: block }
30
+ compiled_path = route[:path].gsub(/:\w+/) do |match|
31
+ route[:params] << match.tr(':', '').to_sym
32
+ '([^/?#]+)'
33
+ end
34
+ route[:compiled_path] = /^#{compiled_path}?$/
35
+ route
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,2 @@
1
+ require 'jeanine/routing/dsl'
2
+ require 'jeanine/routing/evaluation'
@@ -0,0 +1,60 @@
1
+ require 'jeanine/path_proxy'
2
+
3
+ module Jeanine
4
+ module Routing
5
+ module DSL
6
+ extend SingleForwardable
7
+
8
+ RouteError = Class.new(StandardError)
9
+
10
+ def_delegator :Jeanine, :router
11
+
12
+ def get(path = nil, options = {}, &block)
13
+ router.add(:GET, path, options, &block)
14
+ end
15
+
16
+ def post(path = nil, options = {}, &block)
17
+ router.add(:POST, path, options, &block)
18
+ end
19
+
20
+ def put(path = nil, options = {}, &block)
21
+ router.add(:PUT, path, options, &block)
22
+ end
23
+
24
+ def patch(path = nil, options = {}, &block)
25
+ router.add(:PATCH, path, options, &block)
26
+ end
27
+
28
+ def head(path = nil, options = {}, &block)
29
+ router.add(:HEAD, path, options, &block)
30
+ end
31
+
32
+ def options(path = nil, options = {}, &block)
33
+ router.add(:OPTIONS, path, options, &block)
34
+ end
35
+
36
+ def delete(path = nil, options = {}, &block)
37
+ router.add(:DELETE, path, options, &block)
38
+ end
39
+
40
+ def path(pathname, options = {}, &block)
41
+ option_merger = Jeanine::PathProxy.new(self, pathname, options)
42
+ option_merger.instance_eval(&block)
43
+ end
44
+
45
+ def root(path = "/", options = {}, &block)
46
+ router.add(:GET, path, options, &block)
47
+ end
48
+
49
+ def match(path = nil, options = {}, &block)
50
+ via = options.delete(:via)
51
+ unless via.is_a?(Array)
52
+ raise RouteError, "options[:via] must be an array of HTTP verbs"
53
+ end
54
+ via.each do |verb|
55
+ router.add(verb.upcase, path, options, &block)
56
+ end
57
+ end
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,96 @@
1
+ module Jeanine
2
+ module Routing
3
+ module Evaluation
4
+ IGNORED_INSTANCE_VARIABLES = [:@env]
5
+ def route_eval
6
+ before_find_route!
7
+ route = find_route
8
+
9
+ if route
10
+ before_evaluate_route!
11
+ result = instance_eval(&route[:block])
12
+ @response.write(result)
13
+ after_evaluate_route!
14
+ else
15
+ @response.status = 404
16
+ end
17
+ after_response!
18
+ @response.complete!
19
+ end
20
+
21
+ private
22
+
23
+ def find_route
24
+ matches = nil
25
+ route = Jeanine.router[@request.request_method.to_sym].detect do |r|
26
+ matches = r[:compiled_path].match(@request.path_info)
27
+ !matches.nil?
28
+ end
29
+
30
+ return nil if route.nil?
31
+ return route if route && route[:params].empty?
32
+
33
+ index = 0
34
+ while index < matches.captures.size
35
+ param = route[:params][index]
36
+ @request.params[param] = matches.captures[index]
37
+ if index == match.captures.size
38
+ @request.params[param].gsub!(@request.format)
39
+ end
40
+ index += 1
41
+ end
42
+
43
+ route
44
+ end
45
+
46
+ def before_find_route!
47
+ run_before_callbacks!(:before_all)
48
+ end
49
+
50
+ def before_evaluate_route!
51
+ run_before_callbacks!(:before)
52
+ end
53
+
54
+ def after_evaluate_route!
55
+ run_after_callbacks!(:after)
56
+ end
57
+
58
+ def after_response!
59
+ run_after_callbacks!(:after_all)
60
+ end
61
+
62
+ def run_before_callbacks!(type)
63
+ if type == :before_all
64
+ self.class._callbacks[type].each { |callback| eval_callback(&callback[:block]) }
65
+ else
66
+ matching_callbacks(type) do |callback|
67
+ eval_callback(&callback[:block])
68
+ end
69
+ end
70
+ end
71
+
72
+ def run_after_callbacks!(type)
73
+ if type == :after_all
74
+ self.class._callbacks[type].each { |callback| eval_callback(&callback[:block]) }
75
+ else
76
+ matching_callbacks(type) do |callback|
77
+ eval_callback(&callback[:block])
78
+ end
79
+ end
80
+ end
81
+
82
+ def matching_callbacks(type)
83
+ self.class._callbacks[type].select do |callback|
84
+ paths = callback[:paths]
85
+ if paths.detect { |path| path.match?(@request.path_info) }
86
+ yield callback
87
+ end
88
+ end
89
+ end
90
+
91
+ def eval_callback(*args, &callback)
92
+ instance_exec(*args, &callback)
93
+ end
94
+ end
95
+ end
96
+ end
@@ -0,0 +1,3 @@
1
+ module Jeanine
2
+ VERSION = "0.1.0"
3
+ end
@@ -0,0 +1,4 @@
1
+ module Jeanine
2
+ class View
3
+ end
4
+ end
metadata ADDED
@@ -0,0 +1,124 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: jeanine
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Josh Brody
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2020-07-07 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rack
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: tilt
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rspec
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ description: A framework.
70
+ email:
71
+ - git@josh.mn
72
+ executables: []
73
+ extensions: []
74
+ extra_rdoc_files: []
75
+ files:
76
+ - lib/jeanine.rb
77
+ - lib/jeanine/app.rb
78
+ - lib/jeanine/callbacks.rb
79
+ - lib/jeanine/core_ext.rb
80
+ - lib/jeanine/core_ext/array.rb
81
+ - lib/jeanine/core_ext/hash.rb
82
+ - lib/jeanine/core_ext/nil_class.rb
83
+ - lib/jeanine/core_ext/string.rb
84
+ - lib/jeanine/environment.rb
85
+ - lib/jeanine/headers.rb
86
+ - lib/jeanine/mimes.rb
87
+ - lib/jeanine/path_proxy.rb
88
+ - lib/jeanine/renderer.rb
89
+ - lib/jeanine/request.rb
90
+ - lib/jeanine/response.rb
91
+ - lib/jeanine/router.rb
92
+ - lib/jeanine/routing.rb
93
+ - lib/jeanine/routing/dsl.rb
94
+ - lib/jeanine/routing/evaluation.rb
95
+ - lib/jeanine/version.rb
96
+ - lib/jeanine/view.rb
97
+ homepage: https://github.com/joshmn/jeanine
98
+ licenses:
99
+ - MIT
100
+ metadata:
101
+ homepage_uri: https://github.com/joshmn/jeanine
102
+ source_code_uri: https://github.com/joshmn/jeanine
103
+ changelog_uri: https://github.com/joshmn/jeanine
104
+ post_install_message:
105
+ rdoc_options: []
106
+ require_paths:
107
+ - lib
108
+ required_ruby_version: !ruby/object:Gem::Requirement
109
+ requirements:
110
+ - - ">="
111
+ - !ruby/object:Gem::Version
112
+ version: 2.3.0
113
+ required_rubygems_version: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ requirements: []
119
+ rubyforge_project:
120
+ rubygems_version: 2.6.14.3
121
+ signing_key:
122
+ specification_version: 4
123
+ summary: A framework.
124
+ test_files: []