jat 0.0.6 → 0.0.10

Sign up to get free protection for your applications and to get access to all the features.
Files changed (72) hide show
  1. checksums.yaml +4 -4
  2. data/lib/jat/attribute.rb +5 -18
  3. data/lib/jat/config.rb +5 -20
  4. data/lib/jat/plugins/{common/_activerecord_preloads/_activerecord_preloads.rb → base/base_activerecord_preloads/base_activerecord_preloads.rb} +3 -3
  5. data/lib/jat/plugins/{common/_activerecord_preloads → base/base_activerecord_preloads}/lib/preloader.rb +3 -1
  6. data/lib/jat/plugins/{common/_lower_camel_case/_lower_camel_case.rb → base/base_lower_camel_case/base_lower_camel_case.rb} +3 -3
  7. data/lib/jat/plugins/{common/_preloads/_preloads.rb → base/base_preloads/base_preloads.rb} +3 -3
  8. data/lib/jat/plugins/{common/_preloads → base/base_preloads}/lib/format_user_preloads.rb +1 -1
  9. data/lib/jat/plugins/{common/_preloads → base/base_preloads}/lib/preloads_with_path.rb +1 -1
  10. data/lib/jat/plugins/json_api/lib/fields_param_parser.rb +1 -10
  11. data/lib/jat/plugins/json_api/lib/include_param_parser.rb +1 -10
  12. data/lib/jat/plugins/json_api/lib/map.rb +5 -15
  13. data/lib/jat/plugins/json_api/lib/response.rb +2 -15
  14. data/lib/jat/plugins/json_api/lib/response_piece.rb +10 -19
  15. data/lib/jat/plugins/json_api/plugins/json_api_activerecord/json_api_activerecord.rb +1 -1
  16. data/lib/jat/plugins/json_api/plugins/json_api_lower_camel_case/json_api_lower_camel_case.rb +1 -1
  17. data/lib/jat/plugins/json_api/plugins/json_api_preloads/json_api_preloads.rb +1 -1
  18. data/lib/jat/plugins/json_api/plugins/json_api_validate_params/lib/validate_include_param.rb +1 -3
  19. data/lib/jat/plugins/presenter/presenter.rb +79 -0
  20. data/lib/jat/plugins/simple_api/lib/fields_param_parser.rb +21 -46
  21. data/lib/jat/plugins/simple_api/lib/map.rb +5 -15
  22. data/lib/jat/plugins/simple_api/lib/response.rb +2 -15
  23. data/lib/jat/plugins/simple_api/lib/response_piece.rb +2 -15
  24. data/lib/jat/plugins/simple_api/plugins/simple_api_activerecord/simple_api_activerecord.rb +1 -1
  25. data/lib/jat/plugins/simple_api/plugins/simple_api_lower_camel_case/simple_api_lower_camel_case.rb +1 -1
  26. data/lib/jat/plugins/simple_api/plugins/simple_api_preloads/simple_api_preloads.rb +1 -1
  27. data/lib/jat/plugins/simple_api/plugins/simple_api_validate_params/simple_api_validate_params.rb +1 -1
  28. data/lib/jat/plugins/simple_api/simple_api.rb +1 -1
  29. data/lib/jat/plugins/types/types.rb +55 -0
  30. data/lib/jat/plugins.rb +38 -25
  31. data/lib/jat/utils/jat_class.rb +21 -0
  32. data/lib/jat.rb +9 -6
  33. data/test/lib/jat/attribute_test.rb +8 -0
  34. data/test/lib/jat/plugins/activerecord/activerecord_test.rb +27 -0
  35. data/test/lib/jat/plugins/{_activerecord_preloads/_activerecord_preloads_test.rb → base_activerecord_preloads/base_activerecord_preloads_test.rb} +3 -3
  36. data/test/lib/jat/plugins/{_activerecord_preloads → base_activerecord_preloads}/lib/preloader_test.rb +2 -2
  37. data/test/lib/jat/plugins/{_camel_lower/_camel_lower_test.rb → base_lower_camel_case/base_lower_camel_case_test.rb} +2 -2
  38. data/test/lib/jat/plugins/{_preloads/_preloads_test.rb → base_preloads/base_preloads_test.rb} +2 -2
  39. data/test/lib/jat/plugins/{_preloads → base_preloads}/lib/format_user_preloads_test.rb +3 -3
  40. data/test/lib/jat/plugins/{_preloads → base_preloads}/lib/preloads_with_path_test.rb +2 -2
  41. data/test/lib/jat/plugins/json_api/json_api_test.rb +1 -1
  42. data/test/lib/jat/plugins/json_api/lib/fields_param_parser_test.rb +20 -12
  43. data/test/lib/jat/plugins/json_api/lib/include_param_parser_test.rb +25 -11
  44. data/test/lib/jat/plugins/json_api/lib/map_test.rb +132 -124
  45. data/test/lib/jat/plugins/json_api/lib/response_piece_test.rb +13 -0
  46. data/test/lib/jat/plugins/json_api/lib/response_test.rb +6 -1
  47. data/test/lib/jat/plugins/json_api_activerecord/json_api_activerecord_test.rb +1 -1
  48. data/test/lib/jat/plugins/{json_api_camel_lower/json_api_camel_lower_test.rb → json_api_lower_camel_case/json_api_lower_camel_case_test.rb} +6 -0
  49. data/test/lib/jat/plugins/json_api_preloads/json_api_preloads_test.rb +16 -2
  50. data/test/lib/jat/plugins/json_api_preloads/lib/preloads_test.rb +0 -3
  51. data/test/lib/jat/plugins/json_api_validate_params/json_api_validate_params_test.rb +30 -6
  52. data/test/lib/jat/plugins/lower_camel_case/lower_camel_case_test.rb +27 -0
  53. data/test/lib/jat/plugins/maps_cache/maps_cache_test.rb +27 -0
  54. data/test/lib/jat/plugins/preloads/preloads_test.rb +27 -0
  55. data/test/lib/jat/plugins/presenter/presenter_test.rb +215 -0
  56. data/test/lib/jat/plugins/simple_api/lib/fields_param_parser_test.rb +57 -43
  57. data/test/lib/jat/plugins/simple_api/lib/map_test.rb +90 -82
  58. data/test/lib/jat/plugins/simple_api/lib/response_piece_test.rb +13 -0
  59. data/test/lib/jat/plugins/simple_api/lib/response_test.rb +17 -11
  60. data/test/lib/jat/plugins/simple_api/simple_api_test.rb +36 -1
  61. data/test/lib/jat/plugins/simple_api_activerecord/simple_api_activerecord_test.rb +1 -1
  62. data/test/lib/jat/plugins/{simple_api_camel_lower/simple_api_camel_lower_test.rb → simple_api_lower_camel_case/simple_api_lower_camel_case_test.rb} +7 -1
  63. data/test/lib/jat/plugins/simple_api_preloads/lib/preloads_test.rb +1 -6
  64. data/test/lib/jat/plugins/simple_api_preloads/simple_api_preloads_test.rb +16 -2
  65. data/test/lib/jat/plugins/simple_api_validate_params/simple_api_validate_params_test.rb +12 -0
  66. data/test/lib/jat/plugins/types/types_test.rb +83 -0
  67. data/test/lib/jat/plugins/validate_params/validate_params_test.rb +27 -0
  68. data/test/lib/jat/plugins_test.rb +89 -0
  69. data/test/test_helper.rb +14 -4
  70. metadata +72 -67
  71. data/test/lib/plugin_test.rb +0 -49
  72. data/test/test_plugin.rb +0 -56
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 18b7274ab643b613d2356e6f4704683d0ee17f6789fc3c01ba5c6435b09c0c84
4
- data.tar.gz: 197d92680d9bbe8610eca370516fc2b7a36bb7a6dfadf0a2fc75ce5e3959af90
3
+ metadata.gz: d7b5ab9fe35df564d6282bd57f3008293bbc38e72c7dbf0ade8ef27734aafb10
4
+ data.tar.gz: c2bd6717c5555e862bdaafab2bdd16f510d7535be1922e0327253fee7d8cb248
5
5
  SHA512:
