jat 0.0.3 → 0.0.8

Sign up to get free protection for your applications and to get access to all the features.
Files changed (131) hide show
  1. checksums.yaml +4 -4
  2. data/lib/jat/attribute.rb +26 -5
  3. data/lib/jat/config.rb +4 -7
  4. data/lib/jat/plugins/activerecord/activerecord.rb +23 -0
  5. data/lib/jat/plugins/base/base_activerecord_preloads/base_activerecord_preloads.rb +38 -0
  6. data/lib/jat/plugins/{_activerecord_preloads → base/base_activerecord_preloads}/lib/preloader.rb +22 -16
  7. data/lib/jat/plugins/base/base_lower_camel_case/base_lower_camel_case.rb +36 -0
  8. data/lib/jat/plugins/{_preloads/_preloads.rb → base/base_preloads/base_preloads.rb} +14 -4
  9. data/lib/jat/plugins/{_preloads → base/base_preloads}/lib/format_user_preloads.rb +1 -1
  10. data/lib/jat/plugins/{_preloads → base/base_preloads}/lib/preloads_with_path.rb +1 -1
  11. data/lib/jat/plugins/cache/cache.rb +14 -6
  12. data/lib/jat/plugins/json_api/json_api.rb +150 -106
  13. data/lib/jat/plugins/json_api/lib/fields_param_parser.rb +40 -0
  14. data/lib/jat/plugins/json_api/lib/include_param_parser.rb +84 -0
  15. data/lib/jat/plugins/json_api/lib/map.rb +92 -27
  16. data/lib/jat/plugins/json_api/lib/params/fields/validate.rb +8 -5
  17. data/lib/jat/plugins/json_api/lib/response.rb +81 -197
  18. data/lib/jat/plugins/json_api/lib/response_piece.rb +175 -0
  19. data/lib/jat/plugins/json_api/plugins/json_api_activerecord/json_api_activerecord.rb +23 -0
  20. data/lib/jat/plugins/json_api/plugins/json_api_lower_camel_case/json_api_lower_camel_case.rb +34 -0
  21. data/lib/jat/plugins/json_api/plugins/json_api_maps_cache/json_api_maps_cache.rb +58 -0
  22. data/lib/jat/plugins/json_api/plugins/json_api_preloads/json_api_preloads.rb +38 -0
  23. data/lib/jat/plugins/{_json_api_activerecord → json_api/plugins/json_api_preloads}/lib/preloads.rb +17 -25
  24. data/lib/jat/plugins/json_api/plugins/json_api_validate_params/json_api_validate_params.rb +61 -0
  25. data/lib/jat/plugins/json_api/plugins/json_api_validate_params/lib/params_error.rb +6 -0
  26. data/lib/jat/plugins/json_api/plugins/json_api_validate_params/lib/validate_fields_param.rb +59 -0
  27. data/lib/jat/plugins/json_api/plugins/json_api_validate_params/lib/validate_include_param.rb +33 -0
  28. data/lib/jat/plugins/lower_camel_case/lower_camel_case.rb +23 -0
  29. data/lib/jat/plugins/maps_cache/maps_cache.rb +23 -0
  30. data/lib/jat/plugins/preloads/preloads.rb +23 -0
  31. data/lib/jat/plugins/simple_api/lib/fields_param_parser.rb +97 -0
  32. data/lib/jat/plugins/simple_api/lib/map.rb +80 -10
  33. data/lib/jat/plugins/simple_api/lib/response.rb +75 -90
  34. data/lib/jat/plugins/simple_api/lib/response_piece.rb +80 -0
  35. data/lib/jat/plugins/simple_api/plugins/simple_api_activerecord/simple_api_activerecord.rb +23 -0
  36. data/lib/jat/plugins/simple_api/plugins/simple_api_lower_camel_case/simple_api_lower_camel_case.rb +34 -0
  37. data/lib/jat/plugins/simple_api/plugins/simple_api_maps_cache/simple_api_maps_cache.rb +50 -0
  38. data/lib/jat/plugins/simple_api/plugins/simple_api_preloads/lib/preloads.rb +55 -0
  39. data/lib/jat/plugins/simple_api/plugins/simple_api_preloads/simple_api_preloads.rb +38 -0
  40. data/lib/jat/plugins/simple_api/plugins/simple_api_validate_params/lib/fields_error.rb +6 -0
  41. data/lib/jat/plugins/simple_api/plugins/simple_api_validate_params/lib/validate_fields_param.rb +45 -0
  42. data/lib/jat/plugins/simple_api/plugins/simple_api_validate_params/simple_api_validate_params.rb +49 -0
  43. data/lib/jat/plugins/simple_api/simple_api.rb +87 -27
  44. data/lib/jat/plugins/to_str/to_str.rb +15 -5
  45. data/lib/jat/plugins/types/types.rb +54 -0
  46. data/lib/jat/plugins/validate_params/validate_params.rb +23 -0
  47. data/lib/jat/plugins.rb +42 -30
  48. data/lib/jat.rb +40 -35
  49. data/test/lib/jat/attribute_test.rb +22 -4
  50. data/test/lib/jat/plugins/activerecord/activerecord_test.rb +27 -0
  51. data/test/lib/jat/plugins/base_activerecord_preloads/base_activerecord_preloads_test.rb +59 -0
  52. data/test/lib/jat/plugins/{_activerecord_preloads → base_activerecord_preloads}/lib/preloader_test.rb +11 -25
  53. data/test/lib/jat/plugins/base_lower_camel_case/base_lower_camel_case_test.rb +26 -0
  54. data/test/lib/jat/plugins/{_preloads/_preloads_test.rb → base_preloads/base_preloads_test.rb} +2 -2
  55. data/test/lib/jat/plugins/{_preloads → base_preloads}/lib/format_user_preloads_test.rb +3 -3
  56. data/test/lib/jat/plugins/{_preloads → base_preloads}/lib/preloads_with_path_test.rb +2 -2
  57. data/test/lib/jat/plugins/cache/cache_test.rb +11 -11
  58. data/test/lib/jat/plugins/json_api/json_api_test.rb +57 -49
  59. data/test/lib/jat/plugins/json_api/lib/fields_param_parser_test.rb +46 -0
  60. data/test/lib/jat/plugins/json_api/lib/include_param_parser_test.rb +57 -0
  61. data/test/lib/jat/plugins/json_api/lib/map_test.rb +171 -92
  62. data/test/lib/jat/plugins/json_api/lib/response_piece_test.rb +13 -0
  63. data/test/lib/jat/plugins/json_api/lib/response_test.rb +38 -32
  64. data/test/lib/jat/plugins/json_api_activerecord/json_api_activerecord_test.rb +24 -0
  65. data/test/lib/jat/plugins/json_api_lower_camel_case/json_api_lower_camel_case_test.rb +85 -0
  66. data/test/lib/jat/plugins/json_api_maps_cache/json_api_maps_cache_test.rb +107 -0
  67. data/test/lib/jat/plugins/json_api_preloads/json_api_preloads_test.rb +51 -0
  68. data/test/lib/jat/plugins/{_json_api_activerecord → json_api_preloads}/lib/preloads_test.rb +19 -13
  69. data/test/lib/jat/plugins/json_api_validate_params/json_api_validate_params_test.rb +108 -0
  70. data/test/lib/jat/plugins/lower_camel_case/lower_camel_case_test.rb +27 -0
  71. data/test/lib/jat/plugins/maps_cache/maps_cache_test.rb +27 -0
  72. data/test/lib/jat/plugins/preloads/preloads_test.rb +27 -0
  73. data/test/lib/jat/plugins/simple_api/lib/fields_param_parser_test.rb +87 -0
  74. data/test/lib/jat/plugins/simple_api/lib/map_test.rb +118 -33
  75. data/test/lib/jat/plugins/simple_api/lib/response_piece_test.rb +13 -0
  76. data/test/lib/jat/plugins/simple_api/lib/response_test.rb +90 -76
  77. data/test/lib/jat/plugins/simple_api/simple_api_test.rb +118 -25
  78. data/test/lib/jat/plugins/simple_api_activerecord/simple_api_activerecord_test.rb +24 -0
  79. data/test/lib/jat/plugins/simple_api_lower_camel_case/simple_api_lower_camel_case_test.rb +54 -0
  80. data/test/lib/jat/plugins/simple_api_maps_cache/simple_api_maps_cache_test.rb +95 -0
  81. data/test/lib/jat/plugins/simple_api_preloads/lib/preloads_test.rb +140 -0
  82. data/test/lib/jat/plugins/simple_api_preloads/simple_api_preloads_test.rb +51 -0
  83. data/test/lib/jat/plugins/simple_api_validate_params/simple_api_validate_params_test.rb +101 -0
  84. data/test/lib/jat/plugins/to_str/to_str_test.rb +3 -3
  85. data/test/lib/jat/plugins/types/types_test.rb +84 -0
  86. data/test/lib/jat/plugins/validate_params/validate_params_test.rb +27 -0
  87. data/test/lib/jat/plugins_test.rb +88 -0
  88. data/test/lib/jat_test.rb +47 -24
  89. data/test/lib/plugin_test.rb +3 -3
  90. data/test/test_helper.rb +7 -6
  91. data/test/test_plugin.rb +9 -12
  92. metadata +107 -88
  93. data/CHANGELOG.md +0 -7
  94. data/README.md +0 -21
  95. data/jat.gemspec +0 -37
  96. data/lib/jat/plugins/_activerecord_preloads/_activerecord_preloads.rb +0 -29
  97. data/lib/jat/plugins/_json_api_activerecord/_json_api_activerecord.rb +0 -22
  98. data/lib/jat/plugins/camel_lower/camel_lower.rb +0 -18
  99. data/lib/jat/plugins/json_api/lib/construct_traversal_map.rb +0 -91
  100. data/lib/jat/plugins/json_api/lib/presenters/document_links_presenter.rb +0 -48
  101. data/lib/jat/plugins/json_api/lib/presenters/document_meta_presenter.rb +0 -48
  102. data/lib/jat/plugins/json_api/lib/presenters/jsonapi_presenter.rb +0 -48
  103. data/lib/jat/plugins/json_api/lib/presenters/links_presenter.rb +0 -48
  104. data/lib/jat/plugins/json_api/lib/presenters/meta_presenter.rb +0 -48
  105. data/lib/jat/plugins/json_api/lib/presenters/relationship_links_presenter.rb +0 -53
  106. data/lib/jat/plugins/json_api/lib/presenters/relationship_meta_presenter.rb +0 -53
  107. data/lib/jat/plugins/json_api/lib/traversal_map.rb +0 -34
  108. data/lib/jat/plugins/simple_api/lib/construct_traversal_map.rb +0 -45
  109. data/lib/jat/plugins/simple_api/lib/params/parse.rb +0 -68
  110. data/lib/jat/presenter.rb +0 -51
  111. data/test/lib/jat/plugins/_activerecord_preloads/_activerecord_preloads_test.rb +0 -40
  112. data/test/lib/jat/plugins/_json_api_activerecord/_json_api_activerecord_test.rb +0 -29
  113. data/test/lib/jat/plugins/camel_lower/camel_lower_test.rb +0 -78
  114. data/test/lib/jat/plugins/json_api/lib/construct_traversal_map_test.rb +0 -119
  115. data/test/lib/jat/plugins/json_api/lib/params/fields/parse_test.rb +0 -24
  116. data/test/lib/jat/plugins/json_api/lib/params/fields/validate_test.rb +0 -47
  117. data/test/lib/jat/plugins/json_api/lib/params/fields_test.rb +0 -37
  118. data/test/lib/jat/plugins/json_api/lib/params/include/parse_test.rb +0 -46
  119. data/test/lib/jat/plugins/json_api/lib/params/include/validate_test.rb +0 -51
  120. data/test/lib/jat/plugins/json_api/lib/params/include_test.rb +0 -41
  121. data/test/lib/jat/plugins/json_api/lib/presenters/document_links_presenter_test.rb +0 -69
  122. data/test/lib/jat/plugins/json_api/lib/presenters/document_meta_presenter_test.rb +0 -69
  123. data/test/lib/jat/plugins/json_api/lib/presenters/jsonapi_presenter_test.rb +0 -69
  124. data/test/lib/jat/plugins/json_api/lib/presenters/links_presenter_test.rb +0 -69
  125. data/test/lib/jat/plugins/json_api/lib/presenters/meta_presenter_test.rb +0 -69
  126. data/test/lib/jat/plugins/json_api/lib/presenters/relationship_links_presenter_test.rb +0 -75
  127. data/test/lib/jat/plugins/json_api/lib/presenters/relationship_meta_presenter_test.rb +0 -75
  128. data/test/lib/jat/plugins/json_api/lib/traversal_map_test.rb +0 -58
  129. data/test/lib/jat/plugins/simple_api/lib/construct_traversal_map_test.rb +0 -100
  130. data/test/lib/jat/plugins/simple_api/lib/params/parse_test.rb +0 -71
  131. data/test/lib/jat/presenter_test.rb +0 -61
