Skip to content

Commit a86b7e7

Browse files
author
Lee Richmond
committed
break DSL into separate class
1 parent e68a88d commit a86b7e7

File tree

5 files changed

+128
-122
lines changed

5 files changed

+128
-122
lines changed

lib/jsonapi_compliable.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
require 'jsonapi_ams_extensions'
44

55
require "jsonapi_compliable/version"
6+
require "jsonapi_compliable/errors"
7+
require "jsonapi_compliable/dsl"
68

79
module JSONAPICompliable
810
autoload :Base, 'jsonapi_compliable/base'

lib/jsonapi_compliable/base.rb

Lines changed: 14 additions & 119 deletions
Original file line numberDiff line numberDiff line change
@@ -1,120 +1,15 @@
11
module JSONAPICompliable
2-
class BadFilter < StandardError; end
3-
class UnsupportedPageSize < StandardError; end
4-
52
module Base
63
extend ActiveSupport::Concern
74
include Deserializable
85

96
MAX_PAGE_SIZE = 1_000
107

11-
class JsonApiConfig
12-
attr_accessor :_includes,
13-
:_default_filters,
14-
:_extra_fields,
15-
:_filters,
16-
:_sort,
17-
:_paginate
18-
19-
def initialize
20-
@_includes = {}
21-
@_filters = {}
22-
@_default_filters = {}
23-
@_extra_fields = {}
24-
@_sort = nil
25-
@_paginate = nil
26-
end
27-
28-
def includes(whitelist: nil, &blk)
29-
whitelist = parse_includes(whitelist) if whitelist
30-
31-
@_includes = {
32-
whitelist: whitelist,
33-
custom_function: blk
34-
}
35-
end
36-
37-
def allow_filter(name, *args, &blk)
38-
opts = args.extract_options!
39-
aliases = [name, opts[:aliases]].flatten.compact
40-
@_filters[name.to_sym] = {
41-
aliases: aliases,
42-
if: opts[:if],
43-
filter: blk
44-
}
45-
end
46-
47-
def default_filter(name, &blk)
48-
@_default_filters[name.to_sym] = {
49-
filter: blk
50-
}
51-
end
52-
53-
def sort(&blk)
54-
@_sort = blk
55-
end
56-
57-
def paginate(&blk)
58-
@_paginate = blk
59-
end
60-
61-
def extra_field(field, &blk)
62-
@_extra_fields[field.keys.first] ||= []
63-
@_extra_fields[field.keys.first] << {
64-
name: field.values.first,
65-
proc: blk
66-
}
67-
end
68-
69-
def parse_includes(includes)
70-
JSONAPI::IncludeDirective.new(includes)
71-
end
72-
73-
def filter_scope(controller, scope, name, value)
74-
name = name.to_sym
75-
filter = find_filter!(controller, name)
76-
value = value.split(',') if value.include?(',')
77-
78-
if custom_scope = filter.values.first[:filter]
79-
custom_scope.call(scope, value)
80-
else
81-
scope.where(filter.keys.first => value)
82-
end
83-
end
84-
85-
def default_filter_scope(controller, scope)
86-
@_default_filters.each_pair do |name, opts|
87-
next if find_filter(controller, name)
88-
scope = opts[:filter].call(scope)
89-
end
90-
91-
scope
92-
end
93-
94-
private
95-
96-
def find_filter(controller, name)
97-
find_filter!(controller, name)
98-
rescue BadFilter
99-
nil
100-
end
101-
102-
def find_filter!(controller, name)
103-
filter_name, filter_value = \
104-
@_filters.find { |_name, opts| opts[:aliases].include?(name.to_sym) }
105-
raise BadFilter unless filter_name
106-
if guard = filter_value[:if]
107-
raise BadFilter if controller.send(guard) == false
108-
end
109-
{ filter_name => filter_value }
110-
end
111-
end
112-
1138
included do
114-
class_attribute :_jsonapi_config
9+
class_attribute :_jsonapi_compliable
11510

11611
def self.inherited(klass)
117-
klass._jsonapi_config = nil
12+
klass._jsonapi_compliable = nil
11813
end
11914

