jeanine 0.2.0 → 0.7.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: a9120ffa8994858a7560330fa0afbe1bf18e2f94
4
- data.tar.gz: fd326e260cc8c90a5b70b8b8ad4a1cd5b0b9869a
3
+ metadata.gz: d3df31123e22ecf9f1dd465af168aa34b3199e75
4
+ data.tar.gz: 9fb4883db99cbf0a30b4895064bcb10f00896c6c
5
5
  SHA512:
6
- metadata.gz: 8b11b5b73abed4a7df44caf5a7b53ad6d2d52616fc23658e8c0d864239c0dc7b3fdfb6837c6d611f593944ad2518d92cc9af945ec3185a7bdfd783f913c3309c
7
- data.tar.gz: 2ca9b7d2196c08e57bda6f983cfb0a1da71c06772bb6b42b76deb0aa941d5cb454eef4041d9834f8b3eeea9644d5a86b22e48de5f6b951a32e39481d9ac631a4
6
+ metadata.gz: e871411c10b283ab9ad26c5b568870e651dc25110cb1e5ea842e607dfe1d3d28dfac640bb574cfe19ee0bb01575668e1906fdbd2c9d5304e0c85a75977d3bfd4
7
+ data.tar.gz: 214f87e732bbfa864f5b64574c27b4a284c260c7447dc867af01a94da52edac49308d427da84c19846b8c540a2309ab3d81117b99b6f4330df04b194b3b5c65a
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require_relative '../lib/jeanine/cli'
4
+
5
+ Jeanine::CLI.new(ARGV).execute
@@ -1,15 +1,14 @@
1
+ require 'rack'
2
+
1
3
  require 'forwardable'
2
4
  require 'logger'
3
5
 
4
6
  require "jeanine/version"
5
7
  require 'jeanine/core_ext'
6
- require 'jeanine/router'
7
- require 'jeanine/app'
8
- require 'tilt'
9
8
 
10
9
  module Jeanine
11
- def self.tilt_cache
12
- @title_cache ||= Tilt::Cache.new
10
+ def self._installed_plugins
11
+ @_installed_plugins ||= []
13
12
  end
14
13
 
15
14
  def self.logger
@@ -23,4 +22,7 @@ module Jeanine
23
22
  def self.router
24
23
  @router ||= Router.new
25
24
  end
25
+
26
+ autoload :Router, 'jeanine/router'
27
+ autoload :App, 'jeanine/app'
26
28
  end
@@ -1,22 +1,36 @@
1
- require 'jeanine/callbacks'
2
1
  require 'jeanine/mimes'
3
2
  require 'jeanine/request'
4
- require 'jeanine/rescuing'
5
3
  require 'jeanine/response'
6
- require 'jeanine/renderer'
7
4
  require 'jeanine/routing'
8
- require 'jeanine/session'
9
5
 
10
6
  module Jeanine
11
7
  class App
12
- include Session
13
8
  include Routing::Evaluation
9
+
14
10
  attr_reader :request, :response
15
11
 
12
+ def self.plugin(name)
13
+ unless Jeanine._installed_plugins.include?(name)
14
+ unless const_defined?("Jeanine::#{name}")
15
+ require "jeanine/#{name.to_s.underscore}"
16
+ end
17
+ include Kernel.const_get("Jeanine::#{name}")
18
+ Jeanine._installed_plugins << name
19
+ end
20
+ end
21
+
22
+ def self.installed_plugins
23
+ Jeanine._installed_plugins
24
+ end
25
+
26
+ # plugin :Callbacks
27
+ # plugin :Rendering
28
+ # plugin :Rescuing
29
+ # plugin :Session
30
+
16
31
  class << self
17
- include Callbacks
18
32
  include Routing::DSL
19
- include Rescuing
33
+
20
34
  alias :_new :new
21
35
  def new(*args, &block)
22
36
  initialize!
@@ -41,24 +55,11 @@ module Jeanine
41
55
  end
42
56
  end
43
57
 
44
- include Rescuing
45
-
46
58
  def call(env)