@@ -1,65 +1,125 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative "./lib/fields_param_parser"
3
4
  require_relative "./lib/map"
4
5
  require_relative "./lib/response"
6
+ require_relative "./lib/response_piece"
5
7
 
6
- # Serializes to JSON-API format
7
8
  class Jat
8
9
  module Plugins
9
10
  module SimpleApi
10
- DEFAULT_META_KEY = :meta
11
+ def self.plugin_name
12
+ :simple_api
13
+ end
14
+
15
+ def self.before_load(jat_class, **_opts)
16
+ response_plugin = jat_class.config[:response_plugin_loaded]
17
+ return unless response_plugin
18
+
19
+ raise Error, "Response plugin `#{response_plugin}` was already loaded before"
20
+ end
21
+
22
+ def self.load(jat_class, **_opts)
23
+ jat_class.include(InstanceMethods)
24
+ jat_class.extend(ClassMethods)
25
+ end
26
+
27
+ def self.after_load(jat_class, **_opts)
28
+ jat_class.config[:response_plugin_loaded] = plugin_name
29
+
30
+ jat_class.meta_key(:meta)
31
+
32
+ fields_parser_class = Class.new(FieldsParamParser)
33
+ fields_parser_class.jat_class = jat_class
34
+ jat_class.const_set(:FieldsParamParser, fields_parser_class)
35
+
36
+ map_class = Class.new(Map)
37
+ map_class.jat_class = jat_class
38
+ jat_class.const_set(:Map, map_class)
39
+
40
+ response_class = Class.new(Response)
41
+ response_class.jat_class = jat_class
42
+ jat_class.const_set(:Response, response_class)
11
43
 
