api_presenter 0.2.3 → 0.2.4

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 73dd421a335a6bd28bb1fa83bcf1142f3f72de40
4
- data.tar.gz: 8e07b111ea8ab9d0f5dbb13420113ed9d7204825
3
+ metadata.gz: 2a3e0a34d5d50f902760195ffd58a409d3231a15
4
+ data.tar.gz: 8a4261472f7ba030c7ff72e2bed5d9c3171b98d6
5
5
  SHA512:
6
- metadata.gz: f59b72c776aa0279c438cb20744d39074e9d18de3eadf9f84a7aa9e6849fe418a99e00ea8f7edd796fe3cc5c7227e34bae678e73fa1fd8917ece3abfc4373468
7
- data.tar.gz: 36c674a4aa24f8f8af48c8ed2daba2c9e6c1dc1864b25edc23175ee4fa705508a71078775a7f2ea19784a649b82e8c458f489d4a3546a8d486b2956f85fea60a
6
+ metadata.gz: 3e3491e2c26ac8affb10ba11eaeef277be47b4b9666f205a6c9f5a07da5178b204ffcc28961e10df10811abb6a98ff5cc0e0968e0d213911f07f96d1094a94fa
7
+ data.tar.gz: e426cce2a716fc7cdcb4e5066cd9b9a51509a5c339886031c27159fe0a6698c07f08f107f939cd6c0a071637bd7f4ee942f61e2876d139757f42383e157ed367
data/CHANGELOG.md CHANGED
@@ -1,3 +1,7 @@
1
+ ## 0.2.4 (2016-11-07)
2
+
3
+ Logical restructure. No API changes.
4
+
1
5
  ## 0.2.0 (2016-11-07)
2
6
 
3
7
  Fixes require statements. Note to self: don't publish a gem right before leaving for holidays.
data/lib/api_presenter.rb CHANGED
@@ -1,205 +1,10 @@
1
1
  require 'pundit'
2
+ module ApiPresenter; end
2
3
 