47
- begin
48
- @env = env
49
- @request = Jeanine::Request.new(env)
50
- @response = Jeanine::Response.new
51
- catch(:halt) { route_eval }
52
- rescue => error
53
- handler = self.class.rescue_handlers[error.class]
54
- raise error unless handler
55
- if handler.is_a?(Symbol)
56
- @response.write(send(handler, error))
57
- else
58
- @response.write(instance_exec(error, &handler))
59
- end
60
- @response.complete!
61
- end
59
+ @env = env
60
+ @request = Jeanine::Request.new(env)
61
+ @response = Jeanine::Response.new
62
+ catch(:halt) { route_eval }
62
63
  end
63
64
 
64
65
  private
@@ -71,11 +72,6 @@ module Jeanine
71
72
  end
72
73
  end
73
74
 
74
- def render(*args)
75
- @response.action_variables = instance_variables_cache
76
- Renderer.new(@response).render(*args)
77
- end
78
-
79
75
  def instance_variables_cache
80
76
  instance_variables.each_with_object({}) do |var, obj|
81
77
  obj[var] = instance_variable_get(var)
@@ -1,28 +1,106 @@
1
1
  module Jeanine
2
2
  module Callbacks
3
- def _callbacks
4
- @_callbacks ||= {
5
- before: [],
6
- after: [],
7
- before_all: [],
8
- after_all: []
9
- }
3
+ def self.included(klass)
4
+ klass.extend InstanceMethods
5
+ klass.prepend EvaluationMethods
10
6
  end
11
7
 
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 }
8
+ module InstanceMethods
9
+ def _callbacks
10
+ @_callbacks ||= {
11
+ before: [],
12
+ after: [],
13
+ before_all: [],
14
+ after_all: []
15
+ }
16
+ end
17
+
18
+ def before(*paths, &block)
19
+ _register_callback(:before, paths, &block)
17
20
  end
18
- end
19
21
 
20
- def before(*paths, &block)
21
- _register_callback(:before, paths, &block)
22
+ def after(*paths, &block)
23
+ _register_callback(:after, paths, &block)
24
+ end
25
+
26
+ private
27
+
28
+ def _register_callback(type, paths = [], &block)
29
+ if paths == []
30
+ _callbacks["#{type}_all".to_sym] << { block: block }
31
+ else
32
+ _callbacks[type] << { paths: paths, block: block }
33
+ end
34
+ end
22
35
  end
23
36
 
24
- def after(*paths, &block)
25
- _register_callback(:after, paths, &block)
37
+ module EvaluationMethods
38
+ def route_eval
39
+ before_find_route!
40
+ route = find_route
41
+
42
+ if route
43
+ before_evaluate_route!
44
+ result = instance_eval(&route[:block])
45
+ @response.write(result)
46
+ after_evaluate_route!
47
+ else
48
+ @response.status = 404
49
+ end
50
+ after_response!
51
+ @response.complete!
52
+ end
53
+
54
+ private
55
+
56
+ def before_find_route!
57
+ run_before_callbacks!(:before_all)
58
+ end
59
+
60
+ def before_evaluate_route!
61
+ run_before_callbacks!(:before)
62
+ end
63
+
64
+ def after_evaluate_route!
65
+ run_after_callbacks!(:after)
66
+ end
67
+
68
+ def after_response!
69
+ run_after_callbacks!(:after_all)
70
+ end
71
+
72
+ def run_before_callbacks!(type)
73
+ if type == :before_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 run_after_callbacks!(type)
83
+ if type == :after_all
84
+ self.class._callbacks[type].each { |callback| eval_callback(&callback[:block]) }
85
+ else
86
+ matching_callbacks(type) do |callback|
87
+ eval_callback(&callback[:block])
88
+ end
89
+ end
90
+ end
91
+
92
+ def matching_callbacks(type)
93
+ self.class._callbacks[type].select do |callback|
94
+ paths = callback[:paths]
95
+ if paths.detect { |path| path.match?(@request.path_info) }
96
+ yield callback
97
+ end
98
+ end
99
+ end
100
+
101
+ def eval_callback(*args, &callback)
102
+ instance_exec(*args, &callback)
103
+ end
26
104
  end
27
105
  end
28
106
  end