12
- def self.after_load(jat_class, **opts)
13
- jat_class.plugin(:_json_api_activerecord, **opts) if opts[:activerecord]
44
+ response_piece_class = Class.new(ResponsePiece)
45
+ response_piece_class.jat_class = jat_class
46
+ jat_class.const_set(:ResponsePiece, response_piece_class)
14
47
  end
15
48
 
16
49
  module InstanceMethods
17
- def to_h
18
- Response.new(self).response
50
+ def to_h(object)
51
+ self.class::Response.call(object, context)
19
52
  end
20
53
 
21
- def traversal_map
22
- @traversal_map ||= Map.call(self)
54
+ def map
55
+ @map ||= self.class.map(context)
23
56
  end
24
57
  end
25
58
 
26
59
  module ClassMethods
27
60
  def inherited(subclass)
28
- subclass.root(@root) if defined?(@root)
29
-
30
61
  super
62
+
63
+ fields_parser_class = Class.new(self::FieldsParamParser)
64
+ fields_parser_class.jat_class = subclass
65
+ subclass.const_set(:FieldsParamParser, fields_parser_class)
66
+
67
+ map_class = Class.new(self::Map)
68
+ map_class.jat_class = subclass
69
+ subclass.const_set(:Map, map_class)
70
+
71
+ response_class = Class.new(self::Response)
72
+ response_class.jat_class = subclass
73
+ subclass.const_set(:Response, response_class)
74
+
75
+ response_piece_class = Class.new(self::ResponsePiece)
76
+ response_piece_class.jat_class = subclass
77
+ subclass.const_set(:ResponsePiece, response_piece_class)
78
+
79
+ # Assign same meta
80
+ added_meta.each_value do |attribute|
81
+ params = attribute.params
82
+ subclass.meta(params[:name], **params[:opts], &params[:block])
83
+ end
31
84
  end