3
- module ApiPresenter
4
- class Base
5
-
6
- attr_reader :current_user, :params, :relation
7
-
8
- # @example
9
- # @presenter = PostPresenter.call(
10
- # current_user: current_user,
11
- # relation: relation,
12
- # params: params
13
- # )
14
- #
15
- # @param (see #initialize)
16
- #
17
- # @return [ApiPresenter::Base]
18
- #
19
- def self.call(**kwargs)
20
- new(kwargs).call
21
- end
22
-
23
- # @param current_user [User] Optional. current_user context.
24
- # @param relation [ActiveRecord::Relation, Array] Relation or array-wrapped record(s) to present
25
- # @param params [Hash] Controller params
26
- # @option params [Boolean] :count Optional. If true, return count only.
27
- # @option params [String, Array] :include Optional. Associated resources to include.
28
- # @option params [Boolean] :policies Optional. If true, resolve polciies for relation.
29
- #
30
- def initialize(current_user: nil, relation:, params: {})
31
- @current_user = current_user
32
- @relation = relation
33
- @params = params
34
- end
35
-
36
- # @return [ApiPresenter::Base]
37
- #
38
- def call
39
- return self if count_only?
40
- initialize_resolvers
41
- call_resolvers
42
- self
43
- end
44
-
45
- # Primary collection, empty if count requested
46
- #
47
- # @return [ActiveRecord::Relation, Array<ActiveRecord::Base>]
48
- #
49
- def collection
50
- count_only? ? [] : relation
51
- end
52
-
53
- # Count of primary collection
54
- #
55
- # @note Delegate to Kaminari's `total_count` property, or regular count if not a paginated relation
56
- #
57
- # @return [Integer]
58
- #
59
- def total_count
60
- relation.respond_to?(:total_count) ? relation.total_count : relation.count
61
- end
62
-
63
- # Policies for the primary collection
64
- #
65
- # @example
66
- # [
67
- # { post_id: 1, update: true, destroy: true },
68
- # { post_id: 2, update: false, destroy: false }
69
- # ]
70
- #
71
- # @return [<Array<Hash>]
72
- #
73
- def policies
74
- @policies_resolver ? @policies_resolver.resolved_policies : {}
75
- end
76
-
77
- # Class names of included collections
78
- #
79
- # @example
80
- # [:categories, :sub_categories, :users]
81
- #
82
- # @return [Array<Symbol>]
83
- #
84
- def included_collection_names
85
- @included_collection_names ||= ParseIncludeParams.call(params[:include])
86
- end
87
-
88
- # Map of included collection names and loaded record
89
- #
90
- # @example
91
- # {
92
- # categories: [#<Category id:1>],
93
- # sub_categories: [#<SubCategory id:1>],
94
- # users: [#<User id:1>, #<User id:2]
95
- # }
96
- #
97
- # @return [Hash]
98
- #
99
- def included_collections
100
- @included_collections_resolver ? @included_collections_resolver.resolved_collections : {}
101
- end
102
-
103
- # Preload additional records with the relation
104
- #
105
- # @note Called by resolvers, but can also be called if additional data is required that does
106
- # not need to be loaded as an included collection, and for some reason cannot be chained
107
- # onto the original relation.
108
- #
109
- # @param associations [Symbol, Array<Symbol>]
110
- #
111
- def preload(associations)
112
- @relation = @relation.preload(associations)
113
- end
114
-
115
- # Hash map that defines the sources for included collection names
116
- #
117
- # @example
118
- # def associations_map
119
- # {
120
- # categories: { associations: { sub_category: :category } },
121
- # sub_categories: { associations: :sub_category },
122
- # users: { associations: [:creator, :publisher] }
123
- # }
124
- # end
125
- #
126
- # @abstract
127
- #
128
- # @return [Hash]
129
- #
130
- def associations_map
131
- {}
132
- end
133
-
134
- # Policy methods to resolve for the primary relation
135
- #
136
- # @example Single
137
- # def policy_methods
138
- # :update
139
- # end
140
- #
141
- # @example Multiple
142
- # def policy_methods
143
- # [:update, :destroy]
144
- # end
145
- #
146
- # @abstract
147
- #
148
- # @return [Symbol, Array<Symbol>]
149
- #
150
- def policy_methods
151
- []
152
- end
153
-
154
- # Policy associations to preload to optimize policy resolution
155
- #
156
- # @example Single
157
- # def policy_associations
158
- # :user_profile
159
- # end
160
- #
161
- # @example Multiple
162
- # def policy_associations
163
- # [:user_profile, :company]
164
- # end
165
- #
166
- # @abstract
167
- #
168
- # @return [Symbol, Array<Symbol>]
169
- #
170
- def policy_associations
171
- []
172
- end
173
-
174
- private
175
-
176
- def count_only?
177
- @count_only ||= !!params[:count]
178
- end
179
-
180
- def resolve_policies?
181
- @resolve_policies ||= current_user && !!params[:policies]
182
- end
183
-
184
- def resolve_included_collctions?
185
- included_collection_names.any?
186
- end
187
-
188
- def initialize_resolvers
189
- @policies_resolver = Resolvers::PoliciesResolver.new(self) if resolve_policies?
190
- @included_collections_resolver = Resolvers::IncludedCollectionsResolver.new(self) if resolve_included_collctions?
191
- end
192
-
193
- def call_resolvers
194
- @policies_resolver.call if @policies_resolver
195
- @included_collections_resolver.call if @included_collections_resolver
196
- end
197
- end
198
- end
199
-
200
- require 'api_presenter/parse_include_params'
201
- require 'api_presenter/version'
4
+ require 'api_presenter/base'
202
5
  require 'api_presenter/concerns/presentable'
6
+ require 'api_presenter/parsers/parse_include_params'
203
7
  require 'api_presenter/resolvers/base'
204
- require 'api_presenter/resolvers/policies_resolver'
205
8
  require 'api_presenter/resolvers/included_collections_resolver'
