jsonapionify 0.12.2 → 0.12.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +8 -8
- data/lib/jsonapionify/api/action/documentation.rb +5 -5
- data/lib/jsonapionify/api/base.rb +1 -0
- data/lib/jsonapionify/api/base/app_builder.rb +1 -1
- data/lib/jsonapionify/api/context.rb +3 -5
- data/lib/jsonapionify/api/relationship/many.rb +1 -0
- data/lib/jsonapionify/api/resource/callbacks.rb +3 -48
- data/lib/jsonapionify/api/resource/caller.rb +9 -3
- data/lib/jsonapionify/api/resource/definitions/contexts.rb +1 -0
- data/lib/jsonapionify/api/resource/definitions/scopes.rb +8 -7
- data/lib/jsonapionify/api/resource/error_handling.rb +1 -1
- data/lib/jsonapionify/api/response.rb +2 -6
- data/lib/jsonapionify/callbacks.rb +24 -13
- data/lib/jsonapionify/custom_rescue.rb +38 -0
- data/lib/jsonapionify/destructured_proc.rb +5 -3
- data/lib/jsonapionify/version.rb +1 -1
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
---
|
2
2
|
!binary "U0hBMQ==":
|
3
3
|
metadata.gz: !binary |-
|
4
|
-
|
4
|
+
MWNlMTA2NTM0YmE2ODY1NjgxYzZkZDdkZWI1YTI5NTA5ZjA4YmM0OA==
|
5
5
|
data.tar.gz: !binary |-
|
6
|
-
|
6
|
+
MjllZmNlOGU1NmU1Nzk1YjZlZDYxODMxNThiZWQyYzA5NTVhMDc2Yg==
|
7
7
|
SHA512:
|
8
8
|
metadata.gz: !binary |-
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
Y2RlOTA5MDI3MGQ5M2U2MjAwZGJjMTNiOGNjMjFiOTU2ZmM5YzFlOTRiMDc0
|
10
|
+
MGRjMGJiN2NhZDkyODI2Y2VmNmUxNzE2MThmNjcxOWIzZDE0YjllZTFkYTFj
|
11
|
+
N2Q0YTQ3NTQyY2FkMDQxN2Y2YTE3NTI2OTIwNThhNGVjNjk1YjE=
|
12
12
|
data.tar.gz: !binary |-
|
13
|
-
|
14
|
-
|
15
|
-
|
13
|
+
Y2FmODhmNzdhOTAwNjVmNWMzNDU4MDdlNDZiNzQ3YzlkNDY2NjQyYzRjNmE0
|
14
|
+
NDEyNTU1MzRiN2FkMzZkNGE2NzAyODVkZjNlMDJmNDlmMzg4ODA2ZDUzYWRm
|
15
|
+
OTZkMmYxZjVmOTVkYjliYWZlOWMwNmEyZGYwNzRmODgxZjA4N2I=
|
@@ -61,11 +61,11 @@ module JSONAPIonify::Api
|
|
61
61
|
collection_context = proc do |context|
|
62
62
|
3.times.map { resource.example_instance_for_action(action.name, context) }
|
63
63
|
end
|
64
|
-
defs[:_is_example_] = Context.new(readonly: true) { true }
|
65
|
-
defs[:collection] = Context.new(&collection_context)
|
66
|
-
defs[:paginated_collection] = Context.new { |collection:| collection }
|
67
|
-
defs[:instance] = Context.new(readonly: true) { |collection:| collection.first }
|
68
|
-
defs[:owner_context] = Context.new(readonly: true) { ContextDelegate::Mock.new } if defs.has_key? :owner_context
|
64
|
+
defs[:_is_example_] = Context.new(:_is_example_, readonly: true) { true }
|
65
|
+
defs[:collection] = Context.new(:collection, &collection_context)
|
66
|
+
defs[:paginated_collection] = Context.new(:paginated_collection) { |collection:| collection }
|
67
|
+
defs[:instance] = Context.new(:instance, readonly: true) { |collection:| collection.first }
|
68
|
+
defs[:owner_context] = Context.new(:owner_context, readonly: true) { ContextDelegate::Mock.new } if defs.has_key? :owner_context
|
69
69
|
end
|
70
70
|
end
|
71
71
|
|
@@ -2,7 +2,8 @@ module JSONAPIonify::Api
|
|
2
2
|
class Context
|
3
3
|
using JSONAPIonify::DestructuredProc
|
4
4
|
|
5
|
-
def initialize(readonly: false, persisted: false, existing_context: nil, &block)
|
5
|
+
def initialize(name, readonly: false, persisted: false, existing_context: nil, &block)
|
6
|
+
@name = name.to_sym
|
6
7
|
@readonly = readonly
|
7
8
|
@persisted = persisted
|
8
9
|
@existing_context = existing_context
|
@@ -12,11 +13,8 @@ module JSONAPIonify::Api
|
|
12
13
|
def call(instance, delegate)
|
13
14
|
existing_context = @existing_context || proc {}
|
14
15
|
existing_block = proc { existing_context.call(instance, delegate) }
|
15
|
-
|
16
|
+
JSONAPIonify::CustomRescue.perform(remove: __FILE__, source: @block, formatter: ->(meta) { meta.source_location.join(':') + ":in context: `#{@name}''" }) do
|
16
17
|
instance.instance_exec(delegate, existing_block, &@block.destructure(0))
|
17
|
-
rescue => e
|
18
|
-
e.backtrace.unshift @block.source_location.join(':') + ":in (context)"
|
19
|
-
raise e
|
20
18
|
end
|
21
19
|
end
|
22
20
|
|
@@ -5,56 +5,11 @@ module JSONAPIonify::Api
|
|
5
5
|
extend ActiveSupport::Concern
|
6
6
|
using JSONAPIonify::DestructuredProc
|
7
7
|
included do
|
8
|
+
include JSONAPIonify::Callbacks
|
8
9
|
|
9
|
-
|
10
|
-
|
11
|
-
chains = {
|
12
|
-
main: "__#{name}_callback_chain",
|
13
|
-
before: "__#{name}_before_callback_chain",
|
14
|
-
after: "__#{name}_after_callback_chain"
|
15
|
-
}
|
16
|
-
define_method chains[:main] do |*args, &block|
|
17
|
-
block ||= proc {}
|
18
|
-
if send(chains[:before], *args) != false
|
19
|
-
value = begin
|
20
|
-
instance_exec(*args, @__context, &block&.destructure)
|
21
|
-
rescue => e
|
22
|
-
e.backtrace.unshift block.source_location.join(':') + ":in `(callback)`"
|
23
|
-
raise e
|
24
|
-
end
|
25
|
-
value if send(chains[:after], *args) != false
|
26
|
-
end
|
27
|
-
end unless method_defined? chains[:main]
|
28
|
-
|
29
|
-
# Define before and after chains
|
30
|
-
%i{after before}.each do |timing|
|
31
|
-
define_method chains[timing] { |*| } unless method_defined? chains[timing]
|
32
|
-
callback_name = "#{timing}_#{name}"
|
33
|
-
define_singleton_method callback_name do |sym = nil, &outer_block|
|
34
|
-
outer_block = (outer_block || sym).to_proc
|
35
|
-
prev_chain = instance_method(chains[timing])
|
36
|
-
define_method chains[timing] do |*args, &block|
|
37
|
-
begin
|
38
|
-
if prev_chain.bind(self).call(*args, @__context, &block&.destructure) != false
|
39
|
-
instance_exec(*args, @__context, &outer_block&.destructure)
|
40
|
-
end
|
41
|
-
rescue => e
|
42
|
-
e.backtrace.unshift outer_block.source_location.join(':') + ":in `(callback) #{callback_name}`"
|
43
|
-
raise e
|
44
|
-
end
|
45
|
-
end
|
46
|
-
end
|
47
|
-
end
|
48
|
-
|
49
|
-
private(*chains.values)
|
50
|
-
|
51
|
-
end
|
10
|
+
define_callback_strategy do |*args, &block|
|
11
|
+
instance_exec(*args, @__context, &block.destructure)
|
52
12
|
end
|
53
13
|
end
|
54
|
-
|
55
|
-
def run_callbacks(name, *args, &block)
|
56
|
-
send("__#{name}_callback_chain", *args, &block)
|
57
|
-
end
|
58
|
-
|
59
14
|
end
|
60
15
|
end
|
@@ -19,9 +19,15 @@ module JSONAPIonify::Api
|
|
19
19
|
end
|
20
20
|
|
21
21
|
def response_definition
|
22
|
-
|
23
|
-
|
24
|
-
|
22
|
+
extension = @__context.request.extension
|
23
|
+
responses = action.responses
|
24
|
+
response = nil
|
25
|
+
@__context.request.accept.each do |accept|
|
26
|
+
response = responses.find { |r| r.accept_with_matcher? @__context } ||
|
27
|
+
responses.find { |r| r.accept_with_header? accept: accept, extension: extension }
|
28
|
+
break if response
|
29
|
+
end
|
30
|
+
response || error_now(:not_acceptable)
|
25
31
|
end
|
26
32
|
|
27
33
|
private
|
@@ -1,12 +1,13 @@
|
|
1
1
|
module JSONAPIonify::Api
|
2
2
|
module Resource::Definitions::Scopes
|
3
|
+
using JSONAPIonify::DestructuredProc
|
3
4
|
|
4
5
|
def scope(&block)
|
5
6
|
define_singleton_method(:current_scope) do
|
6
|
-
instance_exec(OpenStruct.new, &block)
|
7
|
+
instance_exec(OpenStruct.new, &block.destructure)
|
7
8
|
end
|
8
9
|
context :scope do |context|
|
9
|
-
instance_exec(context, &block)
|
10
|
+
instance_exec(context, &block.destructure)
|
10
11
|
end
|
11
12
|
end
|
12
13
|
|
@@ -14,16 +15,16 @@ module JSONAPIonify::Api
|
|
14
15
|
|
15
16
|
def instance(&block)
|
16
17
|
define_singleton_method(:find_instance) do |id|
|
17
|
-
instance_exec(current_scope, id, OpenStruct.new, &block)
|
18
|
+
instance_exec(current_scope, id, OpenStruct.new, &block.destructure)
|
18
19
|
end
|
19
20
|
context :instance, persisted: true do |context, scope:, id:|
|
20
|
-
instance_exec(scope, id, context, &block)
|
21
|
+
instance_exec(scope, id, context, &block.destructure)
|
21
22
|
end
|
22
23
|
end
|
23
24
|
|
24
25
|
def collection(&block)
|
25
26
|
context :collection do |context, scope:, includes:|
|
26
|
-
collection =
|
27
|
+
collection = instance_exec(scope, context, &block.destructure)
|
27
28
|
|
28
29
|
# Compute includes manipulations
|
29
30
|
self.class.include_definitions.select do |relationship, _|
|
@@ -40,10 +41,10 @@ module JSONAPIonify::Api
|
|
40
41
|
|
41
42
|
def new_instance(&block)
|
42
43
|
define_singleton_method(:build_instance) do
|
43
|
-
Object.new.instance_exec(current_scope, &block)
|
44
|
+
Object.new.instance_exec(current_scope, &block.destructure)
|
44
45
|
end
|
45
46
|
context :new_instance, persisted: true, readonly: true do |context, scope:|
|
46
|
-
Object.new.instance_exec(scope, context, &block)
|
47
|
+
Object.new.instance_exec(scope, context, &block.destructure)
|
47
48
|
end
|
48
49
|
end
|
49
50
|
end
|
@@ -65,12 +65,8 @@ module JSONAPIonify::Api
|
|
65
65
|
end
|
66
66
|
end
|
67
67
|
|
68
|
-
def accept_with_header?(
|
69
|
-
|
70
|
-
self.accept == accept ||
|
71
|
-
(self.accept == '*/*' && !context.request.extension) ||
|
72
|
-
(accept == '*/*' && !context.request.extension)
|
73
|
-
end
|
68
|
+
def accept_with_header?(accept:, extension:)
|
69
|
+
self.accept == accept || (self.accept == '*/*' && !extension) || (accept == '*/*' && !extension)
|
74
70
|
end
|
75
71
|
|
76
72
|
def accept_with_matcher?(context)
|
@@ -1,11 +1,16 @@
|
|
1
1
|
require 'active_support/concern'
|
2
|
+
require 'unstrict_proc'
|
2
3
|
|
3
4
|
module JSONAPIonify
|
4
5
|
module Callbacks
|
5
6
|
extend ActiveSupport::Concern
|
6
|
-
included do
|
7
7
|
|
8
|
-
|
8
|
+
module ClassMethods
|
9
|
+
def define_callback_strategy(&strategy)
|
10
|
+
define_method(:__callback_strategy, &strategy)
|
11
|
+
end
|
12
|
+
|
13
|
+
def define_callbacks(*names)
|
9
14
|
names.each do |name|
|
10
15
|
chains = {
|
11
16
|
main: "__#{name}_callback_chain",
|
@@ -14,10 +19,12 @@ module JSONAPIonify
|
|
14
19
|
}
|
15
20
|
define_method chains[:main] do |*args, **, &block|
|
16
21
|
block ||= proc {}
|
17
|
-
|
18
|
-
value =
|
19
|
-
|
20
|
-
|
22
|
+
false != send(chains[:before], *args) &&
|
23
|
+
(value = JSONAPIonify::CustomRescue.perform(remove: __FILE__, source: block, formatter: ->(meta) { meta.source_location.join(':') + ":in callback: `run'" }) do
|
24
|
+
__callback_strategy(*args, &block) || true
|
25
|
+
end) &&
|
26
|
+
false != send(chains[:after], *args) &&
|
27
|
+
value
|
21
28
|
end unless method_defined? chains[:main]
|
22
29
|
|
23
30
|
# Define before and after chains
|
@@ -27,13 +34,11 @@ module JSONAPIonify
|
|
27
34
|
define_singleton_method callback_name do |sym = nil, &outer_block|
|
28
35
|
outer_block = (outer_block || sym).to_proc
|
29
36
|
prev_chain = instance_method(chains[timing])
|
30
|
-
define_method chains[timing] do |*args,
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
raise e
|
36
|
-
end
|
37
|
+
define_method chains[timing] do |*args, &block|
|
38
|
+
false != prev_chain.bind(self).call(*args, &block) &&
|
39
|
+
JSONAPIonify::CustomRescue.perform(remove: __FILE__, source: outer_block, formatter: ->(meta) { meta.source_location.join(':') + ":in callback: `#{timing}_#{name}'" }) do
|
40
|
+
__callback_strategy(*args, &outer_block)
|
41
|
+
end
|
37
42
|
end
|
38
43
|
end
|
39
44
|
end
|
@@ -44,6 +49,12 @@ module JSONAPIonify
|
|
44
49
|
end
|
45
50
|
end
|
46
51
|
|
52
|
+
included do
|
53
|
+
define_callback_strategy do |*args, &block|
|
54
|
+
instance_exec(*args, &block)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
47
58
|
def run_callbacks(name, *args, &block)
|
48
59
|
send("__#{name}_callback_chain", *args, &block)
|
49
60
|
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'unstrict_proc'
|
2
|
+
|
3
|
+
class JSONAPIonify::CustomRescue
|
4
|
+
using UnstrictProc
|
5
|
+
|
6
|
+
def self.perform(**opts, &block)
|
7
|
+
new(**opts, &block).perform
|
8
|
+
end
|
9
|
+
|
10
|
+
def initialize(remove: [], source: nil, formatter:, &block)
|
11
|
+
@block = block
|
12
|
+
@formatter = formatter
|
13
|
+
@source = source || block
|
14
|
+
@locs = Array.wrap remove
|
15
|
+
f, l = self.class.method(:perform).source_location
|
16
|
+
@locs << [f, l+1].join(':')
|
17
|
+
end
|
18
|
+
|
19
|
+
def source_location
|
20
|
+
source.source_location
|
21
|
+
end
|
22
|
+
|
23
|
+
def perform
|
24
|
+
@block.call
|
25
|
+
rescue => e
|
26
|
+
loc = [__FILE__, __LINE__-2].join(':')
|
27
|
+
formatted_value = @formatter.unstrict.call(Error.new(e, @source))
|
28
|
+
index = e.backtrace.index { |l| l.include? loc }
|
29
|
+
e.backtrace[index] = formatted_value if index && formatted_value
|
30
|
+
e.backtrace.delete_if { |l| @locs.any? { |rl| l.include? rl } }
|
31
|
+
raise e
|
32
|
+
end
|
33
|
+
|
34
|
+
class Error < Struct.new :error, :source
|
35
|
+
delegate :source_location, to: :source
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
@@ -5,16 +5,18 @@ module JSONAPIonify::DestructuredProc
|
|
5
5
|
original = self
|
6
6
|
Proc.new do |*args|
|
7
7
|
kwargs = original.kwargs_destructured(args[at_index])
|
8
|
-
|
8
|
+
JSONAPIonify::CustomRescue.perform(remove: __FILE__, source: original, formatter: ->(meta) { meta.source_location.join(':') + ":in `block (destructured)'" }) do
|
9
|
+
instance_exec(*args, **kwargs, &original)
|
10
|
+
end
|
9
11
|
end
|
10
12
|
end
|
11
13
|
|
12
14
|
def kwargs
|
13
|
-
parameters.select { |t, k| t.to_s.start_with?
|
15
|
+
parameters.select { |t, k| t.to_s.start_with?('key') && !t.to_s.end_with?('rest') }
|
14
16
|
end
|
15
17
|
|
16
18
|
def arguments
|
17
|
-
parameters.reject { |t, k| t.to_s.start_with?
|
19
|
+
parameters.reject { |t, k| t.to_s.start_with?('key') || t.to_s.end_with?('rest') }
|
18
20
|
end
|
19
21
|
|
20
22
|
def kwargs_destructured(target)
|
data/lib/jsonapionify/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: jsonapionify
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.12.
|
4
|
+
version: 0.12.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jason Waldrip
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-07-
|
11
|
+
date: 2016-07-20 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -608,6 +608,7 @@ files:
|
|
608
608
|
- lib/jsonapionify/callbacks.rb
|
609
609
|
- lib/jsonapionify/character_range.rb
|
610
610
|
- lib/jsonapionify/continuation.rb
|
611
|
+
- lib/jsonapionify/custom_rescue.rb
|
611
612
|
- lib/jsonapionify/deep_sort_collection.rb
|
612
613
|
- lib/jsonapionify/destructured_proc.rb
|
613
614
|
- lib/jsonapionify/documentation.rb
|