32
85
 
33
- def root(new_root = nil)
34
- return (defined?(@root) && @root) unless new_root
86
+ def root(default = nil, one: nil, many: nil)
87
+ root_one = one || default
88
+ root_many = many || default
89
+
90
+ config[:root_one] = root_one ? root_one.to_sym : nil
91
+ config[:root_many] = root_many ? root_many.to_sym : nil
35
92
 
36
- new_root = new_root.to_sym
37
- @root = new_root
93
+ {root_one: root_one, root_many: root_many}
38
94
  end
39
95
 
40
- def root_for_one(new_root_for_one = nil)
41
- return (defined?(@root_for_one) && @root_for_one) unless new_root_for_one
96
+ def meta_key(new_meta_key)
97
+ config[:meta_key] = new_meta_key.to_sym
98
+ end
42
99
 
43
- new_root_for_one = new_root_for_one.to_sym
44
- @root_for_one = new_root_for_one
100
+ def added_meta
101
+ @added_meta ||= {}
45
102
  end
46
103
 
47
- def root_for_many(new_root_for_many = nil)
48
- return (defined?(@root_for_many) && @root_for_many) unless new_root_for_many
104
+ def meta(name, **opts, &block)
105
+ new_attr = self::Attribute.new(name: name, opts: opts, block: block)
106
+ added_meta[new_attr.name] = new_attr
107
+ end
49
108
 
50
- new_root_for_many = new_root_for_many.to_sym
51
- @root_for_many = new_root_for_many
109
+ def map(context)
110
+ self::Map.call(context)
52
111
  end
53
112
 
54
- def meta_key(new_meta_key = nil)
55
- return ((defined?(@meta_key) && @meta_key) || DEFAULT_META_KEY) unless new_meta_key
113
+ def map_full
114
+ @map_full ||= self::Map.call(exposed: :all)
115
+ end
56
116
 
57
- new_meta_key = new_meta_key.to_sym
58
- @meta_key = new_meta_key
117
+ def map_exposed
118
+ @map_exposed ||= self::Map.call(exposed: :default)
59
119
  end
60
120
  end
61
121
  end
62
122
 
63
- register_plugin(:simple_api, SimpleApi)
123
+ register_plugin(SimpleApi.plugin_name, SimpleApi)
64
124
  end
65
125
  end
@@ -3,19 +3,29 @@
3
3
  class Jat
4
4
  module Plugins
5
5
  module ToStr
