simple_json_api 0.0.3 → 0.0.4

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.
Files changed (47) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +14 -2
  3. data/README.md +1 -1
  4. data/lib/generators/simple_json_api/resource/USAGE +8 -0
  5. data/lib/generators/simple_json_api/resource/resource_generator.rb +73 -0
  6. data/lib/generators/simple_json_api/resource/templates/controller_template.rb.erb +34 -0
  7. data/lib/generators/simple_json_api/resource/templates/serializer_template.rb.erb +14 -0
  8. data/lib/simple_json_api/api_node.rb +68 -0
  9. data/lib/simple_json_api/array_serializer.rb +15 -1
  10. data/lib/simple_json_api/association.rb +16 -0
  11. data/lib/simple_json_api/attribute.rb +9 -0
  12. data/lib/simple_json_api/builder.rb +35 -0
  13. data/lib/simple_json_api/dsl.rb +35 -5
  14. data/lib/simple_json_api/field_list.rb +2 -7
  15. data/lib/simple_json_api/helper.rb +5 -0
  16. data/lib/simple_json_api/include_list.rb +12 -7
  17. data/lib/simple_json_api/json_api_wrapper.rb +46 -0
  18. data/lib/simple_json_api/member/data.rb +14 -0
  19. data/lib/simple_json_api/member/included.rb +38 -0
  20. data/lib/simple_json_api/member/links.rb +9 -0
  21. data/lib/simple_json_api/member/meta.rb +9 -0
  22. data/lib/simple_json_api/refinements/active_record.rb +23 -0
  23. data/lib/simple_json_api/refinements/array.rb +13 -0
  24. data/lib/simple_json_api/refinements/symbol.rb +17 -0
  25. data/lib/simple_json_api/resource.rb +23 -0
  26. data/lib/simple_json_api/resource_serializer.rb +25 -24
  27. data/lib/simple_json_api/serializer.rb +39 -2
  28. data/lib/simple_json_api/serializer_factory.rb +22 -0
  29. data/lib/simple_json_api/version.rb +1 -1
  30. data/lib/simple_json_api.rb +7 -29
  31. data/simple_json_api.gemspec +2 -7
  32. data/test/generators/simple_json_api/resource_generator_test.rb +31 -0
  33. data/test/integration/render_basic_test.rb +10 -7
  34. data/test/integration/render_fields_test.rb +35 -16
  35. data/test/integration/render_include_test.rb +66 -63
  36. data/test/integration/render_nested_include_test.rb +38 -83
  37. data/test/integration/serializers_test.rb +1 -1
  38. data/test/setup/data.rb +7 -3
  39. data/test/setup/serializers.rb +2 -0
  40. data/test/test_helper.rb +3 -9
  41. data/test/unit/field_list_test.rb +0 -10
  42. data/test/unit/include_list_test.rb +35 -5
  43. data/test/unit/symbol_refinement_test.rb +16 -0
  44. metadata +25 -89
  45. data/lib/simple_json_api/active_record_refinements.rb +0 -21
  46. data/lib/simple_json_api/array_refinements.rb +0 -14
  47. data/lib/simple_json_api/json_api_builder.rb +0 -84
@@ -0,0 +1,5 @@
1
+ module SimpleJsonApi
2
+ # Controller helper methods
3
+ module Helper
4
+ end
5
+ end
@@ -2,19 +2,24 @@
2
2
  module SimpleJsonApi
3
3
  # List of Included associations for a resource
4
4
  class IncludeList
5
+ attr_reader :include_hash
6
+
5
7
  def initialize(include)
6
8
  @include = include
7
- @include_list = []
9
+ # autovivificious hash
10
+ @include_hash = Hash.new do |hash, key|
11
+ hash[key] = Hash.new(&hash.default_proc)
12
+ end
8
13
  end
9
14
 
10
15
  def parse
11
- @include_list = @include.split(',').map(&:to_s) if @include.is_a? String
16
+ @include.split(',').each do |a|
17
+ inc = a.split('.').inject(@include_hash) do |hash, key|
18
+ hash[key.pluralize.to_sym]
19
+ end
20
+ inc[:include] = true
21
+ end if @include
12
22
  self
13
23
  end
