jeanine 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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: []