6
- metadata.gz: f887b6f910f4677439e5842e4882eedb349e2bc6865e987b9dcec565dca83e20e13b2cf31eed117a332b1ae044c3194445f4241ba65c053c2b7adbba4ceb316d
7
- data.tar.gz: 9562212be2cacf78f9e6e166ca25d7eddfd995d15d16470b1b39cdd0e0cec33d8ffe14b912b4331d51079a6b16b76dd45f4cb2b9d7f74b3ebbab7dbcca202cee
6
+ metadata.gz: 2979f947fc8b2052632549e92990ef0f9039c582915cd405d97954f2a7aa6d7c6bf88627aea7e708f8417107a89e2ea089dfd3f0005425147cca297eb138e3f0
7
+ data.tar.gz: f90de936bc75392e315c4e8c5e8bf3e191aacaca84dd7b0a3dd924d93976e753bccf31425cc9b8588c406dbde0a0690cf0f13788d1e7ffb5871dfdcb553152a0
data/lib/jat/attribute.rb CHANGED
@@ -9,6 +9,8 @@ class Jat
9
9
  attr_reader :params, :opts
10
10
 
11
11
  def initialize(name:, opts: {}, block: nil)
12
+ check_block_valid(block)
13
+
12
14
  @opts = EnumDeepDup.call(opts)