14
-
15
- def include?(resource, parent = [])
16
- path = [parent, resource].flatten.compact.join('.')
17
- @include_list.include?(path)
18
- end
19
24
  end
20
25
  end
@@ -0,0 +1,46 @@
1
+ require 'simple_json_api/member/data'
2
+ require 'simple_json_api/member/included'
3
+ require 'simple_json_api/member/links'
4
+ require 'simple_json_api/member/meta'
5
+
6
+ module SimpleJsonApi
7
+ # JSONAPI Wrapper
8
+ class JsonApiWrapper
9
+ def initialize(root_node)
10
+ @root_node = root_node
11
+ @result = {}
12
+ end
13
+
14
+ def as_json(_options = nil)
15
+ add_members
16
+ @result.delete_if { |_, content| content.blank? }
17
+ @result
18
+ end
19
+
20
+ private
21
+
22
+ def add_members
23
+ links
24
+ meta
25
+ data
26
+ included
27
+ end
28
+
29
+ def links
30
+ @result[:links] ||= Member::Links.new.content
31
+ end
32
+
33
+ def meta
34
+ @result[:meta] ||= Member::Meta.new.content
35
+ end
36
+
37
+ def data
38
+ @result[:data] ||= Member::Data.new(@root_node).content
39
+ end
40
+
41
+ def included
42
+ @result[:included] ||=
43
+ Member::Included.new(@root_node, @result[:data]).content
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,14 @@
1
+ module SimpleJsonApi
2
+ module Member
3
+ # JSONAPI Data top-level member
4
+ class Data
5
+ def initialize(root_node)
6
+ @root_node = root_node
7
+ end
8
+
9
+ def content
10
+ @root_node.serialize
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,38 @@
1
+ module SimpleJsonApi
2
+ module Member
3
+ # JSONAPI Included top-level member
4
+ class Included
5
+ def initialize(root_node, data)
6
+ @root_node = root_node
7
+ @data = data
8
+ @included = []
9
+ end
10
+
11
+ def content
12
+ visit(@root_node)
13
+ @included
14
+ end
15
+
16
+ def visit(node)
17
+ node.associations.each do |association|
18
+ process(association) if included?(association)
19
+ visit(association)
20
+ end
21
+ end
22
+
23
+ def process(association)
24
+ Array[association.serialize].flatten.each do |hash|
25
+ @included << hash unless already_included? hash
26
+ end
27
+ end
28
+
29
+ def included?(association)
30
+ association.assoc_list[:include].present?
31
+ end
32
+
33
+ def already_included?(resource)
34
+ @included.include?(resource) || Array(@data).include?(resource)
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,9 @@
1
+ module SimpleJsonApi
2
+ module Member
3
+ # JSONAPI Links top-level member
4
+ class Links
5
+ def content
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ module SimpleJsonApi
2
+ module Member
3
+ # JSONAPI Meta top-level member
4
+ class Meta
5
+ def content
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,23 @@
1
+ require 'active_record'
2
+
3
+ # SimpleJsonApi
4
+ module SimpleJsonApi
5
+ module Refinements
6
+ # Refinements on ActiveRecord
7
+ module ActiveRecord
8
+ refine ::ActiveRecord::Base do
9
+ def typed_json_id
10
+ [self.class.to_s.downcase.pluralize, json_id]
11
+ end
12
+
13
+ def json_id
14
+ send(json_pk).to_s
15
+ end
16
+
17
+ def json_pk
18
+ self.class.primary_key.to_sym
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,13 @@
1
+ # SimpleJsonApi
2
+ module SimpleJsonApi
3
+ module Refinements
4
+ # Refinements on Array
5
+ module Array
6
+ refine ::Array do
7
+ def includes(includes = nil)
8
+ self
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,17 @@
1
+ # SimpleJsonApi
2
+ module SimpleJsonApi
3
+ module Refinements
4
+ # Refinements on Hash
5
+ module Symbol
6
+ refine ::Symbol do
7
+ def pluralize
8
+ to_s.pluralize.to_sym
9
+ end
10
+
11
+ def singularize
12
+ to_s.singularize.to_sym
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,23 @@
1
+ module SimpleJsonApi
2
+ # The representation of a Resource
3
+ class Resource
4
+ extend Forwardable
5
+ def_delegators :@content, :[], :as_json
6
+
7
+ def initialize(content)
8
+ @content = content
9
+ end
10
+
11
+ def ==(other)
12
+ (@content[:type] &&
13
+ (@content[:type] == other[:type])) &&
14
+ (@content[:id] &&
15
+ (@content[:id] == other[:id]))
16
+ end
17
+ # alias_method :eql?, :==
18
+
19
+ # def hash
20
+ # [@content[:id], @content[:type], Resource].hash
21
+ # end
22
+ end
23
+ end
@@ -1,27 +1,39 @@
1
+ require 'simple_json_api/refinements/active_record'
2
+ require 'simple_json_api/refinements/symbol'
3
+
1
4
  # SimpleJsonApi