6
+ def self.plugin_name
7
+ :to_str
8
+ end
9
+
10
+ def self.load(jat_class, **_opts)
11
+ jat_class.include(InstanceMethods)
12
+ jat_class.extend(ClassMethods)
13
+ end
14
+
6
15
  def self.after_load(jat_class, **opts)
7
16
  jat_class.config[:to_str] = opts[:to_str] || ->(data) { ToStrJSON.dump(data) }
8
17
  end
9
18
 
10
19
  module ClassMethods
11
- def to_str(object, context = {})
12
- new(object, context).to_str
20
+ def to_str(object, context = nil)
21
+ new(context || FROZEN_EMPTY_HASH).to_str(object)
13
22
  end
14
23
  end
15
24
 
16
25
  module InstanceMethods
17
- def to_str
18
- config[:to_str].call(to_h)
26
+ def to_str(object)
27
+ hash = to_h(object)
28
+ config[:to_str].call(hash)
19
29
  end
20
30
  end
21
31
 
@@ -39,6 +49,6 @@ class Jat
39
49
  end
40
50
  end
41
51
 
42
- register_plugin(:to_str, ToStr)
52
+ register_plugin(ToStr.plugin_name, ToStr)
43
53
  end
44
54
  end
@@ -0,0 +1,54 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Jat
4
+ module Plugins
5
+ module Types
6
+ def self.plugin_name
7
+ :types
8
+ end
9
+
10
+ def self.load(jat_class, **_opts)
11
+ jat_class::Attribute.include(InstanceMethods)
12
+ end
13
+
14
+ def self.after_load(jat_class, **_opts)
15
+ jat_class.config[:types] = {
16
+ array: ->(value) { Array(value) },
17
+ bool: ->(value) { !!value },
18
+ float: ->(value) { Float(value) },
19
+ hash: ->(value) { Hash(value) },
20
+ int: ->(value) { Integer(value) },
21
+ str: ->(value) { String(value) }
22
+ }
23
+ end
24
+
25
+ module InstanceMethods
26
+ def block
27
+ return @block if instance_variable_defined?(:@block)
28
+
29
+ original_block = super
30
+ type = opts[:type]
31
+ return original_block unless type
32
+
33
+ @block = typed_block(type, original_block)
34
+ end
35
+
36
+ private
37
+
38
+ def typed_block(type, original_block)
39
+ proc do |object, context|
40
+ value = original_block.call(object, context)
41
+
42
+ # Type conversion
43
+ case type
44
+ when Symbol then self.class.jat_class.config.fetch(:types).fetch(type).call(value)
45
+ else type.call(value)
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
51
+
52
+ register_plugin(Types.plugin_name, Types)
53
+ end
54
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Jat
4
+ module Plugins
5
+ module ValidateParams
6
+ def self.plugin_name
7
+ :validate_params
8
+ end
9
+
10
+ def self.load(jat_class, **opts)
11
+ if jat_class.plugin_used?(:json_api)
12
+ jat_class.plugin :json_api_validate_params, **opts
13
+ elsif jat_class.plugin_used?(:simple_api)
14
+ jat_class.plugin :simple_api_validate_params, **opts
15
+ else
16
+ raise Error, "Please load :json_api or :simple_api plugin first"
17
+ end
18
+ end
19
+ end
20
+
21
+ register_plugin(ValidateParams.plugin_name, ValidateParams)
22
+ end
23
+ end
data/lib/jat/plugins.rb CHANGED
@@ -1,39 +1,51 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class Jat
4
+ class PluginLoadError < Error; end
5
+
4
6
  module Plugins
5
7
  @plugins = {}
6
8
 