12015
before_action :parse_fieldsets!
@@ -141,16 +36,16 @@ def self.call(includes, whitelist)
14136
def scrub_includes
14237
return unless params[:include]
14338

144-
includes = _jsonapi_config.parse_includes(params[:include])
145-
whitelist = _jsonapi_config._includes[:whitelist][params[:action]]
39+
includes = _jsonapi_compliable.parse_includes(params[:include])
40+
whitelist = _jsonapi_compliable.sideloads[:whitelist][params[:action]]
14641
whitelist ? CompareIncludes.call(includes, whitelist) : {}
14742
end
14843

14944
def jsonapi_includes(scope)
15045
scrubbed = scrub_includes
15146
return scope unless scrubbed
15247

153-
scope = if custom_include = _jsonapi_config._includes[:custom_function]
48+
scope = if custom_include = _jsonapi_compliable.sideloads[:custom_function]
15449
custom_include.call(scope, scrubbed)
15550
else
15651
scope.includes(scrubbed)
@@ -164,7 +59,7 @@ def jsonapi_sort(scope)
16459
dir = sort_param.starts_with?('-') ? :desc : :asc
16560
att = sort_param.sub('-', '').to_sym
16661

167-
scope = if custom_sort = _jsonapi_config._sort
62+
scope = if custom_sort = _jsonapi_compliable.sorting
16863
custom_sort.call(scope, att, dir)
16964
else
17065
scope.order(att => dir)
@@ -179,10 +74,10 @@ def jsonapi_paginate(scope)
17974
size = (page_param[:size] || default_page_size).to_i
18075

18176
if size > MAX_PAGE_SIZE
182-
raise UnsupportedPageSize,"Requested page size #{size} is greater than max supported size #{MAX_PAGE_SIZE}"
77+
raise JSONAPICompliable::Errors::UnsupportedPageSize,"Requested page size #{size} is greater than max supported size #{MAX_PAGE_SIZE}"
18378
end
18479

185-
scope = if custom_pagination = _jsonapi_config._paginate
80+
scope = if custom_pagination = _jsonapi_compliable.pagination
18681
custom_pagination.call(scope, number, size)
18782
else
18883
scope.page(number).per(size)
@@ -193,16 +88,16 @@ def jsonapi_paginate(scope)
19388

19489
def jsonapi_filter(scope)
19590
param_filters = params[:filter] || {}
196-
scope = _jsonapi_config.default_filter_scope(self, scope)
91+
scope = _jsonapi_compliable.default_filter_scope(self, scope)
19792
param_filters.each_pair do |param_name, param_value|
198-
scope = _jsonapi_config.filter_scope(self, scope, param_name, param_value)
93+
scope = _jsonapi_compliable.filter_scope(self, scope, param_name, param_value)
19994
end
20095

20196
scope
20297
end
20398

20499
def jsonapi_extra_fields(scope)
205-
_jsonapi_config._extra_fields.each_pair do |namespace, extra_fields|
100+
_jsonapi_compliable.extra_fields.each_pair do |namespace, extra_fields|
206101
extra_fields.each do |extra_field|
207102
if requested_extra_field?(namespace, extra_field[:name])
208103
scope = extra_field[:proc].call(scope)
@@ -311,9 +206,9 @@ def force_includes?
311206

312207
module ClassMethods
313208
def jsonapi(&blk)
314-
config = JsonApiConfig.new
315-
config.instance_eval(&blk)
316-
self._jsonapi_config = config
209+
dsl = JsonapiCompliable::DSL.new
210+
dsl.instance_eval(&blk)
211+
self._jsonapi_compliable = dsl
317212
end
318213
end
319214
end

