praxis 0.22.pre.1 → 2.0.pre.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (96) hide show
  1. checksums.yaml +5 -5
  2. data/.travis.yml +5 -20
  3. data/CHANGELOG.md +328 -323
  4. data/lib/praxis.rb +13 -9
  5. data/lib/praxis/action_definition.rb +8 -10
  6. data/lib/praxis/action_definition/headers_dsl_compiler.rb +1 -1
  7. data/lib/praxis/api_definition.rb +27 -44
  8. data/lib/praxis/api_general_info.rb +2 -3
  9. data/lib/praxis/application.rb +15 -142
  10. data/lib/praxis/bootloader.rb +1 -2
  11. data/lib/praxis/bootloader_stages/environment.rb +13 -0
  12. data/lib/praxis/config.rb +1 -1
  13. data/lib/praxis/controller.rb +0 -2
  14. data/lib/praxis/dispatcher.rb +4 -6
  15. data/lib/praxis/docs/generator.rb +8 -18
  16. data/lib/praxis/docs/link_builder.rb +1 -1
  17. data/lib/praxis/error_handler.rb +5 -5
  18. data/lib/praxis/extensions/attribute_filtering/active_record_filter_query_builder.rb +1 -1
  19. data/lib/praxis/extensions/attribute_filtering/filtering_params.rb +1 -1
  20. data/lib/praxis/extensions/attribute_filtering/sequel_filter_query_builder.rb +125 -0
  21. data/lib/praxis/extensions/field_selection.rb +1 -12
  22. data/lib/praxis/extensions/field_selection/active_record_query_selector.rb +28 -34
  23. data/lib/praxis/extensions/field_selection/sequel_query_selector.rb +35 -39
  24. data/lib/praxis/extensions/rendering.rb +1 -1
  25. data/lib/praxis/file_group.rb +1 -1
  26. data/lib/praxis/handlers/xml.rb +1 -1
  27. data/lib/praxis/mapper/active_model_compat.rb +98 -0
  28. data/lib/praxis/mapper/resource.rb +242 -0
  29. data/lib/praxis/mapper/selector_generator.rb +154 -0
  30. data/lib/praxis/mapper/sequel_compat.rb +76 -0
  31. data/lib/praxis/media_type_identifier.rb +2 -1
  32. data/lib/praxis/middleware_app.rb +13 -15
  33. data/lib/praxis/multipart/part.rb +3 -5
  34. data/lib/praxis/notifications.rb +1 -1
  35. data/lib/praxis/plugins/mapper_plugin.rb +64 -0
  36. data/lib/praxis/request.rb +14 -7
  37. data/lib/praxis/request_stages/response.rb +2 -3
  38. data/lib/praxis/resource_definition.rb +15 -19
  39. data/lib/praxis/response.rb +6 -5
  40. data/lib/praxis/response_definition.rb +5 -7
  41. data/lib/praxis/response_template.rb +3 -4
  42. data/lib/praxis/responses/http.rb +36 -0
  43. data/lib/praxis/responses/internal_server_error.rb +12 -3
  44. data/lib/praxis/responses/multipart_ok.rb +11 -4
  45. data/lib/praxis/responses/validation_error.rb +10 -1
  46. data/lib/praxis/route.rb +1 -1
  47. data/lib/praxis/router.rb +3 -3
  48. data/lib/praxis/routing_config.rb +1 -1
  49. data/lib/praxis/tasks/api_docs.rb +2 -10
  50. data/lib/praxis/tasks/routes.rb +0 -1
  51. data/lib/praxis/trait.rb +1 -1
  52. data/lib/praxis/types/media_type_common.rb +2 -2
  53. data/lib/praxis/types/multipart.rb +1 -1
  54. data/lib/praxis/types/multipart_array.rb +2 -2
  55. data/lib/praxis/types/multipart_array/part_definition.rb +1 -1
  56. data/lib/praxis/version.rb +1 -1
  57. data/praxis.gemspec +11 -9
  58. data/spec/functional_spec.rb +0 -1
  59. data/spec/praxis/action_definition_spec.rb +16 -27
  60. data/spec/praxis/api_definition_spec.rb +8 -13
  61. data/spec/praxis/api_general_info_spec.rb +8 -3
  62. data/spec/praxis/application_spec.rb +8 -14
  63. data/spec/praxis/collection_spec.rb +3 -2
  64. data/spec/praxis/config_spec.rb +2 -2
  65. data/spec/praxis/extensions/field_selection/active_record_query_selector_spec.rb +106 -0
  66. data/spec/praxis/extensions/field_selection/sequel_query_selector_spec.rb +147 -0
  67. data/spec/praxis/extensions/field_selection/support/spec_resources_active_model.rb +130 -0
  68. data/spec/praxis/extensions/field_selection/support/spec_resources_sequel.rb +106 -0
  69. data/spec/praxis/handlers/xml_spec.rb +2 -2
  70. data/spec/praxis/mapper/resource_spec.rb +169 -0
  71. data/spec/praxis/mapper/selector_generator_spec.rb +325 -0
  72. data/spec/praxis/media_type_spec.rb +0 -10
  73. data/spec/praxis/middleware_app_spec.rb +16 -10
  74. data/spec/praxis/request_spec.rb +7 -17
  75. data/spec/praxis/request_stages/action_spec.rb +8 -1
  76. data/spec/praxis/request_stages/validate_spec.rb +1 -1
  77. data/spec/praxis/resource_definition_spec.rb +10 -12
  78. data/spec/praxis/response_definition_spec.rb +12 -26
  79. data/spec/praxis/response_spec.rb +6 -13
  80. data/spec/praxis/responses/internal_server_error_spec.rb +5 -2
  81. data/spec/praxis/router_spec.rb +5 -9
  82. data/spec/spec_app/app/controllers/instances.rb +1 -1
  83. data/spec/spec_app/config.ru +6 -1
  84. data/spec/spec_app/config/environment.rb +3 -21
  85. data/spec/spec_helper.rb +13 -17
  86. data/spec/support/be_deep_equal_matcher.rb +39 -0
  87. data/spec/support/spec_resources.rb +124 -0
  88. metadata +74 -53
  89. data/lib/praxis/extensions/attribute_filtering.rb +0 -28
  90. data/lib/praxis/extensions/attribute_filtering/query_builder.rb +0 -39
  91. data/lib/praxis/extensions/mapper_selectors.rb +0 -16
  92. data/lib/praxis/media_type_collection.rb +0 -127
  93. data/lib/praxis/plugins/praxis_mapper_plugin.rb +0 -246
  94. data/spec/praxis/media_type_collection_spec.rb +0 -157
  95. data/spec/praxis/plugins/praxis_mapper_plugin_spec.rb +0 -142
  96. data/spec/spec_app/app/models/person.rb +0 -3