13
15
  @params = EnumDeepFreeze.call(name: name, opts: @opts, block: block)
14
16
  end
@@ -61,7 +63,7 @@ class Jat
61
63
  def block
62
64
  return @block if instance_variable_defined?(:@block)
63
65
 
64
- current_block = params.fetch(:block).tap { |bl| check_block_valid(bl) if bl }
66
+ current_block = params.fetch(:block)
65
67
  current_block ||= keyword_block
66
68
 
67
69
  @block = current_block
@@ -79,29 +81,14 @@ class Jat
79
81
  end
80
82
 
81
83
  def check_block_valid(block)
82
- raise Error, "Block must be a Proc (not lambda)" if block.lambda?
84
+ return unless block
83
85
 
84
86
  params = block.parameters
85
87
  raise Error, "Block can have 0-2 parameters" if params.count > 2
86
-
87
- valid_params_types = params.all? { |param| param[0] == :opt }
88
- raise Error, "Block parameters must be optional and no keyword parameters" unless valid_params_types
89
- end
90
- end
91
-
92
- module ClassMethods
93
- # Returns the Jat class that this Attribute class is namespaced under.
94
- attr_accessor :jat_class
95
-
96
- # Since Attribute is anonymously subclassed when Jat is subclassed,
97
- # and then assigned to a constant of the Jat subclass, make inspect
98
- # reflect the likely name for the class.
99
- def inspect
100
- "#{jat_class.inspect}::Attribute"
101
88
  end
102
89
  end
103
90
 
104
- extend ClassMethods
91
+ extend Jat::JatClass
105
92
  include InstanceMethods
106
93
  end
107
94
  end
data/lib/jat/config.rb CHANGED
@@ -1,38 +1,23 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "forwardable"
3
4
  require_relative "utils/enum_deep_dup"
4
5
 
5
6
  class Jat
6
7
  class Config
7
8
  module InstanceMethods
9
+ extend Forwardable
10
+
8
11
  attr_reader :opts
9
12
 
10
13
  def initialize(opts = {})
11
14
  @opts = EnumDeepDup.call(opts)
12
15
  end
13
16
 
14
- def []=(key, value)
15
- opts[key] = value
16
- end
17
-
18
- def [](key)
19
- opts[key]
20
- end
21
- end
22
-
23
- module ClassMethods
24
- # Returns the Jat class that this config class is namespaced under.
25
- attr_accessor :jat_class
26
-
27
- # Since Config is anonymously subclassed when Jat is subclassed,
28
- # and then assigned to a constant of the Jat subclass, make inspect
29
- # reflect the likely name for the class.
30
- def inspect
31
- "#{jat_class.inspect}::Config"
32
- end
17
+ def_delegators :@opts, :[], :[]=, :fetch
33
18
  end