@@ -0,0 +1,32 @@
1
+ require 'fileutils'
2
+
3
+ module Jeanine
4
+ class CLI
5
+ def initialize(args)
6
+ @args = args
7
+ end
8
+
9
+ def execute
10
+ if @args[0] == 'new'
11
+ command_new!
12
+ else
13
+ $stdout.puts "I don't know how to `#{@args[0]}`. Maybe you meant `new`?"
14
+ end
15
+ end
16
+
17
+ def command_new!
18
+ FileUtils.mkdir("#{@args[1]}") unless Dir.exists?("#{@args[1]}")
19
+ FileUtils.mkdir("#{@args[1]}/config") unless Dir.exists?("#{@args[1]}/config")
20
+ relative_dir = "lib/jeanine/generator/new"
21
+ Dir.glob("lib/jeanine/generator/new/**/*.*").each do |file|
22
+ new_dir = file.gsub(relative_dir, "#{@args[1]}")[0...-3]
23
+ FileUtils.copy_file(file, new_dir)
24
+ end
25
+ relative_dir = "lib/jeanine/generator/new/config"
26
+ Dir.glob("lib/jeanine/generator/new/config/**/*.*").each do |file|
27
+ new_dir = file.gsub(relative_dir, "#{@args[1]}/config")[0...-3]
28
+ FileUtils.copy_file(file, new_dir)
29
+ end
30
+ end
31
+ end
32
+ end
@@ -5,4 +5,19 @@ class Hash
5
5
  def reverse_merge!(other_hash)
6
6
  replace(reverse_merge(other_hash))
7
7
  end
8
+ def deep_transform_keys(&block)
9
+ result = {}
10
+ each do |key, value|
11
+ result[yield(key)] = value.is_a?(Hash) ? value.deep_transform_keys(&block) : value
12
+ end
13
+ result
14
+ end
15
+
16
+ def deep_transform_keys!(&block)
17
+ keys.each do |key|
18
+ value = delete(key)
19
+ self[yield(key)] = value.is_a?(Hash) ? value.deep_transform_keys!(&block) : value
20
+ end
21
+ self
22
+ end
8
23
  end
@@ -3,4 +3,11 @@ class String
3
3
  return nil if self.empty?
4
4
  self
5
5
  end
6
+ def underscore
7
+ self.gsub(/::/, '/').
8
+ gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
9
+ gsub(/([a-z\d])([A-Z])/,'\1_\2').
10
+ tr("-", "_").
11
+ downcase
12
+ end
6
13
  end
@@ -1,18 +1,16 @@
1
1
  module Broding
2
- module Environment
3
- def env
4
- @_env ||= (ENV["RACK_ENV"].presence || "development")
5
- end
2
+ def env
3
+ @_env ||= (ENV["RACK_ENV"].presence || "development")
4
+ end
6
5
 
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
6
+ def groups(*groups)
7
+ hash = groups.extract_options!
8
+ env = Jeanine.env
9
+ groups.unshift(:default, env)
10
+ groups.concat ENV["BRODY_GROUPS"].to_s.split(",")
11
+ groups.concat hash.map { |k, v| k if v.map(&:to_s).include?(env) }
12
+ groups.compact!
13
+ groups.uniq!
14
+ groups
17
15
  end
18
16
  end
@@ -1,9 +1,15 @@
1
1
  module Jeanine
2
2
  class Mimes
3
3
  MimeTypeNotFound = Class.new(StandardError)
4
- MIME_TYPES_INVERTED = Rack::Mime::MIME_TYPES.invert
4
+ MIME_TYPES_INVERTED = ::Rack::Mime::MIME_TYPES.invert
5
+
6
+ def self.loaded?
7
+ @loaded
8
+ end
5
9
 
6
10
  def self.load!
11
+ return if loaded?
12
+ @loaded = true
7
13
  register(:json, Rack::Mime::MIME_TYPES[".json"])
8
14
  register(:html, Rack::Mime::MIME_TYPES[".html"])
9
15
  register(:text, Rack::Mime::MIME_TYPES[".text"])
@@ -1,6 +1,15 @@
1
1
  require 'jeanine/view'
2
+ require 'jeanine/view_paths'
2
3
 
3
4
  module Jeanine
5
+ def self.view_paths
6
+ @_view_paths ||= Set.new(["views"])
7
+ end
8
+
9
+ def self.tilt_cache
10
+ @title_cache ||= Tilt::Cache.new
11
+ end
12
+
4
13
  class Renderer
5
14
  def self._renderers
6
15
  @_renderers ||= Set.new