lib/jsonapi_compliable/dsl.rb

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
module JsonapiCompliable
2+
class DSL
3+
attr_accessor :sideloads,
4+
:default_filters,
5+
:extra_fields,
6+
:filters,
7+
:sorting,
8+
:pagination
9+
10+
def initialize
11+
@sideloads = {}
12+
@filters = {}
13+
@default_filters = {}
14+
@extra_fields = {}
15+
@sorting = nil
16+
@pagination = nil
17+
end
18+
19+
def includes(whitelist: nil, &blk)
20+
whitelist = parse_includes(whitelist) if whitelist
21+
22+
@sideloads = {
23+
whitelist: whitelist,
24+
custom_function: blk
25+
}
26+
end
27+
28+
def allow_filter(name, *args, &blk)
29+
opts = args.extract_options!
30+
aliases = [name, opts[:aliases]].flatten.compact
31+
@filters[name.to_sym] = {
32+
aliases: aliases,
33+
if: opts[:if],
34+
filter: blk
35+
}
36+
end
37+
38+
def default_filter(name, &blk)
39+
@default_filters[name.to_sym] = {
40+
filter: blk
41+
}
42+
end
43+
44+
def sort(&blk)
45+
@sorting = blk
46+
end
47+
48+
def paginate(&blk)
49+
@pagination = blk
50+
end
51+
52+
def extra_field(field, &blk)
53+
@extra_fields[field.keys.first] ||= []
54+
@extra_fields[field.keys.first] << {
55+
name: field.values.first,
56+
proc: blk
57+
}
58+
end
59+
60+
def parse_includes(includes)
61+
JSONAPI::IncludeDirective.new(includes)
62+
end
63+
64+
def filter_scope(controller, scope, name, value)
65+
name = name.to_sym
66+
filter = find_filter!(controller, name)
67+
value = value.split(',') if value.include?(',')
68+
69+
if custom_scope = filter.values.first[:filter]
70+
custom_scope.call(scope, value)
71+
else
72+
scope.where(filter.keys.first => value)
73+
end
74+
end
75+
76+
def default_filter_scope(controller, scope)
77+
@default_filters.each_pair do |name, opts|
78+
next if find_filter(controller, name)
79+
scope = opts[:filter].call(scope)
80+
end
81+
82+
scope
83+
end
84+
85+
private
86+
87+
def find_filter(controller, name)
88+
find_filter!(controller, name)
89+
rescue JSONAPICompliable::Errors::BadFilter
90+
nil
91+
end
92+
93+
def find_filter!(controller, name)
94+
filter_name, filter_value = \
95+
@filters.find { |_name, opts| opts[:aliases].include?(name.to_sym) }
96+
raise JSONAPICompliable::Errors::BadFilter unless filter_name
97+
if guard = filter_value[:if]
98+
raise JSONAPICompliable::Errors::BadFilter if controller.send(guard) == false
99+
end
100+
{ filter_name => filter_value }
101+
end
102+
end
103+
end

lib/jsonapi_compliable/errors.rb

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
module JSONAPICompliable
2+
module Errors
3+
class BadFilter < StandardError; end
4+
class UnsupportedPageSize < StandardError; end
5+
end
6+
end

spec/jsonapi_compliable_spec.rb

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -311,7 +311,7 @@ def index
311311
it 'should raise error when size > 1000' do
312312
expect {
313313
get :index, params: { page: { number: 2, size: 1001 } }
314-
}.to raise_error(JSONAPICompliable::UnsupportedPageSize)
314+
}.to raise_error(JSONAPICompliable::Errors::UnsupportedPageSize)
315315
end
316316

317317
it 'should limit by size, offset by number' do
@@ -486,7 +486,7 @@ def include_foo!
486486
it 'should raise an error' do
487487
expect {
488488
get :index, params: { filter: { foo: 'bar' } }
489-
}.to raise_error(JSONAPICompliable::BadFilter)
489+
}.to raise_error(JSONAPICompliable::Errors::BadFilter)
490490
end
491491
end
492492

@@ -576,7 +576,7 @@ def include_foo!
576576
it 'should raise error' do
577577
expect {
578578
get :index, params: { filter: { first_name: author2.first_name } }
579-
}.to raise_error(JSONAPICompliable::BadFilter)
579+
}.to raise_error(JSONAPICompliable::Errors::BadFilter)
580580
end
581581
end
582582
end

0 commit comments

Comments
 (0)