jsonapionify 0.11.11 → 0.12.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. checksums.yaml +8 -8
  2. data/README.md +3 -0
  3. data/examples/example_api.rb +80 -0
  4. data/jsonapionify.gemspec +1 -0
  5. data/lib/jsonapionify/api/action/documentation.rb +2 -2
  6. data/lib/jsonapionify/api/attribute.rb +3 -2
  7. data/lib/jsonapionify/api/context.rb +8 -3
  8. data/lib/jsonapionify/api/context_delegate.rb +6 -0
  9. data/lib/jsonapionify/api/relationship.rb +5 -10
  10. data/lib/jsonapionify/api/relationship/many.rb +46 -14
  11. data/lib/jsonapionify/api/relationship/one.rb +31 -8
  12. data/lib/jsonapionify/api/resource.rb +3 -6
  13. data/lib/jsonapionify/api/resource/builders/fields_builder.rb +2 -2
  14. data/lib/jsonapionify/api/resource/builders/relationship_builder.rb +3 -2
  15. data/lib/jsonapionify/api/resource/builders/relationships_builder.rb +3 -2
  16. data/lib/jsonapionify/api/resource/caching.rb +1 -4
  17. data/lib/jsonapionify/api/resource/callbacks.rb +60 -0
  18. data/lib/jsonapionify/api/resource/caller.rb +8 -7
  19. data/lib/jsonapionify/api/resource/defaults/actions.rb +15 -12
  20. data/lib/jsonapionify/api/resource/defaults/hooks.rb +10 -57
  21. data/lib/jsonapionify/api/resource/defaults/options.rb +3 -8
  22. data/lib/jsonapionify/api/resource/defaults/params.rb +0 -2
  23. data/lib/jsonapionify/api/resource/defaults/request_contexts.rb +24 -29
  24. data/lib/jsonapionify/api/resource/defaults/response_contexts.rb +11 -18
  25. data/lib/jsonapionify/api/resource/definitions/actions.rb +38 -22
  26. data/lib/jsonapionify/api/resource/definitions/attributes.rb +2 -2
  27. data/lib/jsonapionify/api/resource/definitions/helpers.rb +1 -1
  28. data/lib/jsonapionify/api/resource/definitions/includes.rb +16 -0
  29. data/lib/jsonapionify/api/resource/definitions/pagination.rb +7 -11
  30. data/lib/jsonapionify/api/resource/definitions/params.rb +19 -26
  31. data/lib/jsonapionify/api/resource/definitions/relationships.rb +3 -3
  32. data/lib/jsonapionify/api/resource/definitions/request_headers.rb +14 -16
  33. data/lib/jsonapionify/api/resource/definitions/response_headers.rb +2 -1
  34. data/lib/jsonapionify/api/resource/definitions/scopes.rb +17 -6
  35. data/lib/jsonapionify/api/resource/definitions/sorting.rb +8 -7
  36. data/lib/jsonapionify/api/resource/error_handling.rb +3 -2
  37. data/lib/jsonapionify/api/resource/exec.rb +3 -1
  38. data/lib/jsonapionify/api/resource/includer.rb +20 -51
  39. data/lib/jsonapionify/api/response.rb +3 -1
  40. data/lib/jsonapionify/callbacks.rb +10 -7
  41. data/lib/jsonapionify/destructured_proc.rb +27 -0
  42. data/lib/jsonapionify/structure/collections/base.rb +20 -8
  43. data/lib/jsonapionify/structure/objects/base.rb +11 -2
  44. data/lib/jsonapionify/structure/objects/resource_identifier.rb +9 -14
  45. data/lib/jsonapionify/version.rb +1 -1
  46. metadata +20 -2
@@ -1,5 +1,7 @@
1
1
  module JSONAPIonify::Api
2
2
  class Response
3
+ using JSONAPIonify::DestructuredProc
4
+
3
5
  attr_reader :action, :accept, :response_block, :status,
4
6
  :matcher, :content_type, :extension, :example_accept
5
7
 
@@ -39,7 +41,7 @@ module JSONAPIonify::Api
39
41
  status ||= self.status
40
42
  response = self
41
43
  instance.instance_eval do
42
- body = instance_exec(context, &response.response_block)
44
+ body = instance_exec(context, &response.response_block.destructure)
43
45
  Rack::Response.new.tap do |rack_response|
44
46
  rack_response.status = status
45
47
  response_headers.each do |k, v|
@@ -12,7 +12,7 @@ module JSONAPIonify
12
12
  before: "__#{name}_before_callback_chain",
13
13
  after: "__#{name}_after_callback_chain"
14
14
  }
15
- define_method chains[:main] do |*args, &block|
15
+ define_method chains[:main] do |*args, **, &block|
16
16
  block ||= proc {}
17
17
  if send(chains[:before], *args) != false