7
- # Register the given plugin with Jat, so that it can be loaded using
8
- # `Jat.plugin` with a symbol. Should be used by plugin files. Example:
9
- #
10
- # Jat::Plugins.register_plugin(:plugin_name, PluginModule)
11
- def self.register_plugin(name, mod)
12
- @plugins[name] = mod
13
- end
14
-
15
- # If the registered plugin already exists, use it. Otherwise, require it
16
- # and return it. This raises a LoadError if such a plugin doesn't exist,
17
- # or a Jat::Error if it exists but it does not register itself
18
- # correctly.
19
- def self.load_plugin(name)
20
- require "jat/plugins/#{name}/#{name}" unless @plugins.key?(name)
21
-
22
- @plugins[name] || raise(Error, "plugin #{name} did not register itself correctly in Jat::Plugins")
23
- end
24
-
25
- # Delegate call to the plugin in a way that works across Ruby versions.
26
- def self.before_load(plugin, jat_class, **opts)
27
- return unless plugin.respond_to?(:before_load)
28
-
29
- plugin.before_load(jat_class, **opts)
30
- end
31
-
32
- # Delegate call to the plugin in a way that works across Ruby versions.
33
- def self.after_load(plugin, jat_class, **opts)
34
- return unless plugin.respond_to?(:after_load)
35
-
36
- plugin.after_load(jat_class, **opts)
9
+ class << self
10
+ # Registers given plugin to be able to load it using symbol name.
11
+ #
12
+ # Example: Jat::Plugins.register_plugin(:plugin_name, PluginModule)
13
+ def register_plugin(name, mod)
14
+ @plugins[name] = mod
15
+ end
16
+
17
+ # If the registered plugin already exists, use it. Otherwise, require
18
+ # and return it. This raises a LoadError if such a plugin doesn't exist,
19
+ # or a Jat::Error if it exists but it does not register itself
20
+ # correctly.
21
+ def find_plugin(name)
22
+ return name if name.is_a?(Module)
23
+ return @plugins[name] if @plugins.key?(name)
24
+
25
+ begin
26
+ require_plugin(name)
27
+ rescue PluginLoadError
28
+ if name.start_with?("json_api")
29
+ require_plugin(name, "/json_api/plugins")
30
+ elsif name.start_with?("simple_api")
31
+ require_plugin(name, "/simple_api/plugins")
32
+ elsif name.start_with?("base")
33
+ require_plugin(name, "/base")
34
+ else
35
+ raise
36
+ end
37
+ end
38
+
39
+ @plugins[name] || raise(PluginLoadError, "Plugin '#{name}' did not register itself correctly")
40
+ end
41
+
42
+ private
43
+
44
+ def require_plugin(name, prefix = nil)
45
+ require "jat/plugins#{prefix}/#{name}/#{name}"
46
+ rescue LoadError
47
+ raise PluginLoadError, "Plugin '#{name}' does not exist"
48
+ end
37
49
  end
38
50
  end
39
51
  end
data/lib/jat.rb CHANGED
@@ -1,16 +1,20 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative "jat/attribute"
4
- require_relative "jat/presenter"
5
- require_relative "jat/config"
6
- require_relative "jat/plugins"
7
-
8
3
  # Main namespace
9
4
  class Jat
10
5
  # A generic exception used by Jat.
11
6
  class Error < StandardError; end
12
7
 
13
- @config = Config.new
8
+ FROZEN_EMPTY_HASH = {}.freeze
9
+ FROZEN_EMPTY_ARRAY = [].freeze
10
+ end
11
+
12
+ require_relative "jat/attribute"
13
+ require_relative "jat/config"
14
+ require_relative "jat/plugins"
15
+
16
+ class Jat
17
+ @config = Config.new({plugins: []})
14
18
 
15
19
  module ClassMethods
16
20
  attr_reader :config
@@ -27,11 +31,6 @@ class Jat
27
31
  attribute_class.jat_class = subclass
28
32
  subclass.const_set(:Attribute, attribute_class)
29
33
 
30
- # Initialize object presenter
31
- presenter_class = Class.new(self::Presenter)
32
- presenter_class.jat_class = subclass
33
- subclass.const_set(:Presenter, presenter_class)
34
-
35
34
  # Assign same attributes
36
35
  attributes.each_value do |attribute|
37
36
  params = attribute.params
@@ -41,29 +40,34 @@ class Jat
41
40
  super
42
41
  end
43
42
 
44
- def plugin(plugin, **opts)
45
- if !plugin.is_a?(Symbol) && !plugin.is_a?(Module)
46
- raise Error, "Plugin class must be a Symbol or a Module, #{plugin.inspect} given"
47
- end
43
+ def plugin(name, **opts)
44
+ return if plugin_used?(name)
48
45
 
49
- plugin = Plugins.load_plugin(plugin) if plugin.is_a?(Symbol)
46
+ plugin = Plugins.find_plugin(name)
50
47
 
51
- Plugins.before_load(plugin, self, **opts)
48
+ # We split loading of plugin to three methods - before_load, load, after_load:
49
+ #
50
+ # - **before_load** usually used to check requirements and to load additional plugins
51
+ # - **load** usually used to include plugin modules
52
+ # - **after_load** usually used to add config options
53
+ plugin.before_load(self, **opts) if plugin.respond_to?(:before_load)
54
+ plugin.load(self, **opts) if plugin.respond_to?(:load)
55
+ plugin.after_load(self, **opts) if plugin.respond_to?(:after_load)
52
56
 
53
- include(plugin::InstanceMethods) if defined?(plugin::InstanceMethods)
54
- extend(plugin::ClassMethods) if defined?(plugin::ClassMethods)
57
+ # Store attached plugins, so we can check it is loaded later
58
+ config[:plugins] << (plugin.respond_to?(:plugin_name) ? plugin.plugin_name : plugin)
55
59
 
56
- self::Attribute.include plugin::AttributeMethods if defined?(plugin::AttributeMethods)
57
- self::Attribute.extend plugin::AttributeClassMethods if defined?(plugin::AttributeClassMethods)
58
-
59
- self::Config.include plugin::ConfigMethods if defined?(plugin::ConfigMethods)
60
- self::Config.extend plugin::ConfigClassMethods if defined?(plugin::ConfigClassMethods)
60
+ plugin
61
+ end
61
62
 