@@ -81,6 +90,16 @@ module Jeanine
81
90
  Thread.current[:tilt_cache] ||= Tilt::Cache.new
82
91
  end
83
92
 
93
+ def find_template!(template)
94
+ Jeanine.view_paths.to_a.each do |path|
95
+ template_with_path = "#{path}/#{template}"
96
+ if File.exist?(template_with_path)
97
+ return template_with_path
98
+ end
99
+ end
100
+ raise "Template not found in view paths. Looking for #{template} in #{Jeanine.view_paths.to_a.join(', ')}"
101
+ end
102
+
84
103
  def html(engine, template_name, options = {}, locals = {}, &block)
85
104
  locals = options.delete(:locals) || locals || {}
86
105
  layout = options[:layout]
@@ -94,6 +113,7 @@ module Jeanine
94
113
  unless layout.include?("layouts/")
95
114
  layout = "layouts/#{layout}"
96
115
  end
116
+ layout = find_template!(layout)
97
117
  options = options.merge(layout: false, scope: scope)
98
118
  catch(:layout_missing) { return html(engine, layout, options, locals) { output } }
99
119
  end
@@ -104,7 +124,8 @@ module Jeanine
104
124
  Tilt::Cache.new.fetch engine, template_name, options do
105
125
  template = Tilt[engine]
106
126
  raise "Template engine not found: #{engine}" if template.nil?
107
- template.new("views/#{template_name}", options)
127
+ template_name = find_template!(template_name)
128
+ template.new(template_name, options)
108
129
  end
109
130
  end
110
131
 
@@ -127,4 +148,21 @@ module Jeanine
127
148
  text
128
149
  end
129
150
  end
151
+
152
+ module Rendering
153
+ def self.included(klass)
154
+ klass.extend ClassMethods
155
+ end
156
+
157
+ def render(*args)
158
+ @response.action_variables = instance_variables_cache
159
+ Renderer.new(@response).render(*args)
160
+ end
161
+
162
+ module ClassMethods
163
+ def append_view_path(path)
164
+ Jeanine.view_paths << path
165
+ end
166
+ end
167
+ end
130
168
  end
@@ -1,5 +1,4 @@
1
1
  require 'rack/request'
2
- require 'jeanine/headers'
3
2
 
4
3
  module Jeanine
5
4
  class Request < Rack::Request
@@ -17,8 +16,8 @@ module Jeanine
17
16
  super
18
17
  end
19
18
 
20
- def headers
21
- @headers ||= Jeanine::Headers.new(self)
19
+ def params
20
+ super.deep_transform_keys!(&:to_sym)
22
21
  end
23
22
 
24
23
  def post?
@@ -0,0 +1,41 @@
1
+ module Jeanine
2
+ module Rescuable
3
+ def self.included(base)
4
+ base.extend ClassMethods
5
+ base.prepend InstanceMethods
6
+ end
7
+
8
+ module InstanceMethods
9
+ def call(env)
10
+ begin
11
+ super
12
+ rescue => error
13
+ handler = self.class.rescue_handlers[error.class.to_s]
14
+ raise error unless handler
15
+ if handler.is_a?(Symbol)
16
+ @response.write(send(handler, error))
17
+ else
18
+ @response.write(instance_exec(error, &handler))
19
+ end
20
+ @response.complete!
21
+ end
22
+ end
23
+ end
24
+
25
+ module ClassMethods
26
+ def rescue_from(*exceptions, with: nil, &block)
27
+ exceptions.each do |exception|
28
+ if with
29
+ rescue_handlers[exception.to_s] = with
30
+ else
31
+ rescue_handlers[exception.to_s] = block
32
+ end
33
+ end
34
+ end
35
+
36
+ def rescue_handlers
37
+ @rescue_handlers ||= {}
38
+ end
39
+ end
40
+ end
41
+ end
@@ -1,20 +1,14 @@
1
1
  module Jeanine
2
2
  module Routing
3
3
  module Evaluation
4
- IGNORED_INSTANCE_VARIABLES = [:@env]
5
4
  def route_eval
6
- before_find_route!
7
5
  route = find_route
8
-
9
6
  if route
10
- before_evaluate_route!
11
7
  result = instance_eval(&route[:block])
12
8
  @response.write(result)