18
18
  value = instance_exec(*args, &block)
@@ -23,19 +23,22 @@ module JSONAPIonify
23
23
  # Define before and after chains
24
24
  %i{after before}.each do |timing|
25
25
  define_method chains[timing] { |*| } unless method_defined? chains[timing]
26
-
27
- define_singleton_method "#{timing}_#{name}" do |sym = nil, &outer_block|
26
+ callback_name = "#{timing}_#{name}"
27
+ define_singleton_method callback_name do |sym = nil, &outer_block|
28
28
  outer_block = (outer_block || sym).to_proc
29
29
  prev_chain = instance_method(chains[timing])
30
- define_method chains[timing] do |*args, &block|
31
- if prev_chain.bind(self).call(*args, &block) != false
32
- instance_exec(*args, &outer_block)
30
+ define_method chains[timing] do |*args, **, &block|
31
+ begin
32
+ instance_exec(*args, &outer_block) if prev_chain.bind(self).call(*args, &block) != false
33
+ rescue => e
34
+ e.backtrace.unshift outer_block.source_location.join(':') + ":in `(callback) #{callback_name}`"
35
+ raise e
33
36
  end
34
37
  end
35
38
  end
36
39
  end
37
40
 
38
- private *chains.values
41
+ private(*chains.values)
39
42
 
40
43
  end
41
44
  end
@@ -0,0 +1,27 @@
1
+ module JSONAPIonify::DestructuredProc
2
+ refine Proc do
3
+ def destructure(at_index = arguments.length-1)
4
+ return self unless kwargs.present?
5
+ original = self
6
+ Proc.new do |*args|
7
+ kwargs = original.kwargs_destructured(args[at_index])
8
+ instance_exec(*args, **kwargs, &original)
9
+ end
10
+ end
11
+
12
+ def kwargs
13
+ parameters.select { |t, k| t.to_s.start_with? 'key' }
14
+ end
15
+
16
+ def arguments
17
+ parameters.reject { |t, k| t.to_s.start_with? 'key' }
18
+ end
19
+
20
+ def kwargs_destructured(target)
21
+ kwargs.each_with_object({}) do |(_, key), kw|
22
+ next unless target.respond_to? key
23
+ kw[key] = target.public_send(key)
24
+ end
25
+ end
26
+ end
27
+ end
@@ -4,8 +4,7 @@ require 'concurrent'
4
4
 
5
5
  module JSONAPIonify::Structure
6
6
  module Collections
7
- class Base < Concurrent::Array
8
- include EnumerableObserver
7
+ class Base < Array
9
8
  include Helpers::InheritsOrigin
10
9
  attr_reader :parent
11
10
 
@@ -20,11 +19,6 @@ module JSONAPIonify::Structure
20
19
  value_is Objects::Base
21
20
 
22
21
  def initialize(array = [])
23
- observe.added do |items|
24
- items.each do |item|
25
- item.instance_variable_set(:@parent, self) unless item.frozen?
26
- end
27
- end
28
22
  array.each do |instance|
29
23
  self << instance
30
24
  end
@@ -82,7 +76,25 @@ module JSONAPIonify::Structure
82
76
  )
83
77
  end
84
78
  end
85
- super new_instance
79
+ self[length] = new_instance
80
+ end
81
+
82
+ def [] k
83
+ v = super
84
+ v.nil? || v.instance_variable_get(:@parent) == self ? v : self[k] = v
85
+ end
86
+
87
+ def []= k, v
88
+ unless v.nil? || v.instance_variable_get(:@parent) == self
89
+ v = v.dup.tap { |obj| obj.instance_variable_set :@parent, self}
90
+ end
91
+ super(k, v)
92
+ end
93
+
94
+ def each
95
+ length.times do |i|
96
+ yield self[i]
97
+ end
86
98
  end
87
99
 
88
100
  def errors
@@ -54,7 +54,7 @@ module JSONAPIonify::Structure
54
54
 
55
55
  # Initialize the object
56
56
  def initialize(**attributes)
57
- @object = Concurrent::Hash.new
57
+ @object = Hash.new
58
58
  run_callbacks :initialize do
59
59
  attributes.each do |k, v|
60
60
  self[k] = v
@@ -90,7 +90,7 @@ module JSONAPIonify::Structure
90
90
  end
91
91
 
92
92
  def to_json(**opts)
93
- Oj.dump(as_json **opts)
93
+ Oj.dump as_json(**opts)
94
94
  end
95
95
 
96
96
  def signature
@@ -155,6 +155,15 @@ module JSONAPIonify::Structure
155
155
  JSON.pretty_generate as_json
156
156
  end
157
157
 