62
- self::Presenter.include plugin::PresenterMethods if defined?(plugin::PresenterMethods)
63
- self::Presenter.extend plugin::PresenterClassMethods if defined?(plugin::PresenterClassMethods)
63
+ def plugin_used?(plugin)
64
+ plugin_name =
65
+ case plugin
66
+ when Module then plugin.respond_to?(:plugin_name) ? plugin.plugin_name : plugin
67
+ else plugin
68
+ end
64
69
 
65
- Plugins.after_load(plugin, self, **opts)
66
- plugin
70
+ config[:plugins].include?(plugin_name)
67
71
  end
68
72
 
69
73
  def call
@@ -71,7 +75,7 @@ class Jat
71
75
  end
72
76
 
73
77
  def to_h(object, context = nil)
74
- new(object, context || {}).to_h
78
+ new(context || {}).to_h(object)
75
79
  end
76
80
 
77
81
  def attributes
@@ -81,20 +85,21 @@ class Jat
81
85
  def attribute(name, **opts, &block)
82
86
  new_attr = self::Attribute.new(name: name, opts: opts, block: block)
83
87
  attributes[new_attr.name] = new_attr
84
- self::Presenter.add_method(new_attr.original_name, new_attr.block)
85
- new_attr
88
+ end
89
+
90
+ def relationship(name, serializer:, **opts, &block)
91
+ attribute(name, serializer: serializer, **opts, &block)
86
92
  end
87
93
  end
88
94
 
89
95
  module InstanceMethods
90
- attr_reader :object, :context
96
+ attr_reader :context
91
97
 
92
- def initialize(object, context)
93
- @object = object
98
+ def initialize(context = {})
94
99
  @context = context
95
100
  end
96
101
 
97
- def to_h
102
+ def to_h(_object)
98
103
  raise Error, "Method #to_h must be implemented by plugin"
99
104
  end
100
105
 
@@ -127,16 +127,34 @@ describe Jat::Attribute do
127
127
 
128
128
  describe "#block" do
129
129
  it "returns provided block" do
130
- block = -> {}
130
+ block = proc { |object, context| [object, context] }
131
131
  attribute = attribute_class.new(name: "foo", block: block)
132
- assert_equal block, attribute.block
132
+ assert_equal ["OBJECT", "CONTEXT"], attribute.value("OBJECT", "CONTEXT")
133
+ end
134
+
135
+ it "returns provided block when block was without params" do
136
+ block = proc { "RESULT" }
137
+ attribute = attribute_class.new(name: "foo", block: block)
138
+ assert_equal "RESULT", attribute.value("OBJECT", "CONTEXT")
139
+ end
140
+
141
+ it "returns provided block when block was with one param" do
142
+ block = proc { |object| object }
143
+ attribute = attribute_class.new(name: "foo", block: block)
144
+ assert_equal "OBJECT", attribute.value("OBJECT", "CONTEXT")
133
145
  end
134
146
 
135
147
  it "constructs block that calls current key method on object" do
136
148
  attribute = attribute_class.new(name: "foo", opts: {key: :length})
137
- presenter = jat_class::Presenter.new([1, 2, 3], {})
149
+ assert_equal 3, attribute.value([1, 2, 3], nil)
150
+ end
138
151
 
139
- assert_equal 3, presenter.instance_exec(&attribute.block)
152
+ it "raises error if provide block with more than 2 params" do
153
+ jat_class.attribute(:foo) {}
154
+ jat_class.attribute(:foo) { |_| }
155
+ jat_class.attribute(:foo) { |_, _| }
156
+ err = assert_raises(Jat::Error) { jat_class.attribute(:foo) { |_, _, _| } }
157
+ assert_equal "Block can have 0-2 parameters", err.message
140
158
  end
141
159
  end
142
160
  end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "test_helper"