9
+ require 'api_presenter/resolvers/policies_resolver'
10
+ require 'api_presenter/version'
@@ -0,0 +1,196 @@
1
+ module ApiPresenter
2
+ class Base
3
+
4
+ attr_reader :current_user, :params, :relation
5
+
6
+ # @example
7
+ # @presenter = PostPresenter.call(
8
+ # current_user: current_user,
9
+ # relation: relation,
10
+ # params: params
11
+ # )
12
+ #
13
+ # @param (see #initialize)
14
+ #
15
+ # @return [ApiPresenter::Base]
16
+ #
17
+ def self.call(**kwargs)
18
+ new(kwargs).call
19
+ end
20
+
21
+ # @param current_user [User] Optional. current_user context.
22
+ # @param relation [ActiveRecord::Relation, Array] Relation or array-wrapped record(s) to present
23
+ # @param params [Hash] Controller params
24
+ # @option params [Boolean] :count Optional. If true, return count only.
25
+ # @option params [String, Array] :include Optional. Associated resources to include.
26
+ # @option params [Boolean] :policies Optional. If true, resolve polciies for relation.
27
+ #
28
+ def initialize(current_user: nil, relation:, params: {})
29
+ @current_user = current_user
30
+ @relation = relation
31
+ @params = params
32
+ end
33
+
34
+ # @return [ApiPresenter::Base]
35
+ #
36
+ def call
37
+ return self if count_only?
38
+ initialize_resolvers
39
+ call_resolvers
40
+ self
41
+ end
42
+
43
+ # Primary collection, empty if count requested
44
+ #
45
+ # @return [ActiveRecord::Relation, Array<ActiveRecord::Base>]
46
+ #
47
+ def collection
48
+ count_only? ? [] : relation
49
+ end
50
+
51
+ # Count of primary collection
52
+ #
53
+ # @note Delegate to Kaminari's `total_count` property, or regular count if not a paginated relation
54
+ #
55
+ # @return [Integer]
56
+ #
57
+ def total_count
58
+ relation.respond_to?(:total_count) ? relation.total_count : relation.count
59
+ end
60
+
61
+ # Policies for the primary collection
62
+ #
63
+ # @example
64
+ # [
65
+ # { post_id: 1, update: true, destroy: true },
66
+ # { post_id: 2, update: false, destroy: false }
67
+ # ]
68
+ #
69
+ # @return [<Array<Hash>]
70
+ #
71
+ def policies
72
+ @policies_resolver ? @policies_resolver.resolved_policies : {}
73
+ end
74
+
75
+ # Class names of included collections
76
+ #
77
+ # @example
78
+ # [:categories, :sub_categories, :users]
79
+ #
80
+ # @return [Array<Symbol>]
81
+ #
82
+ def included_collection_names
83
+ @included_collection_names ||= Parsers::ParseIncludeParams.call(params[:include])
84
+ end
85
+
86
+ # Map of included collection names and loaded record
87
+ #
88
+ # @example
89
+ # {
90
+ # categories: [#<Category id:1>],
91
+ # sub_categories: [#<SubCategory id:1>],
92
+ # users: [#<User id:1>, #<User id:2]
93
+ # }
94
+ #
95
+ # @return [Hash]
96
+ #
97
+ def included_collections
98
+ @included_collections_resolver ? @included_collections_resolver.resolved_collections : {}
99
+ end
100
+
101
+ # Preload additional records with the relation
102
+ #
103
+ # @note Called by resolvers, but can also be called if additional data is required that does
104
+ # not need to be loaded as an included collection, and for some reason cannot be chained
105
+ # onto the original relation.
106
+ #
107
+ # @param associations [Symbol, Array<Symbol>]
108
+ #
109
+ def preload(associations)
110
+ @relation = @relation.preload(associations)
111
+ end
112
+
113
+ # Hash map that defines the sources for included collection names
114
+ #
115
+ # @example
116
+ # def associations_map
117
+ # {
118
+ # categories: { associations: { sub_category: :category } },
119
+ # sub_categories: { associations: :sub_category },
120
+ # users: { associations: [:creator, :publisher] }
121
+ # }
122
+ # end
123
+ #
124
+ # @abstract
125
+ #
126
+ # @return [Hash]
127
+ #
128
+ def associations_map
129
+ {}
130
+ end
131
+
132
+ # Policy methods to resolve for the primary relation
133
+ #
134
+ # @example Single
135
+ # def policy_methods
136
+ # :update
137
+ # end
138
+ #
139
+ # @example Multiple
140
+ # def policy_methods
141
+ # [:update, :destroy]
142
+ # end
143
+ #
144
+ # @abstract
145
+ #
146
+ # @return [Symbol, Array<Symbol>]
147
+ #
148
+ def policy_methods
149
+ []
150
+ end
151
+
152
+ # Policy associations to preload to optimize policy resolution
153
+ #
154
+ # @example Single
155
+ # def policy_associations
156
+ # :user_profile
157
+ # end
158
+ #
159
+ # @example Multiple
160
+ # def policy_associations
161
+ # [:user_profile, :company]
162
+ # end
163
+ #
164
+ # @abstract
165
+ #
166
+ # @return [Symbol, Array<Symbol>]
167
+ #
168
+ def policy_associations
169
+ []
170
+ end
171
+
172
+ private
173
+
174
+ def count_only?
175
+ @count_only ||= !!params[:count]
176
+ end
177
+
178
+ def resolve_policies?
179
+ @resolve_policies ||= current_user && !!params[:policies]
180
+ end
181
+
182
+ def resolve_included_collctions?
183
+ included_collection_names.any?
184
+ end
185
+
186
+ def initialize_resolvers
187
+ @policies_resolver = Resolvers::PoliciesResolver.new(self) if resolve_policies?
188
+ @included_collections_resolver = Resolvers::IncludedCollectionsResolver.new(self) if resolve_included_collctions?
189
+ end
190
+
191
+ def call_resolvers
192
+ @policies_resolver.call if @policies_resolver
193
+ @included_collections_resolver.call if @included_collections_resolver
194
+ end
195
+ end
196
+ end
@@ -0,0 +1,27 @@
1
+ module ApiPresenter
2
+ module Parsers
3
+
4
+ # Parses values into array of acceptable association map keys:
5
+ # * Removes blanks and dups
6
+ # * Underscores camel-cased keys
7
+ # * Converts to symbol
8
+ #
9
+ # @param values [String, Array<String>, Array<Symbol>] Comma-delimited string or array
10
+ #
11
+ # @return [Array<Symbol>]
12
+ #
13
+ class ParseIncludeParams
14
+ def self.call(values)
15
+ return [] if values.blank?
16
+
17
+ array = values.is_a?(Array) ? values.dup : values.split(',')
18
+ array.select!(&:present?)
19
+ array.map! { |value| value.try(:underscore) || value }
20
+ array.uniq!
21
+ array.map!(&:to_sym)
22
+
23
+ array
24
+ end
25
+ end
26
+ end
27
+ end
@@ -1,3 +1,3 @@
1
1
  module ApiPresenter