@@ -1,10 +1,10 @@
1
1
  require 'rack'
2
2
  require 'attributor'
3
- require 'praxis-mapper'
4
3
  require 'praxis-blueprints'
5
4
 
6
5
  require 'active_support/concern'
7
6
  require 'praxis/request_superclassing'
7
+ require 'active_support/inflector'
8
8
 
9
9
  $:.unshift File.dirname(__FILE__)
10
10
 
@@ -62,7 +62,6 @@ module Praxis
62
62
 
63
63
  autoload :Links, 'praxis/links'
64
64
  autoload :MediaType, 'praxis/media_type'
65
- autoload :MediaTypeCollection, 'praxis/media_type_collection'
66
65
  autoload :MediaTypeIdentifier, 'praxis/media_type_identifier'
67
66
  autoload :Multipart, 'praxis/types/multipart'
68
67
  autoload :Collection, 'praxis/collection'
@@ -89,7 +88,8 @@ module Praxis
89
88
  autoload :MapperSelectors, 'praxis/extensions/mapper_selectors'
90
89
  autoload :Rendering, 'praxis/extensions/rendering'
91
90
  autoload :FieldExpansion, 'praxis/extensions/field_expansion'
92
- autoload :AttributeFiltering, 'praxis/extensions/attribute_filtering'
91
+ autoload :ActiveRecordFilterQueryBuilder, 'praxis/extensions/attribute_filtering/active_record_filter_query_builder'
92
+ autoload :SequelFilterQueryBuilder, 'praxis/extensions/attribute_filtering/sequel_filter_query_builder'
93
93
  end
94
94
 
95
95
  module Handlers
@@ -123,11 +123,15 @@ module Praxis
123
123
  autoload :Response, 'praxis/request_stages/response'
124
124
  end
125
125
 