34
19
 
35
20
  include InstanceMethods
36
- extend ClassMethods
21
+ extend Jat::JatClass
37
22
  end
38
23
  end
@@ -4,9 +4,9 @@ require_relative "./lib/preloader"
4
4
 
5
5
  class Jat
6
6
  module Plugins
7
- module ActiverecordPreloads
7
+ module BaseActiverecordPreloads
8
8
  def self.plugin_name
9
- :_activerecord_preloads
9
+ :base_activerecord_preloads
10
10
  end
11
11
 
12
12
  def self.load(jat_class, **_opts)
@@ -33,6 +33,6 @@ class Jat
33
33
  end
34
34
  end
35
35
 
36
- register_plugin(ActiverecordPreloads.plugin_name, ActiverecordPreloads)
36
+ register_plugin(BaseActiverecordPreloads.plugin_name, BaseActiverecordPreloads)
37
37
  end
38
38
  end
@@ -2,7 +2,7 @@
2
2
 
3
3
  class Jat
4
4
  module Plugins
5
- module ActiverecordPreloads
5
+ module BaseActiverecordPreloads
6
6
  class Preloader
7
7
  module ClassMethods
8
8
  def preload(object, preloads)
@@ -21,6 +21,7 @@ class Jat
21
21
  end
22
22
 
23
23
  class Loader
24
+ # :nocov: We can check only one version of activerecord
24
25
  def self.call(records, associations)
25
26
  if ActiveRecord::VERSION::MAJOR >= 7
26
27
  ActiveRecord::Associations::Preloader.new(records: records, associations: associations).call
@@ -28,6 +29,7 @@ class Jat
28
29
  ActiveRecord::Associations::Preloader.new.preload(records, associations)
29
30
  end
30
31
  end
32
+ # :nocov:
31
33
  end
32
34
 
33
35
  class ActiverecordObject
@@ -2,9 +2,9 @@
2
2
 
3
3
  class Jat
4
4
  module Plugins
5
- module LowerCamelCase
5
+ module BaseLowerCamelCase
6
6
  def self.plugin_name
7
- :_lower_camel_case
7
+ :base_lower_camel_case
8
8
  end
9
9
 
10
10
  def self.load(jat_class, **_opts)
@@ -18,7 +18,7 @@ class Jat
18
18
  end
19
19
  end
20
20
 
21
- register_plugin(LowerCamelCase.plugin_name, LowerCamelCase)
21
+ register_plugin(BaseLowerCamelCase.plugin_name, BaseLowerCamelCase)
22
22
  end
23
23
 
24
24
  class LowerCamelCaseTransformation
@@ -6,9 +6,9 @@ require_relative "./lib/preloads_with_path"
6
6
  # This plugin adds attribute methods #preloads, #preloads_path
7
7
  class Jat
8
8
  module Plugins
9
- module Preloads
9
+ module BasePreloads
10
10
  def self.plugin_name
11
- :_preloads
11
+ :base_preloads
12
12
  end
13
13
 
14
14
  def self.load(jat_class, **_opts)
@@ -58,6 +58,6 @@ class Jat
58
58
  end
59
59
  end
60
60
 
61
- register_plugin(Preloads.plugin_name, Preloads)
61
+ register_plugin(BasePreloads.plugin_name, BasePreloads)
62
62
  end
63
63
  end
@@ -2,7 +2,7 @@
2
2
 
3
3
  class Jat
4
4
  module Plugins
5
- module Preloads
5
+ module BasePreloads
6
6
  class FormatUserPreloads