13
- after_evaluate_route!
14
9
  else
15
10
  @response.status = 404
16
11
  end
17
- after_response!
18
12
  @response.complete!
19
13
  end
20
14
 
@@ -34,7 +28,7 @@ module Jeanine
34
28
  while index < matches.captures.size
35
29
  param = route[:params][index]
36
30
  @request.params[param] = matches.captures[index]
37
- if index == match.captures.size
31
+ if index == matches.captures.size
38
32
  @request.params[param].gsub!(@request.format)
39
33
  end
40
34
  index += 1
@@ -43,54 +37,6 @@ module Jeanine
43
37
  route
44
38
  end
45
39
 
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
40
  end
95
41
  end
96
42
  end
@@ -1,3 +1,3 @@
1
1
  module Jeanine
2
- VERSION = "0.2.0"
2
+ VERSION = "0.7.0"
3
3
  end
@@ -0,0 +1,8 @@
1
+ require 'tilt'
2
+
3
+ module Jeanine
4
+
5
+ module ViewPaths
6
+
7
+ end
8
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: jeanine
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.7.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Josh Brody
8
8
  autorequire:
9
- bindir: bin
9
+ bindir: exe
10
10
  cert_chain: []
11
- date: 2020-07-07 00:00:00.000000000 Z
11
+ date: 2020-07-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rack
@@ -53,7 +53,7 @@ dependencies:
53
53
  - !ruby/object:Gem::Version
54
54
  version: '0'
55
55
  - !ruby/object:Gem::Dependency
56
- name: rspec
56
+ name: minitest
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
59
  - - ">="
@@ -66,16 +66,60 @@ dependencies:
66
66
  - - ">="
67
67
  - !ruby/object:Gem::Version
68
68
  version: '0'
69
- description: A framework.
69
+ - !ruby/object:Gem::Dependency
70
+ name: minitest-reporters
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: rack-test
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: pry
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ description: A lightning-fast, batteries-included Ruby web micro-framework.
70
112
  email:
71
113
  - git@josh.mn
72
114
  executables: []
73
115
  extensions: []
74
116
  extra_rdoc_files: []
75
117
  files:
118
+ - exe/jeanine
76
119
  - lib/jeanine.rb
77
120
  - lib/jeanine/app.rb
78
121
  - lib/jeanine/callbacks.rb
122
+ - lib/jeanine/cli.rb
79
123
  - lib/jeanine/core_ext.rb
80
124
  - lib/jeanine/core_ext/array.rb
81
125
  - lib/jeanine/core_ext/hash.rb
@@ -85,9 +129,9 @@ files:
85
129
  - lib/jeanine/headers.rb
86
130
  - lib/jeanine/mimes.rb
87
131
  - lib/jeanine/path_proxy.rb
88
- - lib/jeanine/renderer.rb
132
+ - lib/jeanine/rendering.rb
89
133
  - lib/jeanine/request.rb
90
- - lib/jeanine/rescuing.rb
134
+ - lib/jeanine/rescuable.rb
91
135
  - lib/jeanine/response.rb
92
136
  - lib/jeanine/router.rb
93
137
  - lib/jeanine/routing.rb
@@ -96,6 +140,7 @@ files:
96
140
  - lib/jeanine/session.rb
97
141
  - lib/jeanine/version.rb
98
142
  - lib/jeanine/view.rb
143
+ - lib/jeanine/view_paths.rb
99
144
  homepage: https://github.com/joshmn/jeanine
100
145
  licenses:
101
146
  - MIT
@@ -122,5 +167,5 @@ rubyforge_project:
122
167
  rubygems_version: 2.6.14.3
123
168
  signing_key:
124
169
  specification_version: 4
125
- summary: A framework.
170
+ summary: A lightning-fast, batteries-included Ruby web micro-framework.
126
171
  test_files: []
@@ -1,17 +0,0 @@
1
- module Jeanine
2
- module Rescuing
3
- def rescue_from(*exceptions, with: nil, &block)
4
- exceptions.each do |exception|
5
- if with
6
- rescue_handlers[exception] = with
7
- else
8
- rescue_handlers[exception] = block
9
- end
10
- end
11
- end
12
-
13
- def rescue_handlers
14
- @rescue_handlers ||= {}
15
- end
16
- end
17
- end