126
- # # Avoid loading responses (and templates) lazily as they need to be registered in time
127
- # ... now done in Praxis initialize
128
- # require 'praxis/responses/http'
129
- # require 'praxis/responses/internal_server_error'
130
- # require 'praxis/responses/validation_error'
131
- # require 'praxis/responses/multipart_ok'
126
+ module Mapper
127
+ autoload :Resource, 'praxis/mapper/resource'
128
+ autoload :SelectorGenerator, 'praxis/mapper/selector_generator'
129
+ end
130
+
131
+ # Avoid loading responses (and templates) lazily as they need to be registered in time
132
+ require 'praxis/responses/http'
133
+ require 'praxis/responses/internal_server_error'
134
+ require 'praxis/responses/validation_error'
135
+ require 'praxis/responses/multipart_ok'
132
136
 
133
137
  end
@@ -12,7 +12,6 @@ module Praxis
12
12
 
13
13
  attr_reader :name
14
14
  attr_reader :resource_definition
15
- attr_reader :api_definition
16
15
  attr_reader :routes
17
16
  attr_reader :primary_route
18
17
  attr_reader :named_routes
@@ -40,7 +39,6 @@ module Praxis
40
39
  @metadata = Hash.new
41
40
  @routes = []
42
41
  @traits = []
43
- @api_definition = resource_definition.application.api_definition
44
42
 
45
43
  if (media_type = resource_definition.media_type)
46
44
  if media_type.kind_of?(Class) && media_type < Praxis::Types::MediaTypeCommon
@@ -49,7 +47,7 @@ module Praxis
49
47
  end
50
48
 
51
49
  version = resource_definition.version
52
- api_info = api_definition.info(resource_definition.version)
50
+ api_info = ApiDefinition.instance.info(resource_definition.version)
53
51
 
54
52
  route_base = "#{api_info.base_path}#{resource_definition.version_prefix}"
55
53
  prefix = Array(resource_definition.routing_prefix)
@@ -66,11 +64,11 @@ module Praxis
66
64
  end
67
65
 
68
66
  def trait(trait_name)
69
- unless api_definition.traits.has_key? trait_name
67
+ unless ApiDefinition.instance.traits.has_key? trait_name
70
68
  raise Exceptions::InvalidTrait.new("Trait #{trait_name} not found in the system")
71
69
  end
72
70
 
73
- trait = api_definition.traits.fetch(trait_name)
71
+ trait = ApiDefinition.instance.traits.fetch(trait_name)
74
72
  trait.apply!(self)
75
73
  traits << trait_name
76
74
  end
@@ -78,7 +76,7 @@ module Praxis
78
76
 
79
77
  def update_attribute(attribute, options, block)
80
78
  attribute.options.merge!(options)
81
- attribute.type.attributes(options, &block)
79
+ attribute.type.attributes(**options, &block)
82
80
  end
83
81
 
84
82
  def response(name, type=nil, **args, &block)
@@ -92,7 +90,7 @@ module Praxis
92
90
  args[:media_type] = type
93
91
  end
94
92
 
95
- template = api_definition.response(name)
93
+ template = ApiDefinition.instance.response(name)
96
94
  @responses[name] = template.compile(self, **args)
97
95
  end
98
96
 
@@ -305,7 +303,7 @@ module Praxis
305
303
 
306
304
  # and return that one if it already corresponds to a registered handler
307
305
  # otherwise, add the encoding
308
- if resource_definition.application.handlers.include?(pick.handler_name)
306
+ if Praxis::Application.instance.handlers.include?(pick.handler_name)
309
307
  return pick
310
308
  else
311
309
  return pick + handler_name
@@ -322,13 +320,13 @@ module Praxis
322
320
 
323
321
  hash[:examples] = {}
324
322
 
325
- default_handlers = api_definition.info.consumes
323
+ default_handlers = ApiDefinition.instance.info.consumes
326
324
 
327
325
  default_handlers.each do |default_handler|
328
326
  dumped_payload = payload.dump(example, default_format: default_handler)
329
327
 
330
328
  content_type = derive_content_type(example, default_handler)
331
- handler = resource_definition.application.handlers[content_type.handler_name]
329
+ handler = Praxis::Application.instance.handlers[content_type.handler_name]
332
330
 
333
331
  # in case handler is nil, use dumped_payload as-is.
334
332
  generated_payload = if handler.nil?
@@ -25,7 +25,7 @@ module Praxis
25
25
  # Defining the existence without any other options can only mean that it is required (otherwise it is a useless definition)
26
26
  options[:required] = true if options.empty?
27
27
  end
28
- key name , String, options
28
+ key name , String, **options
29
29
  end