2
- VERSION = "0.2.3"
2
+ VERSION = "0.2.4"
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: api_presenter
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.3
4
+ version: 0.2.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Yuval Kordov
@@ -129,8 +129,9 @@ files:
129
129
  - bin/console
130
130
  - bin/setup
131
131
  - lib/api_presenter.rb
132
+ - lib/api_presenter/base.rb
132
133
  - lib/api_presenter/concerns/presentable.rb
133
- - lib/api_presenter/parse_include_params.rb
134
+ - lib/api_presenter/parsers/parse_include_params.rb
134
135
  - lib/api_presenter/resolvers/base.rb
135
136
  - lib/api_presenter/resolvers/included_collections_resolver.rb
136
137
  - lib/api_presenter/resolvers/policies_resolver.rb
@@ -1,25 +0,0 @@
1
- module ApiPresenter
2
-
3
- # Parses values into array of acceptable association map keys:
4
- # * Removes blanks and dups
5
- # * Underscores camel-cased keys
6
- # * Converts to symbol
7
- #
8
- # @param values [String, Array<String>, Array<Symbol>] Comma-delimited string or array
9
- #
10
- # @return [Array<Symbol>]
11
- #
12
- class ParseIncludeParams
13
- def self.call(values)
14
- return [] if values.blank?
15
-
16
- array = values.is_a?(Array) ? values.dup : values.split(',')
17
- array.select!(&:present?)
18
- array.map! { |value| value.try(:underscore) || value }
19
- array.uniq!
20
- array.map!(&:to_sym)
21
-
22
- array
23
- end
24
- end
25
- end