158
+ def inspect
159
+ hash_inspect = to_h.to_s.gsub(
160
+ /\:([a-zA-Z_-]+)=>/, '\\1: '
161
+ )[1..-2].gsub(
162
+ /\{([^\s])/, '{ \\1').gsub(/([^\s])\}/, '\\1 }'
163
+ )
164
+ to_s.sub(/>$/, " #{hash_inspect}>")
165
+ end
166
+
158
167
  private
159
168
 
160
169
  def collect_child_errors
@@ -1,7 +1,8 @@
1
1
  module JSONAPIonify::Structure
2
2
  module Objects
3
3
  class ResourceIdentifier < Base
4
- define_order *%i{type id}
4
+
5
+ define_order :type, :id
5
6
 
6
7
  # A resource object **MUST** contain at least the following top-level members:
7
8
  must_contain! :id, :type # Describes ResourceObjects that share common attributes and relationships.
@@ -22,25 +23,19 @@ module JSONAPIonify::Structure
22
23
 
23
24
  def duplicate_exists?
24
25
  return false unless parent.is_a?(Array)
25
- peers = parent - [self]
26
- !!peers.index(self)
27
- end
28
-
29
- def ==(other)
30
- same_as? other
26
+ parent.select { |peer| peer.eql? self }.length > 1
31
27
  end
32
28
 
33
29
  def duplicate_does_not_exist?
34
30
  !duplicate_exists?
35
31
  end
36
32
 
37
- def same_as?(other)
38
- return false unless other.is_a? ResourceIdentifier
39
- other_type, other_id = other.values_at :type, :id
40
- local_type, local_id = values_at :type, :id
41
- other_type == local_type &&
42
- !(other_id || local_id).nil? &&
43
- other_id == local_id
33
+ def hash
34
+ { type: self[:type], id: self[:id] }.hash
35
+ end
36
+
37
+ def eql?(other)
38
+ other.hash == self.hash
44
39
  end
45
40
 
46
41
  end
@@ -1,3 +1,3 @@
1
1
  module JSONAPIonify
2
- VERSION = "0.11.11"
2
+ VERSION = "0.12.0"
3
3
  end
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.11.11
4
+ version: 0.12.0
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-01 00:00:00.000000000 Z
11
+ date: 2016-07-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -206,6 +206,20 @@ dependencies:
206
206
  - - ! '>='
207
207
  - !ruby/object:Gem::Version
208
208
  version: '0'
209
+ - !ruby/object:Gem::Dependency
210
+ name: yard
211
+ requirement: !ruby/object:Gem::Requirement
212
+ requirements:
213
+ - - ! '>='
214
+ - !ruby/object:Gem::Version
215
+ version: '0'
216
+ type: :development
217
+ prerelease: false
218
+ version_requirements: !ruby/object:Gem::Requirement
219
+ requirements:
220
+ - - ! '>='
221
+ - !ruby/object:Gem::Version
222
+ version: '0'
209
223
  - !ruby/object:Gem::Dependency
210
224
  name: pry-byebug
211
225
  requirement: !ruby/object:Gem::Requirement
@@ -511,6 +525,7 @@ files:
511
525
  - bin/console
512
526
  - bin/setup
513
527
  - config.ru
528
+ - examples/example_api.rb
514
529
  - index.html
515
530
  - jsonapionify.gemspec
516
531
  - lib/core_ext/boolean.rb
@@ -552,6 +567,7 @@ files:
552
567
  - lib/jsonapionify/api/resource/builders/resource_builder.rb
553
568
  - lib/jsonapionify/api/resource/builders/resource_identifer_builder.rb
554
569
  - lib/jsonapionify/api/resource/caching.rb
570
+ - lib/jsonapionify/api/resource/callbacks.rb
555
571
  - lib/jsonapionify/api/resource/caller.rb
556
572
  - lib/jsonapionify/api/resource/class_methods.rb
557
573
  - lib/jsonapionify/api/resource/defaults.rb
@@ -567,6 +583,7 @@ files:
567
583
  - lib/jsonapionify/api/resource/definitions/attributes.rb
568
584
  - lib/jsonapionify/api/resource/definitions/contexts.rb
569
585
  - lib/jsonapionify/api/resource/definitions/helpers.rb
586
+ - lib/jsonapionify/api/resource/definitions/includes.rb
570
587
  - lib/jsonapionify/api/resource/definitions/pagination.rb
571
588
  - lib/jsonapionify/api/resource/definitions/params.rb
572
589
  - lib/jsonapionify/api/resource/definitions/relationships.rb
@@ -591,6 +608,7 @@ files:
591
608
  - lib/jsonapionify/character_range.rb
592
609
  - lib/jsonapionify/continuation.rb
593
610
  - lib/jsonapionify/deep_sort_collection.rb
611
+ - lib/jsonapionify/destructured_proc.rb
594
612
  - lib/jsonapionify/documentation.rb
595
613
  - lib/jsonapionify/documentation/template.erb
596
614
  - lib/jsonapionify/indented_string.rb