30
30
 
31
31
  # Override the attribute to really call "key" in the hash (for temporary backwards compat)
@@ -1,57 +1,41 @@
1
+ require 'singleton'
1
2
  require 'forwardable'
2
3
 
3
4
  module Praxis
4
5
 
5
6
  class ApiDefinition
7
+ include Singleton
6
8
  extend Forwardable
7
9
 
8
10
  attr_reader :traits
9
11
  attr_reader :responses
10
12
  attr_reader :infos
11
13
  attr_reader :global_info
12
- attr_reader :application
13
14
 
14
15
  attr_accessor :versioning_scheme
15
16
 
16
- def self.instance
17
- i = Thread.current[:praxis_instance] || $praxis_initializing_instance
18
- raise "Trying to use Praxis::ApiDefinition outside the context of a Praxis::Application" unless i
19
- i.api_definition
20
- end
21
-
22
17
  def self.define(&block)
23
-
24
- definition = Praxis::Application.current_instance.api_definition
25
- if block.arity == 0
26
- definition.instance_eval(&block)
27
- else
28
- yield(definition)
29
- end
30
- end
31
-
32
- def define(&block)
33
18
  if block.arity == 0
34
- self.instance_eval(&block)
19
+ self.instance.instance_eval(&block)
35
20
  else
36
- yield(self)
21
+ yield(self.instance)
37
22
  end
38
23
  end
39
24
 
40
- def initialize(application)
41
- @application = application
25
+ def initialize
42
26
  @responses = Hash.new
43
27
  @traits = Hash.new
44
28
  @base_path = ''
45
29
 
46
- @global_info = ApiGeneralInfo.new(application: application)
30
+ @global_info = ApiGeneralInfo.new
47
31
 
48
32
  @infos = Hash.new do |hash, version|
49
- hash[version] = ApiGeneralInfo.new(@global_info, application: application, version: version)
33
+ hash[version] = ApiGeneralInfo.new(@global_info, version: version)
50
34
  end
51
35
  end
52
36
 
53
37
  def response_template(name, &block)
54
- @responses[name] = Praxis::ResponseTemplate.new(name, application, &block)
38
+ @responses[name] = Praxis::ResponseTemplate.new(name, &block)
55
39
  end
56
40
 
57
41
  def response(name)
@@ -107,26 +91,25 @@ module Praxis
107
91
  data
108
92
  end
109
93
 
110
- # CANNOT DEFINE IT AT FILE LOADING TIME: THE INSTANCE FOR THE API_DEFINITION IS NOT READY YET.
111
- # define do |api|
112
- # api.response_template :ok do |media_type: , location: nil, headers: nil, description: nil |
113
- # status 200
114
- # description( description || 'Standard response for successful HTTP requests.' )
115
- #
116
- # media_type media_type
117
- # location location
118
- # headers headers if headers
119
- # end
120
- #
121
- # api.response_template :created do |media_type: nil, location: nil, headers: nil, description: nil|
122
- # status 201
123
- # description( description || 'The request has been fulfilled and resulted in a new resource being created.' )
124
- #
125
- # media_type media_type if media_type
126
- # location location
127
- # headers headers if headers
128
- # end
129
- # end
94
+ define do |api|
95
+ api.response_template :ok do |media_type: , location: nil, headers: nil, description: nil |
96
+ status 200
97
+ description( description || 'Standard response for successful HTTP requests.' )
98
+
99
+ media_type media_type
100
+ location location
101
+ headers headers if headers
102
+ end
103
+
104
+ api.response_template :created do |media_type: nil, location: nil, headers: nil, description: nil|
105
+ status 201
106
+ description( description || 'The request has been fulfilled and resulted in a new resource being created.' )
107
+
108
+ media_type media_type if media_type
109
+ location location
110
+ headers headers if headers
111
+ end
112
+ end
130
113
 
131
114
  end
132
115
 
@@ -3,11 +3,10 @@ module Praxis
3
3
 
4
4
  attr_reader :version
5
5
 
6
- def initialize(global_info=nil, application:, version: nil)
6
+ def initialize(global_info=nil, version: nil)
7
7
  @data = Hash.new
8
8
  @global_info = global_info
9
9
  @version = version
10
- @application = application
11
10
 
12
11
  if @global_info.nil? # this *is* the global info
13
12
  version_with [:header, :params]
@@ -55,7 +54,7 @@ module Praxis
55
54
  get(:version_with)