2
5
  module SimpleJsonApi
3
6
  # The Serializer will serialize a model
4
7
  class ResourceSerializer < Serializer
5
- using ActiveRecordRefinements
8
+ using Refinements::ActiveRecord
9
+ using Refinements::Symbol
6
10
 
7
11
  def _root_name
8
12
  self.class._root_name
9
13
  end
10
14
 
15
+ def type
16
+ _root_name
17
+ end
18
+
19
+ def id
20
+ _object.try(:id) || _object.try(:guid)
21
+ end
22
+
11
23
  def _fields
12
- @_fields ||= begin
13
- defaults = self.class.default_fields.split(',')
14
- builders = _builder.fields_for(_root_name).presence
15
- (builders || defaults).map(&:to_sym)
16
- end
24
+ @_fields ||= _get_fields
25
+ end
26
+
27
+ # If default_fields is not specified, use all_fields
28
+ def _get_fields
29
+ builder_fields
17
30
  end
18
31
 
19
32
  def serialize
20
33
  hash = {}
21
34
  attribute_values(hash)
22
35
  link_values(hash[:links] = {})
23
- _association_values
24
- hash
36
+ Resource.new(hash)
25
37
  end
26
38
 
27
39
  def attribute_values(hash)
@@ -38,31 +50,20 @@ module SimpleJsonApi
38
50
  end
39
51
 
40
52
  def link(association)
41
- resource = send(association.name)
42
53
  if association.type == :has_many
43
- resource.to_a.map do |obj|
54
+ includes = association.polymorphic ? [] : Serializer.includes(association)
55
+ resource = send(association.name, includes)
56
+ resource.map do |obj|
44
57
  association[:polymorphic] ? obj.typed_json_id : obj.json_id
45
58
  end
46
59
  else
47
- resource.json_id
60
+ resource = send(association.name)
61
+ resource.json_id if resource
48
62
  end
49
63
  end
50
64
 
51
65
  def _associations
52
66
  self.class._associations
53
67
  end
54
-
55
- def _association_values
56
- _associations.each do |association|
57
- name = association[:name]
58
- obj = send(name)
59
- _builder.add_linked_elem(
60
- name,
61
- obj,
62
- association,
63
- @_base
64
- )
65
- end
66
- end
67
68
  end
68
69
  end
@@ -1,3 +1,6 @@
1
+ require 'simple_json_api/dsl'
2
+ # require 'simple_json_api/refinements/array'
3
+
1
4
  # SimpleJsonApi
2
5
  module SimpleJsonApi
3
6
  # The Serializer will serialize a model
@@ -16,6 +19,34 @@ module SimpleJsonApi
16
19
  @_base = base
17
20
  end
18
21
 
22
+ def associated_object(association_name)
23
+ send(association_name)
24
+ end
25
+
26
+ private
27
+
28
+ def default_fields
29
+ self.class._default_fields
30
+ end
31
+
32
+ def all_fields
33
+ self.class.default_attributes.split(',')
34
+ end
35
+
36
+ def required_fields
37
+ [:type, :id]
38
+ end
39
+
40
+ def builder_fields
41
+ bf = _builder.fields_for(_root_name).presence
42
+ fields = if bf.present?
43
+ (required_fields + Array(bf)).uniq
44
+ else
45
+ default_fields ? default_fields & all_fields : all_fields
46
+ end
47
+ (required_fields + Array(fields)).uniq.map(&:to_sym)
48
+ end
49
+
19
50
  class << self