4
+
5
+ describe "Jat::Plugins::Activerecord" do
6
+ it "raises error if no response plugin is loaded" do
7
+ new_class = Class.new(Jat)
8
+ err = assert_raises(Jat::Error) { new_class.plugin :activerecord }
9
+ assert_equal "Please load :json_api or :simple_api plugin first", err.message
10
+ end
11
+
12
+ it "loads simple_api compatible plugin" do
13
+ new_class = Class.new(Jat)
14
+ new_class.plugin :simple_api
15
+ new_class.plugin :activerecord
16
+
17
+ assert new_class.plugin_used?(:simple_api_activerecord)
18
+ end
19
+
20
+ it "loads json_api compatible plugin" do
21
+ new_class = Class.new(Jat)
22
+ new_class.plugin :json_api
23
+ new_class.plugin :activerecord
24
+
25
+ assert new_class.plugin_used?(:json_api_activerecord)
26
+ end
27
+ end
@@ -0,0 +1,59 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "test_helper"
4
+
5
+ describe "Jat::Plugins::BaseActiverecordPreloads" do
6
+ let(:jat_class) do
7
+ api_test = api_test()
8
+
9
+ Class.new(Jat) do
10
+ include api_test
11
+ plugin(:base_activerecord_preloads)
12
+ end
13
+ end
14
+
15
+ let(:api_test) do
16
+ Module.new do
17
+ def to_h(object)
18
+ object
19
+ end
20
+ end
21
+ end
22
+
23
+ describe "InstanceMethods" do
24
+ it "adds preloads to object when calling to_h" do
25
+ object = "OBJ"
26
+ preloads = "PRELOADS"
27
+ jat = jat_class.new
28
+ jat.expects(:preloads).returns(preloads)
29
+
30
+ Jat::Plugins::BaseActiverecordPreloads::Preloader
31
+ .expects(:preload)
32
+ .with(object, preloads).returns("OBJ_WITH_PRELOADS")
33
+
34
+ assert_equal("OBJ_WITH_PRELOADS", jat.to_h(object))
35
+ end
36
+
37
+ it "skips preloadings for nil" do
38
+ object = nil
39
+ jat = jat_class.new
40
+
41
+ assert_same object, jat.to_h(object)
42
+ end
43
+
44
+ it "skips preloadings for empty array" do
45
+ object = []
46
+ jat = jat_class.new
47
+
48
+ assert_same object, jat.to_h(object)
49
+ end
50
+
51
+ it "skips preloadings when nothing to preload" do
52
+ object = "OBJECT"
53
+ jat = jat_class.new
54
+ jat.expects(:preloads).returns({})
55
+
56
+ assert_same object, jat.to_h(object)
57
+ end
58
+ end
59
+ end
@@ -4,11 +4,11 @@ require "test_helper"
4
4
  require "support/activerecord"
5
5
 
6
6
  describe "Jat::Plugins::ActiverecordPreloads" do
7
- before { Jat::Plugins.load_plugin(:_activerecord_preloads) }
7
+ before { Jat::Plugins.find_plugin(:base_activerecord_preloads) }
8
8
 
9
9
  describe "Preloader" do
10
10
  let(:described_class) { plugin::Preloader }
11
- let(:plugin) { Jat::Plugins::ActiverecordPreloads }
11
+ let(:plugin) { Jat::Plugins::BaseActiverecordPreloads }
12
12
 
13
13
  describe ".handlers" do
14
14
  it "returns memorized array of handlers" do
@@ -52,18 +52,17 @@ describe "Jat::Plugins::ActiverecordPreloads" do
52
52
  assert_equal true, user.association(:comments).loaded?
53
53
  end
54
54
 
55
- it "resets activerecord object preloaded relations" do
55
+ it "preloads data to activerecord array" do
56
56
  user = AR::User.create!
57
- comment = user.comments.create!
58
- user.comments.to_a && comment.delete # preload comments manually and delete comment
59
57
 
60
- described_class.preload(user, {comments: {}})
58
+ users = [user]
59
+ result = described_class.preload(users, {comments: {}})
61
60
 
62
- assert_equal true, user.association(:comments).loaded?
63
- assert_equal [], user.comments
61
+ assert_same result, users
62
+ assert_equal true, result[0].association(:comments).loaded?
64
63
  end
65
64
 
66
- it "preloads data to activerecord relation object" do
65
+ it "preloads data to activerecord relation" do
67
66
  user = AR::User.create!
68
67
 
69
68
  result = described_class.preload(AR::User.where(id: user.id), {comments: {}})
@@ -72,26 +71,13 @@ describe "Jat::Plugins::ActiverecordPreloads" do
72
71
  assert_equal true, result[0].association(:comments).loaded?
73
72
  end
74
73
 
75
- it "preloads data to activerecord array" do
74
+ it "preloads data to loaded activerecord relation" do
76
75
  user = AR::User.create!
77
76
 
78
- users = [user]
79
- result = described_class.preload(users, {comments: {}})
80
-
81
- assert_same result, users
82
- assert_equal true, result[0].association(:comments).loaded?
83
- end
84
-
85
- it "resets activerecord array preloaded relations" do
86
- user = AR::User.create!
87
- comment = user.comments.create!
88
- user.comments.to_a && comment.delete # preload comments manually and delete comment
89
-
90
- users = [user]
91
- result = described_class.preload(users, {comments: {}})
77
+ result = described_class.preload(AR::User.where(id: user.id).load, {comments: {}})
92
78
 
79
+ assert_equal result, [user]
93
80
  assert_equal true, result[0].association(:comments).loaded?
94
- assert_equal [], result[0].comments
95
81
  end
96
82
  end
97
83
  end