7
7
  METHODS = {
8
8
  Array => :array_to_hash,
@@ -2,7 +2,7 @@
2
2
 
3
3
  class Jat
4
4
  module Plugins
5
- module Preloads
5
+ module BasePreloads
6
6
  class PreloadsWithPath
7
7
  module ClassMethods
8
8
  BANG = "!"
@@ -7,16 +7,6 @@ class Jat
7
7
  module ClassMethods
8
8
  COMMA = ","
9
9
 
10
- # Returns the Jat class that this FieldsParamParser class is namespaced under.
11
- attr_accessor :jat_class
12
-
13
- # Since FieldsParamParser is anonymously subclassed when Jat is subclassed,
14
- # and then assigned to a constant of the Jat subclass, make inspect
15
- # reflect the likely name for the class.
16
- def inspect
17
- "#{jat_class.inspect}::FieldsParamParser"
18
- end
19
-
20
10
  def parse(fields)
21
11
  return FROZEN_EMPTY_HASH unless fields
22
12
 
@@ -33,6 +23,7 @@ class Jat
33
23
  end
34
24
  end
35
25
 
26
+ extend Jat::JatClass
36
27
  extend ClassMethods
37
28
  end
38
29
  end
@@ -8,16 +8,6 @@ class Jat
8
8
  COMMA = ","
9
9
  DOT = "."
10
10
 
11
- # Returns the Jat class that this IncludeParamParser class is namespaced under.
12
- attr_accessor :jat_class
13
-
14
- # Since IncludeParamParser is anonymously subclassed when Jat is subclassed,
15
- # and then assigned to a constant of the Jat subclass, make inspect
16
- # reflect the likely name for the class.
17
- def inspect
18
- "#{jat_class.inspect}::IncludeParamParser"
19
- end
20
-
21
11
  def parse(includes_string_param)
22
12
  return {} unless includes_string_param
23
13
 
@@ -77,6 +67,7 @@ class Jat
77
67
  end
78
68
  end
79
69
 
70
+ extend Jat::JatClass
80
71
  extend ClassMethods
81
72
  end
82
73
  end
@@ -5,16 +5,6 @@ class Jat
5
5
  module JsonApi
6
6
  class Map
7
7
  module ClassMethods
8
- # Returns the Jat class that this Map class is namespaced under.
9
- attr_accessor :jat_class
10
-
11
- # Since Map is anonymously subclassed when Jat is subclassed,
12
- # and then assigned to a constant of the Jat subclass, make inspect
13
- # reflect the likely name for the class.
14
- def inspect
15
- "#{jat_class.inspect}::Map"
16
- end
17
-
18
8
  # Returns structure like
19
9
  # {
20
10
  # type1 => {
@@ -103,14 +93,14 @@ class Jat
103
93
  end
104
94
 
105
95
  def attribute_exposed?(attribute)
106
- case exposed
107
- when :all then true
108
- when :none then false
109
- else attribute.exposed?
110
- end
96
+ return true if exposed == :all
97
+ return false if exposed == :none
98
+
99
+ attribute.exposed?
111
100
  end
112
101
  end
113
102
 
103
+ extend Jat::JatClass
114
104
  extend ClassMethods
115
105
  include InstanceMethods
116
106
  end
@@ -6,16 +6,6 @@ class Jat
6
6
  module JsonApi
7
7
  class Response
8
8
  module ClassMethods
9
- # Returns the Jat class that this Response class is namespaced under.
10
- attr_accessor :jat_class
11
-
12
- # Since Response is anonymously subclassed when Jat is subclassed,
13
- # and then assigned to a constant of the Jat subclass, make inspect
14
- # reflect the likely name for the class.
15
- def inspect
16
- "#{jat_class.inspect}::Response"
17
- end
18
-
19
9
  def call(object, context)
20
10
  new(object, context).to_h
21
11
  end
@@ -87,7 +77,7 @@ class Jat
87
77
  attributes.each do |name, attribute|
88
78
  next if data.key?(name)
89
79
 
90
- value = attribute_value(attribute)
80
+ value = attribute.value(object, context)
91
81
 
92
82
  unless value.nil?
93
83
  data = data.dup if data.equal?(FROZEN_EMPTY_HASH)
@@ -98,10 +88,6 @@ class Jat
98
88
  data
99
89
  end
100
90
 
101
- def attribute_value(attribute)
102
- attribute.block.call(object, context)
103
- end
104
-
105
91
  def context_jsonapi
106
92
  context_attr_transform(:jsonapi)
107
93
  end
@@ -119,6 +105,7 @@ class Jat
119
105
  end
120
106
  end
121
107
 
108
+ extend Jat::JatClass
122
109
  extend ClassMethods
123
110
  include InstanceMethods
124
111
  end
@@ -5,16 +5,6 @@ class Jat
5
5
  module JsonApi
6
6
  class ResponsePiece
7
7
  module ClassMethods
8
- # Returns the Jat class that this ResponsePiece class is namespaced under.
9
- attr_accessor :jat_class
10
-
11
- # Since ResponsePiece is anonymously subclassed when Jat is subclassed,
12
- # and then assigned to a constant of the Jat subclass, make inspect
13
- # reflect the likely name for the class.
14
- def inspect
15
- "#{jat_class.inspect}::ResponsePiece"
16
- end
17
-
18
8
  def call(object, context, map, includes)
19
9
  new(object, context, map, includes).to_h
20
10
  end
@@ -60,7 +50,7 @@ class Jat
60
50
 
61
51
  attributes_names.each_with_object({}) do |name, attrs|
62
52
  attribute = jat_class.attributes[name]
63
- attrs[name] = attribute.block.call(object, context)
53
+ attrs[name] = attribute.value(object, context)
64
54
  end
65
55
  end
66
56
 
@@ -70,7 +60,7 @@ class Jat
70
60
 
71
61
  relationships_names.each_with_object({}) do |name, rels|
72
62
  rel_attribute = jat_class.attributes[name]
73
- rel_object = rel_attribute.block.call(object, context)
63
+ rel_object = rel_attribute.value(object, context)
74
64
 
75
65
  rel_serializer = rel_attribute.serializer.call
76
66
  rel_links = get_relationship_links(rel_serializer, rel_object)
@@ -123,37 +113,37 @@ class Jat
123
113
  def get_links
124
114
  jat_class
125
115
  .object_links
126
- .transform_values { |attr| attr.block.call(object, context) }
116
+ .transform_values { |attr| attr.value(object, context) }
127
117
  .tap(&:compact!)
128
118
  end
129
119
 
130
120
  def get_meta
131
121
  jat_class
132
122
  .added_object_meta
133
- .transform_values { |attr| attr.block.call(object, context) }
123
+ .transform_values { |attr| attr.value(object, context) }
134
124
  .tap(&:compact!)
135
125
  end
136
126
 
137
127
  def get_relationship_links(rel_serializer, rel_object)
138
128
  links = rel_serializer.relationship_links
139
- return FROZEN_EMPTY_HASH unless links
129
+ return FROZEN_EMPTY_HASH if links.empty?
140
130
 
141
131
  context[:parent_object] = object
142
132
 
143
133
  links
144
- .transform_values { |attr| attr.block.call(rel_object, context) }
134
+ .transform_values { |attr| attr.value(rel_object, context) }
145
135
  .tap(&:compact!)
146
136
  .tap { context.delete(:parent_object) }
147
137
  end
148
138
 
149
139
  def get_relationship_meta(rel_serializer, rel_object)
150
140
  meta = rel_serializer.added_relationship_meta
151
- return FROZEN_EMPTY_HASH unless meta
141
+ return FROZEN_EMPTY_HASH if meta.empty?
152
142
 
153
143
  context[:parent_object] = object
154
144
 
155
145
  meta
156
- .transform_values { |attr| attr.block.call(rel_object, context) }
146
+ .transform_values { |attr| attr.value(rel_object, context) }
157
147
  .tap(&:compact!)
158
148
  .tap { context.delete(:parent_object) }
159
149
  end
@@ -163,10 +153,11 @@ class Jat
163
153
  end
164
154
 
165
155
  def id
166
- @id ||= jat_class.get_id.block.call(object, context)
156
+ @id ||= jat_class.get_id.value(object, context)
167
157
  end
168
158
  end
169
159
 
160
+ extend Jat::JatClass
170
161
  extend ClassMethods
171
162
  include InstanceMethods
172
163
  end
@@ -14,7 +14,7 @@ class Jat
14
14
 
15
15
  def self.load(jat_class, **opts)
16
16
  jat_class.plugin :json_api_preloads, **opts
17
- jat_class.plugin :_activerecord_preloads, **opts
17
+ jat_class.plugin :base_activerecord_preloads, **opts
18
18
  end
19
19
  end
20
20
 
@@ -10,7 +10,7 @@ class Jat
10
10
  def self.before_load(jat_class, **_opts)
11
11
  raise Error, "Please load :json_api plugin first" unless jat_class.plugin_used?(:json_api)
12
12
 
13
- jat_class.plugin :_lower_camel_case
13
+ jat_class.plugin :base_lower_camel_case
14
14
  end
15
15
 
16
16
  def self.load(jat_class, **_opts)
@@ -12,7 +12,7 @@ class Jat
12
12
  def self.before_load(jat_class, **opts)
13
13
  raise Error, "Please load :json_api plugin first" unless jat_class.plugin_used?(:json_api)
14
14
 
15
- jat_class.plugin :_preloads, **opts
15
+ jat_class.plugin :base_preloads, **opts
16
16
  end
17
17
 
18
18
  def self.load(jat_class, **_opts)
@@ -22,9 +22,7 @@ class Jat
22
22
  allowed_relationships = jat_class.attributes.each_value.select(&:relation?).map!(&:name)
23
23
  allowed_relationships = "'#{allowed_relationships.join("', '")}'"
24
24
 
25
- raise JsonApiParamsError,
26
- "Type '#{type}' has no included '#{name}' relationship. " \
27
- "Existing relationships are: #{allowed_relationships}"
25
+ raise JsonApiParamsError, "Type '#{type}' has no included '#{name}' relationship. Existing relationships are: #{allowed_relationships}"
28
26
  end
29
27
  end
30
28
  end
@@ -0,0 +1,79 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "delegate"
4
+ require "forwardable"
5
+
6
+ class Jat
7
+ module Plugins
8
+ module Presenter
9
+ def self.plugin_name
10
+ :presenter
11
+ end
12
+
13
+ def self.before_load(jat_class, **opts)
14
+ if jat_class.plugin_used?(:json_api)
15
+ jat_class.plugin :json_api_preloads, **opts
16
+ elsif jat_class.plugin_used?(:simple_api)
17
+ jat_class.plugin :simple_api_preloads, **opts
18
+ else
19
+ raise Error, "Please load :json_api or :simple_api plugin first"
20
+ end
21
+ end
22
+
23
+ def self.load(jat_class, **_opts)
24
+ jat_class.extend(ClassMethods)
25
+ jat_class::ResponsePiece.include(ResponsePieceInstanceMethods)
26
+ end
27
+
28
+ def self.after_load(jat_class, **_opts)
29
+ presenter_class = Class.new(Presenter)
30
+ presenter_class.jat_class = jat_class
31
+ jat_class.const_set(:Presenter, presenter_class)
32
+ end
33
+
34
+ class Presenter < SimpleDelegator
35
+ module InstanceMethods
36
+ # Delegates all missing methods to current object.
37
+ # We create real methods after first missing method.
38
+ # rubocop:disable Style/MissingRespondToMissing (base SimpleDelegator class has this method)
39
+ def method_missing(name, *args, &block)
40
+ super(name, *args, &block).tap do
41
+ self.class.def_delegator :__getobj__, name
42
+ end
43
+ end
44
+ # rubocop:enable Style/MissingRespondToMissing
45
+ end
46
+
47
+ extend Forwardable
48
+ extend Jat::JatClass
49
+ include InstanceMethods
50
+ end
51
+
52
+ module ClassMethods
53
+ def inherited(subclass)
54
+ presenter_class = Class.new(self::Presenter)
55
+ presenter_class.jat_class = subclass
56
+ subclass.const_set(:Presenter, presenter_class)
57
+
58
+ super
59
+ end
60
+
61
+ def attribute(name, **opts, &block)
62
+ # Define attr_accessor in presenter automatically
63
+ super.tap do |attribute|
64
+ self::Presenter.def_delegator(:__getobj__, attribute.key) unless attribute.params[:block]
65
+ end
66
+ end
67
+ end
68
+
69
+ module ResponsePieceInstanceMethods
70
+ def initialize(*)
71
+ super
72
+ @object = jat_class::Presenter.new(object)
73
+ end
74
+ end
75
+ end
76
+
77
+ register_plugin(Presenter.plugin_name, Presenter)
78
+ end
79
+ end
@@ -5,20 +5,10 @@ class Jat
5
5
  module SimpleApi
6
6
  class FieldsParamParser
7
7
  module ClassMethods
8
- # Returns the Jat class that this FieldsParamParser class is namespaced under.
9
- attr_accessor :jat_class
10
-
11
- # Since FieldsParamParser is anonymously subclassed when Jat is subclassed,
12
- # and then assigned to a constant of the Jat subclass, make inspect
13
- # reflect the likely name for the class.
14
- def inspect
15
- "#{jat_class.inspect}::FieldsParamParser"
16
- end
17
-
18
8
  def parse(fields)
19
9
  return FROZEN_EMPTY_HASH unless fields
20
10
 
21
- new(fields).parse
11
+ new.parse(fields)
22
12
  end
23
13
  end
24
14
 
@@ -27,68 +17,53 @@ class Jat
27
17
  OPEN_BRACKET = "("
28
18
  CLOSE_BRACKET = ")"
29
19
 
30
- def initialize(fields)
31
- @fields = fields
32
- end
33
-
34
20
  # user => { user: {} }
35
21
  # user(id) => { user: { id: {} } }
36
22
  # user(id,name) => { user: { id: {}, name: {} } }
37
23
  # user,comments => { user: {}, comments: {} }
38
24
  # user(comments(text)) => { user: { comments: { text: {} } } }
39
- def parse
40
- current_attr = nil
25
+ def parse(fields)
26
+ res = {}
27
+ attribute = +""
28
+ path_stack = nil
41
29
 
42
30
  fields.each_char do |char|
43
31
  case char
44
32
  when COMMA
45
- next unless current_attr
46
-
47
- add_attribute(current_attr)
48
- current_attr = nil
33
+ add_attribute(res, path_stack, attribute, FROZEN_EMPTY_HASH)
49
34
  when CLOSE_BRACKET
50
- if current_attr
51
- add_attribute(current_attr)
52
- current_attr = nil
53
- end
54
-
55
- route.pop
35
+ add_attribute(res, path_stack, attribute, FROZEN_EMPTY_HASH)
36
+ path_stack&.pop
56
37
  when OPEN_BRACKET
57
- next unless current_attr
58
-
59
- attribute_name = add_attribute(current_attr, {})
60
- route << attribute_name
61
- current_attr = nil
38
+ name = add_attribute(res, path_stack, attribute, {})
39
+ (path_stack ||= []).push(name) if name
62
40
  else
63
- current_attr = current_attr ? current_attr.insert(-1, char) : char
41
+ attribute.insert(-1, char)
64
42
  end
65
43
  end
66
44
 
67
- add_attribute(current_attr) if current_attr
45
+ add_attribute(res, path_stack, attribute, FROZEN_EMPTY_HASH)
68
46
 
69
47
  res
70
48
  end
71
49
 
72
50
  private
73
51
 
74
- attr_reader :fields
52
+ def add_attribute(res, path_stack, attribute, nested_attributes = FROZEN_EMPTY_HASH)
53
+ attribute.strip!
54
+ return if attribute.empty?
75
55
 
76
- def add_attribute(current_attr, nested_attrs = FROZEN_EMPTY_HASH)
77
- current_resource = route.empty? ? res : res.dig(*route)
78
- attribute_name = current_attr.strip.to_sym
79
- current_resource[attribute_name] = nested_attrs
80
- attribute_name
81
- end
56
+ name = attribute.to_sym
57
+ attribute.clear
82
58
 
83
- def res
84
- @res ||= {}
85
- end
59
+ current_attrs = !path_stack || path_stack.empty? ? res : res.dig(*path_stack)
60
+ current_attrs[name] = nested_attributes
86
61
 
87
- def route
88
- @route ||= []
62
+ name
89
63
  end
90
64
  end
91
65
 
66
+ extend Jat::JatClass
92
67
  extend ClassMethods
93
68
  include InstanceMethods
94
69
  end