20
51
  attr_reader :registered_serializers
21
52
 
@@ -26,6 +57,7 @@ module SimpleJsonApi
26
57
  end
27
58
 
28
59
  def for(model, association)
60
+ return association.serializer if association.serializer.present?
29
61
  if association[:polymorphic]
30
62
  for_polymorphic(model)
31
63
  else
@@ -33,19 +65,24 @@ module SimpleJsonApi
33
65
  end
34
66
  end
35
67
 
68
+ def includes(association)
69
+ serializer = Serializer.for_regular(association)
70
+ serializer._associations.reject(&:polymorphic).map { |a| a[:name] } if serializer
71
+ end
72
+
36
73
  def for_regular(association)
37
74
  resource = association[:name].to_s.pluralize.to_sym
38
75
  serializer = @registered_serializers.find do |entry|
39
76
  entry[:resource] == resource
40
77
  end
41
- serializer[:serializer]
78
+ serializer[:serializer] if serializer
42
79
  end
43
80
 
44
81
  def for_polymorphic(model)
45
82
  serializer = @registered_serializers.find do |entry|
46
83
  entry[:model] == model.class
47
84
  end
48
- serializer[:serializer]
85
+ serializer[:serializer] if serializer
49
86
  end
50
87
  end
51
88
  end
@@ -0,0 +1,22 @@
1
+ require 'simple_json_api/serializer'
2
+ require 'simple_json_api/array_serializer'
3
+ require 'simple_json_api/resource_serializer'
4
+
5
+ # SimpleJsonApi
6
+ module SimpleJsonApi
7
+ # The SerializerFactory will return the serializer for an object
8
+ class SerializerFactory
9
+ def self.create(object, serializer, builder)
10
+ if use_array_serializer?(object)
11
+ ArraySerializer.new(object, builder, serializer)
12
+ else
13
+ serializer.new(object, builder)
14
+ end
15
+ end
16
+
17
+ def self.use_array_serializer?(object)
18
+ object.is_a?(Array) ||
19
+ object.is_a?(ActiveRecord::Associations::CollectionProxy)
20
+ end
21
+ end
22
+ end
@@ -1,4 +1,4 @@
1
1
  # SimpleJsonApi
2
2
  module SimpleJsonApi
3
- VERSION = '0.0.3'
3
+ VERSION = '0.0.4'
4
4
  end
@@ -1,38 +1,16 @@
1
1
  require 'simple_json_api/version'
2
2
 
3
- require 'simple_json_api/active_record_refinements'
4
- require 'simple_json_api/array_refinements'
5
- # require 'simple_json_api/association'
6
- # require 'simple_json_api/attribute'
7
- require 'simple_json_api/dsl'
8
- require 'simple_json_api/field_list'
9
- require 'simple_json_api/include_list'
3
+ require 'simple_json_api/json_api_wrapper'
4
+ require 'simple_json_api/builder'
5
+ require 'simple_json_api/resource'
6
+ require 'simple_json_api/helper'
10
7
 
11
- require 'simple_json_api/serializer'
12
- require 'simple_json_api/array_serializer'
13
- require 'simple_json_api/resource_serializer'
14
-
15
- require 'simple_json_api/json_api_builder'
8
+ # require 'simple_json_api/helper'
16
9
 
17
10
  # SimpleJsonApi
18
11
  module SimpleJsonApi
19
- # Wrapper for a linked association
20
- Association = Struct.new(:name, :type, :serializer, :polymorphic, :key) do
21
- def key
22
- name_s = name.to_s
23
- (type == :has_many) ? name_s.pluralize.to_sym : name_s.singularize.to_sym
24
- end
25
- end
26
-
27
- # Attribute
28
- Attribute = Struct.new(:name, :key) do
29
- def key
30
- self[:key] || self[:name]
31
- end
32
- end
33
-
34
12
  # Main hook to generate json
35
- def self.render(model:, serializer:, options: {})
36
- JsonApiBuilder.new(model, serializer, options).to_json
13
+ def self.render(model:, serializer:, fields: nil, include: nil, wrapper: JsonApiWrapper)
14
+ Builder.new(model, wrapper, serializer, fields, include).to_json
37
15
  end
38
16
  end