56
55
  else
57
56
  if @global_info.nil? # this *is* the global info
58
- @application.versioning_scheme = val
57
+ Application.instance.versioning_scheme = val
59
58
  set(:version_with, val)
60
59
  else
61
60
  raise "Use of version_with is only allowed in the global part of " \
@@ -1,15 +1,16 @@
1
+ require 'singleton'
1
2
  require 'mustermann'
2
3
  require 'logger'
3
4
 
4
5
  module Praxis
5
6
  class Application
7
+ include Singleton
6
8
 
7
9
  attr_reader :router
8
10
  attr_reader :controllers
9
11
  attr_reader :resource_definitions
10
12
  attr_reader :app
11
13
  attr_reader :builder
12
- attr_reader :api_definition
13
14
 
14
15
  attr_accessor :bootloader
15
16
  attr_accessor :file_layout
@@ -24,30 +25,12 @@ module Praxis
24
25
 
25
26
  attr_accessor :versioning_scheme
26
27
 
27
- @@registered_apps = {}
28
28
 
29
- def self.registered_apps
30
- @@registered_apps
31
- end
32
-
33
- def self.instance
34
- i = current_instance
35
- return i if i
36
- $praxis_initializing_instance = self.new
37
- end
38
-
39
- def self.current_instance
40
- Thread.current[:praxis_instance] || $praxis_initializing_instance
41
- end
42
-
43
29
  def self.configure
44
- # Should fail (i.e., be nil) if it's not in initialization/setup or a runtime call
45
- yield(current_instance)
30
+ yield(self.instance)
46
31
  end
47
32
 
48
- def initialize(name: 'default', skip_registration: false)
49
- old = $praxis_initializing_instance
50
- $praxis_initializing_instance = self # ApiDefinition.new needs to get the instance...
33
+ def initialize
51
34
  @controllers = Set.new
52
35
  @resource_definitions = Set.new
53
36
 
@@ -68,135 +51,29 @@ module Praxis
68
51
  @config = Config.new
69
52
  @root = nil
70
53
  @logger = Logger.new(STDOUT)
71
- @api_definition = ApiDefinition.new(self)
72
-
73
- @api_definition.define do |api|
74
- api.response_template :ok do |media_type: , location: nil, headers: nil, description: nil |
75
- status 200
76
- description( description || 'Standard response for successful HTTP requests.' )
77
-
78
- media_type media_type
79
- location location
80
- headers headers if headers
81
- end
82
-
83
- api.response_template :created do |media_type: nil, location: nil, headers: nil, description: nil|
84
- status 201
85
- description( description || 'The request has been fulfilled and resulted in a new resource being created.' )
86
-
87
- media_type media_type if media_type
88
- location location
89
- headers headers if headers
90
- end
91
- end
92
-
93
- require 'praxis/responses/http'
94
- self.api_definition.define do |api|
95
- [
96
- [ :accepted, 202, "The request has been accepted for processing, but the processing has not been completed." ],
97
- [ :no_content, 204,"The server successfully processed the request, but is not returning any content."],
98
- [ :multiple_choices, 300,"Indicates multiple options for the resource that the client may follow."],
99
- [ :moved_permanently, 301,"This and all future requests should be directed to the given URI."],
100
- [ :found, 302,"The requested resource resides temporarily under a different URI."],
101
- [ :see_other, 303,"The response to the request can be found under another URI using a GET method"],
102
- [ :not_modified, 304,"Indicates that the resource has not been modified since the version specified by the request headers If-Modified-Since or If-Match."],
103
- [ :temporary_redirect, 307,"In this case, the request should be repeated with another URI; however, future requests should still use the original URI."],
104
- [ :bad_request, 400,"The request cannot be fulfilled due to bad syntax."],
105
- [ :unauthorized, 401,"Similar to 403 Forbidden, but specifically for use when authentication is required and has failed or has not yet been provided."],
106
- [ :forbidden, 403,"The request was a valid request, but the server is refusing to respond to it."],
107
- [ :not_found, 404,"The requested resource could not be found but may be available again in the future."],
108
- [ :method_not_allowed, 405,"A request was made of a resource using a request method not supported by that resource."],
109
- [ :not_acceptable, 406,"The requested resource is only capable of generating content not acceptable according to the Accept headers sent in the request."],
110
- [ :request_timeout, 408,"The server timed out waiting for the request."],
111
- [ :conflict, 409, "Indicates that the request could not be processed because of conflict in the request, such as an edit conflict in the case of multiple updates."],
112
- [ :precondition_failed, 412,"The server does not meet one of the preconditions that the requester put on the request."],
113
- [ :unprocessable_entity, 422,"The request was well-formed but was unable to be followed due to semantic errors."],
114
- ].each do |name, code, base_description|
115
- api.response_template name do |media_type: nil, location: nil, headers: nil, description: nil|
116
- status code
117
- description( description || base_description ) # description can "potentially" be overriden in an individual action.
118
-
119
- media_type media_type if media_type
120
- location location if location
121
- headers headers if headers
122
- end
123
- end
54
+ end
55
+
56
+
57
+ def setup(root: '.')
58
+ return self unless @app.nil?
59
+
60
+ @root = Pathname.new(root).expand_path
124
61
 
125
- end
126
-
127
- require 'praxis/responses/internal_server_error'
128
- self.api_definition.define do |api|
129
- api.response_template :internal_server_error do
130
- description "A generic error message, given when an unexpected condition was encountered and no more specific message is suitable."
131
- status 500
132
- media_type "application/json"
133
- end
134
- end
135
-
136
- require 'praxis/responses/validation_error'
137
- self.api_definition.define do |api|
138
- api.response_template :validation_error do
139
- description "An error message indicating that one or more elements of the request did not match the API specification for the action"
140
- status 400
141
- media_type "application/json"
142
- end
143
- end
144
-
145
-
146
- require 'praxis/responses/multipart_ok'
147
- self.api_definition.define do |api|
148
- api.response_template :multipart_ok do |media_type: Praxis::Types::MultipartArray|
149
- status 200
150
- media_type media_type
151
- end
152
- end
153
-
154
62
  builtin_handlers = {
155
63
  'plain' => Praxis::Handlers::Plain,
156
64
  'json' => Praxis::Handlers::JSON,
157
65
  'x-www-form-urlencoded' => Praxis::Handlers::WWWForm
158
66
  }
159
-
160
67
  # Register built-in handlers unless the app already provided its own
161
68
  builtin_handlers.each_pair do |name, handler|
162
69
  self.handler(name, handler) unless handlers.key?(name)
163
70
  end
164
-
165
- setup_initial_config!
166
-
167
- unless skip_registration
168
- if self.class.registered_apps[name]
169
- raise "A Praxis instance named #{name} has already been registered, please use the :name parameter to initialize them"
170
- end
171
- self.class.registered_apps[name] = self
172
- end
173
- $praxis_initializing_instance = old
174
- end
175
-
176
- def setup_initial_config!
177
- self.config do
178
- attribute :praxis do
179
- attribute :validate_responses, Attributor::Boolean, default: false
180
- attribute :validate_response_bodies, Attributor::Boolean, default: false
181
-
182
- attribute :show_exceptions, Attributor::Boolean, default: false
183
- attribute :x_cascade, Attributor::Boolean, default: true
184
- end
185
- end
186
- end
187
-
188
71
 
189
- def setup(root: '.')
190
- return self unless @app.nil?
191
- saved_value = $praxis_initializing_instance
192
- $praxis_initializing_instance = self
193
- @root = Pathname.new(root).expand_path
72
+ @bootloader.setup!
194
73
 
195
- bootloader.setup!
196
- builder.run(@router)
197
- @app = builder.to_app
74
+ @builder.run(@router)
75
+ @app = @builder.to_app
198
76
 
199
- $praxis_initializing_instance = saved_value
200
77
  self
201
78
  end
202
79
 
@@ -226,13 +103,9 @@ module Praxis
226
103
 
227
104
  def call(env)
228
105
  response = []
229
- old = Thread.current[:praxis_instance]
230
- Thread.current[:praxis_instance] = self
231
106
  Notifications.instrument 'rack.request.all'.freeze, response: response do
232
107
  response.push(*@app.call(env))
233
108
  end
234
- ensure
235
- Thread.current[:praxis_instance] = old
236
109
  end
237
110
 
238
111
  def layout(&block)
@@ -241,7 +114,7 @@ module Praxis
241
114
 
242
115
  def config(key=nil, type=Attributor::Struct, **opts, &block)
243
116
  if block_given? || (type==Attributor::Struct && !opts.empty? )
244
- @config.define(key, type, opts, &block)
117
+ @config.define(key, type, **opts, &block)
245
118
  else
246
119
  @config.get
247
120
  end