easy-jsonapi 1.0.0
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.
- checksums.yaml +7 -0
- data/.github/workflows/publish-gem.yml +60 -0
- data/.github/workflows/rake.yml +35 -0
- data/.rspec +3 -0
- data/.ruby-version +1 -0
- data/CHANGELOG.md +5 -0
- data/CODE_OF_CONDUCT.md +74 -0
- data/Gemfile +5 -0
- data/Gemfile.lock +106 -0
- data/LICENSE.txt +21 -0
- data/README.md +209 -0
- data/Rakefile +20 -0
- data/UsingTheRequestObject.md +74 -0
- data/UsingUserConfigurations.md +95 -0
- data/bin/bundle +114 -0
- data/bin/console +15 -0
- data/bin/htmldiff +29 -0
- data/bin/kramdown +29 -0
- data/bin/ldiff +29 -0
- data/bin/license_finder +29 -0
- data/bin/license_finder_pip.py +29 -0
- data/bin/maruku +29 -0
- data/bin/marutex +29 -0
- data/bin/nokogiri +29 -0
- data/bin/racc +29 -0
- data/bin/rackup +29 -0
- data/bin/rake +29 -0
- data/bin/redcarpet +29 -0
- data/bin/reverse_markdown +29 -0
- data/bin/rspec +29 -0
- data/bin/rubocop +29 -0
- data/bin/ruby-parse +29 -0
- data/bin/ruby-rewrite +29 -0
- data/bin/setup +8 -0
- data/bin/solargraph +29 -0
- data/bin/thor +29 -0
- data/bin/tilt +29 -0
- data/bin/yard +29 -0
- data/bin/yardoc +29 -0
- data/bin/yri +29 -0
- data/easy-jsonapi.gemspec +39 -0
- data/lib/easy/jsonapi.rb +12 -0
- data/lib/easy/jsonapi/collection.rb +144 -0
- data/lib/easy/jsonapi/config_manager.rb +144 -0
- data/lib/easy/jsonapi/config_manager/config.rb +49 -0
- data/lib/easy/jsonapi/document.rb +71 -0
- data/lib/easy/jsonapi/document/error.rb +48 -0
- data/lib/easy/jsonapi/document/error/error_member.rb +15 -0
- data/lib/easy/jsonapi/document/jsonapi.rb +26 -0
- data/lib/easy/jsonapi/document/jsonapi/jsonapi_member.rb +15 -0
- data/lib/easy/jsonapi/document/links.rb +36 -0
- data/lib/easy/jsonapi/document/links/link.rb +15 -0
- data/lib/easy/jsonapi/document/meta.rb +26 -0
- data/lib/easy/jsonapi/document/meta/meta_member.rb +14 -0
- data/lib/easy/jsonapi/document/resource.rb +56 -0
- data/lib/easy/jsonapi/document/resource/attributes.rb +37 -0
- data/lib/easy/jsonapi/document/resource/attributes/attribute.rb +29 -0
- data/lib/easy/jsonapi/document/resource/relationships.rb +40 -0
- data/lib/easy/jsonapi/document/resource/relationships/relationship.rb +50 -0
- data/lib/easy/jsonapi/document/resource_id.rb +28 -0
- data/lib/easy/jsonapi/exceptions.rb +27 -0
- data/lib/easy/jsonapi/exceptions/document_exceptions.rb +619 -0
- data/lib/easy/jsonapi/exceptions/headers_exceptions.rb +156 -0
- data/lib/easy/jsonapi/exceptions/naming_exceptions.rb +36 -0
- data/lib/easy/jsonapi/exceptions/query_params_exceptions.rb +67 -0
- data/lib/easy/jsonapi/exceptions/user_defined_exceptions.rb +253 -0
- data/lib/easy/jsonapi/field.rb +43 -0
- data/lib/easy/jsonapi/header_collection.rb +38 -0
- data/lib/easy/jsonapi/header_collection/header.rb +11 -0
- data/lib/easy/jsonapi/item.rb +88 -0
- data/lib/easy/jsonapi/middleware.rb +158 -0
- data/lib/easy/jsonapi/name_value_pair.rb +72 -0
- data/lib/easy/jsonapi/name_value_pair_collection.rb +78 -0
- data/lib/easy/jsonapi/parser.rb +38 -0
- data/lib/easy/jsonapi/parser/document_parser.rb +196 -0
- data/lib/easy/jsonapi/parser/headers_parser.rb +33 -0
- data/lib/easy/jsonapi/parser/rack_req_params_parser.rb +117 -0
- data/lib/easy/jsonapi/request.rb +40 -0
- data/lib/easy/jsonapi/request/query_param_collection.rb +56 -0
- data/lib/easy/jsonapi/request/query_param_collection/fields_param.rb +32 -0
- data/lib/easy/jsonapi/request/query_param_collection/fields_param/fieldset.rb +34 -0
- data/lib/easy/jsonapi/request/query_param_collection/filter_param.rb +28 -0
- data/lib/easy/jsonapi/request/query_param_collection/filter_param/filter.rb +34 -0
- data/lib/easy/jsonapi/request/query_param_collection/include_param.rb +119 -0
- data/lib/easy/jsonapi/request/query_param_collection/page_param.rb +55 -0
- data/lib/easy/jsonapi/request/query_param_collection/query_param.rb +47 -0
- data/lib/easy/jsonapi/request/query_param_collection/sort_param.rb +25 -0
- data/lib/easy/jsonapi/response.rb +22 -0
- data/lib/easy/jsonapi/utility.rb +158 -0
- data/lib/easy/jsonapi/version.rb +8 -0
- metadata +248 -0
@@ -0,0 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'easy/jsonapi/request/query_param_collection/query_param'
|
4
|
+
|
5
|
+
module JSONAPI
|
6
|
+
class Request
|
7
|
+
class QueryParamCollection < JSONAPI::NameValuePairCollection
|
8
|
+
# Used to create a unique Fieldset JSONAPI::Request::QueryParamCollection::QueryParam
|
9
|
+
class FieldsParam < QueryParam
|
10
|
+
|
11
|
+
# @param fieldset_arr [Array<JSONAPI::Request::QueryParamCollection::FieldsParam::Fieldset>]
|
12
|
+
# The array of fieldsets found in the query string. Ex: fields[resource]=res_field1,res_field2
|
13
|
+
def initialize(fieldset_arr)
|
14
|
+
super('fields', fieldset_arr)
|
15
|
+
end
|
16
|
+
|
17
|
+
# Alias to parent #value method
|
18
|
+
# @return [Array<JSONAPI::Request::QueryParamCollection::FieldsParam::Fieldset>]
|
19
|
+
def fieldsets
|
20
|
+
value
|
21
|
+
end
|
22
|
+
|
23
|
+
# @return The the query string representation of the included fieldsets
|
24
|
+
# ex: "#{fieldset1.to_s}&{fieldset2.to_s}&..."
|
25
|
+
def to_s
|
26
|
+
JSONAPI::Utility.to_string_collection(value, delimiter: '&')
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'easy/jsonapi/name_value_pair_collection'
|
4
|
+
require 'easy/jsonapi/request/query_param_collection/fields_param'
|
5
|
+
require 'easy/jsonapi/utility'
|
6
|
+
|
7
|
+
module JSONAPI
|
8
|
+
class Request
|
9
|
+
class QueryParamCollection < NameValuePairCollection
|
10
|
+
class FieldsParam < QueryParam
|
11
|
+
# Collection of fields related to specific resource objects
|
12
|
+
class Fieldset
|
13
|
+
|
14
|
+
attr_reader :resource_type, :fields
|
15
|
+
|
16
|
+
# @param field_arr [Array<JSONAPI::Field>]
|
17
|
+
# A fieldset is a collection of Resource Fields
|
18
|
+
def initialize(resource_type, field_arr = [])
|
19
|
+
@resource_type = resource_type
|
20
|
+
@fields = field_arr
|
21
|
+
end
|
22
|
+
|
23
|
+
# Represention of Fieldset as a string where fields
|
24
|
+
# are comma separated strings
|
25
|
+
def to_s
|
26
|
+
pre_string = "fields[#{@resource_type}]="
|
27
|
+
JSONAPI::Utility.to_string_collection(@fields, delimiter: ',', pre_string: pre_string)
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'easy/jsonapi/request/query_param_collection/query_param'
|
4
|
+
require 'easy/jsonapi/utility'
|
5
|
+
|
6
|
+
module JSONAPI
|
7
|
+
class Request
|
8
|
+
class QueryParamCollection < JSONAPI::NameValuePairCollection
|
9
|
+
|
10
|
+
# Used to create a unique Filter JSONAPI::Request::QueryParamCollection::QueryParam
|
11
|
+
class FilterParam < QueryParam
|
12
|
+
|
13
|
+
# @param filter_arr [Array<JSONAPI::Request::QueryParamCollection::FilterParam::Filter>]
|
14
|
+
# The array of filters included in the query string. Ex: filter[articles]=(posted_date == today)
|
15
|
+
def initialize(filter_arr)
|
16
|
+
super('filters', filter_arr)
|
17
|
+
end
|
18
|
+
|
19
|
+
# Represent each filter separated by a & value
|
20
|
+
# Ex: "#{filter1.to_s}&{filter2.to_s}&..."
|
21
|
+
def to_s
|
22
|
+
JSONAPI::Utility.to_string_collection(value, delimiter: '&')
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'easy/jsonapi/request/query_param_collection/filter_param'
|
4
|
+
|
5
|
+
module JSONAPI
|
6
|
+
class Request
|
7
|
+
class QueryParamCollection < NameValuePairCollection
|
8
|
+
class FilterParam < QueryParam
|
9
|
+
# Represents an individual Filtering scheme for the filter query param(s) used.
|
10
|
+
class Filter
|
11
|
+
|
12
|
+
attr_reader :resource_type, :filter
|
13
|
+
|
14
|
+
# @param resource_type [String] The type to filter
|
15
|
+
# @param filter [String] The filter algorithm
|
16
|
+
def initialize(resource_type, filter)
|
17
|
+
@resource_type = resource_type
|
18
|
+
@filter = filter
|
19
|
+
end
|
20
|
+
|
21
|
+
# @return [String] The value of the filter
|
22
|
+
def value
|
23
|
+
@filter
|
24
|
+
end
|
25
|
+
|
26
|
+
# Represent filter as an individual filter query param
|
27
|
+
def to_s
|
28
|
+
"filter[#{@resource_type}]=#{@filter}"
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,119 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'easy/jsonapi/request/query_param_collection/query_param'
|
4
|
+
require 'easy/jsonapi/utility'
|
5
|
+
|
6
|
+
module JSONAPI
|
7
|
+
class Request
|
8
|
+
class QueryParamCollection < JSONAPI::NameValuePairCollection
|
9
|
+
# The include query param
|
10
|
+
class IncludeParam < QueryParam
|
11
|
+
|
12
|
+
|
13
|
+
# @param includes_arr [Array<String>] An array with each individual query include
|
14
|
+
# Ex: incude=author,people => ['author', 'people']
|
15
|
+
def initialize(includes_arr)
|
16
|
+
includes_hash_structure = store_includes(includes_arr)
|
17
|
+
super('includes', includes_hash_structure)
|
18
|
+
end
|
19
|
+
|
20
|
+
# to string
|
21
|
+
def to_s
|
22
|
+
"include=#{stringify_includes_hash(value)}"
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
# Represent include internal hash as query string
|
28
|
+
# @param includes_hash [Hash] The internal structure
|
29
|
+
def stringify_includes_hash(includes_hash)
|
30
|
+
to_return = ''
|
31
|
+
first = true
|
32
|
+
includes_hash.each do |mem_name, mem_hash|
|
33
|
+
if first
|
34
|
+
to_return += to_s_mem(mem_name, mem_hash)
|
35
|
+
first = false
|
36
|
+
else
|
37
|
+
to_return += ",#{to_s_mem(mem_name, mem_hash)}"
|
38
|
+
end
|
39
|
+
end
|
40
|
+
to_return
|
41
|
+
end
|
42
|
+
|
43
|
+
# Depending on the delimiter stringify differently.
|
44
|
+
# @param mem_name [Symbol] The name of the member to stringify
|
45
|
+
# @param mem_hash [Hash] The information about that member
|
46
|
+
def to_s_mem(mem_name, mem_hash)
|
47
|
+
if mem_hash[:relationships] == {}
|
48
|
+
mem_name.to_s
|
49
|
+
else
|
50
|
+
delimiter = mem_hash[:included] == true ? '.' : '-'
|
51
|
+
prefix = "#{mem_name}#{delimiter}"
|
52
|
+
to_return = ''
|
53
|
+
first = true
|
54
|
+
mem_hash[:relationships].each do |m_name, m_hash|
|
55
|
+
if first
|
56
|
+
to_return += "#{prefix}#{to_s_mem(m_name, m_hash)}"
|
57
|
+
first = false
|
58
|
+
else
|
59
|
+
to_return += ",#{prefix}#{to_s_mem(m_name, m_hash)}"
|
60
|
+
end
|
61
|
+
end
|
62
|
+
to_return
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
# Helper for #initialize
|
67
|
+
# @param includes_arr [Array<String>] The array of includes to store
|
68
|
+
def store_includes(includes_arr)
|
69
|
+
incl_hash = {}
|
70
|
+
includes_arr.each do |include_str|
|
71
|
+
include_str_arr = include_str.scan(/\w+|-|\./) # split into array (word, -, or .)
|
72
|
+
store_include(incl_hash, include_str_arr)
|
73
|
+
end
|
74
|
+
incl_hash
|
75
|
+
end
|
76
|
+
|
77
|
+
# @param loc_in_h [Hash] The location within the main hash
|
78
|
+
# @param i_arr [Array<String>] The array of include strings
|
79
|
+
def store_include(loc_in_h, i_arr)
|
80
|
+
res_name = i_arr[0].to_sym
|
81
|
+
if i_arr.length == 1
|
82
|
+
add_member(loc_in_h, res_name, included: true)
|
83
|
+
else
|
84
|
+
add_member(loc_in_h, res_name, included: res_included?(i_arr))
|
85
|
+
store_include(loc_in_h[res_name][:relationships], i_arr[2..])
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
# @param (see #store_include)
|
90
|
+
def res_included?(i_arr)
|
91
|
+
delim = i_arr[1]
|
92
|
+
case delim
|
93
|
+
when '.'
|
94
|
+
true
|
95
|
+
when '-'
|
96
|
+
false
|
97
|
+
else
|
98
|
+
raise 'Syntax Error in include query string query param'
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
# @param loc_in_h [Hash] The location within the main hash
|
103
|
+
# @param res_name [Symbol] The name of the resource
|
104
|
+
# @param included [TrueClass | FalseClass] Whether or not a resource
|
105
|
+
# is being requested or not
|
106
|
+
def add_member(loc_in_h, res_name, included:)
|
107
|
+
if loc_in_h.key?(res_name)
|
108
|
+
loc_in_h[res_name][:included] = included unless included == false
|
109
|
+
else
|
110
|
+
loc_in_h[res_name] = {
|
111
|
+
included: included,
|
112
|
+
relationships: {}
|
113
|
+
}
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'easy/jsonapi/request/query_param_collection/query_param'
|
4
|
+
|
5
|
+
module JSONAPI
|
6
|
+
class Request
|
7
|
+
class QueryParamCollection < JSONAPI::NameValuePairCollection
|
8
|
+
# Used to create a unique Page JSONAPI::Request::QueryParamCollection::QueryParam
|
9
|
+
class PageParam < QueryParam
|
10
|
+
|
11
|
+
# @param offset [Integer | String] the page offset
|
12
|
+
# @param limit [Integer | String] the # of resources returned on a given page
|
13
|
+
def initialize(offset:, limit:)
|
14
|
+
super('page', { offset: offset.to_i, limit: limit.to_i })
|
15
|
+
end
|
16
|
+
|
17
|
+
# @raise [RuntimeError] Informs user to use a different method
|
18
|
+
def value
|
19
|
+
raise 'PageParam does not provide a #value method, try #offset or #limit instead'
|
20
|
+
end
|
21
|
+
|
22
|
+
# @raise [RuntimeError] Informs user to use a different method
|
23
|
+
def value=(_)
|
24
|
+
raise 'PageParam does not provide a #value= method, try #offset= or #limit= instead'
|
25
|
+
end
|
26
|
+
|
27
|
+
# @return [Integer] The page offset
|
28
|
+
def offset
|
29
|
+
@item[:value][:offset]
|
30
|
+
end
|
31
|
+
|
32
|
+
# @param new_offset [Integer | String] The new page offset number
|
33
|
+
def offset=(new_offset)
|
34
|
+
@item[:value][:offset] = new_offset.to_i
|
35
|
+
end
|
36
|
+
|
37
|
+
# @return [Integer] The # of resources returned on a given page
|
38
|
+
def limit
|
39
|
+
@item[:value][:limit]
|
40
|
+
end
|
41
|
+
|
42
|
+
# @param new_limit [Integer] The new page limit number
|
43
|
+
def limit=(new_limit)
|
44
|
+
@item[:value][:limit] = new_limit.to_i
|
45
|
+
end
|
46
|
+
|
47
|
+
# Represents the Page class in a string format
|
48
|
+
def to_s
|
49
|
+
"page[offset]=#{offset}&page[limit]=#{limit}"
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'easy/jsonapi/request/query_param_collection'
|
4
|
+
require 'easy/jsonapi/name_value_pair'
|
5
|
+
require 'easy/jsonapi/exceptions/query_params_exceptions'
|
6
|
+
require 'easy/jsonapi/utility'
|
7
|
+
|
8
|
+
|
9
|
+
module JSONAPI
|
10
|
+
class Request
|
11
|
+
class QueryParamCollection < JSONAPI::NameValuePairCollection
|
12
|
+
# A generic name=value query parameter
|
13
|
+
class QueryParam < JSONAPI::NameValuePair
|
14
|
+
|
15
|
+
# @param name [String] The name of the parameter
|
16
|
+
# @param value [String | Array<String>] The value of the parameter
|
17
|
+
def initialize(name, value)
|
18
|
+
if instance_of?(QueryParam)
|
19
|
+
JSONAPI::Exceptions::QueryParamsExceptions.check_param_name(name)
|
20
|
+
end
|
21
|
+
value = value.split(',') if value.is_a? String
|
22
|
+
super(name, value)
|
23
|
+
end
|
24
|
+
|
25
|
+
# Update the query_param value, turning value into an array if it was given as a string
|
26
|
+
# @param new_value [String, Array<String>] The new value of the Parameter
|
27
|
+
def value=(new_value)
|
28
|
+
new_value = new_value.split(',') if new_value.is_a? String
|
29
|
+
super(new_value)
|
30
|
+
end
|
31
|
+
|
32
|
+
# Represents a parameter as a string
|
33
|
+
def to_s
|
34
|
+
"#{name}=#{JSONAPI::Utility.to_string_collection(value, delimiter: ',')}"
|
35
|
+
end
|
36
|
+
|
37
|
+
# @raise RuntimeError Cannot change the name of a QueryParam object
|
38
|
+
def name=(_)
|
39
|
+
raise 'Cannot change the name of QueryParam Objects'
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
# include=author,comments-likers,comments.likes
|
47
|
+
# author comments-likers comments.likes
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'easy/jsonapi/request/query_param_collection/query_param'
|
4
|
+
|
5
|
+
module JSONAPI
|
6
|
+
class Request
|
7
|
+
class QueryParamCollection < JSONAPI::NameValuePairCollection
|
8
|
+
# Used to create a unique Sort JSONAPI::Request::QueryParamCollection::QueryParam
|
9
|
+
class SortParam < QueryParam
|
10
|
+
|
11
|
+
# @param res_field_arr [Array<JSONAPI::Field] The resource fields
|
12
|
+
# to sort the primary resources by.
|
13
|
+
def initialize(res_field_arr)
|
14
|
+
super('sorts', res_field_arr)
|
15
|
+
end
|
16
|
+
|
17
|
+
# Represent sort as query string
|
18
|
+
def to_s
|
19
|
+
"sort=#{JSONAPI::Utility.to_string_collection(value, delimiter: ',')}"
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'easy/jsonapi/exceptions'
|
4
|
+
|
5
|
+
module JSONAPI
|
6
|
+
# Used to validate the serialized response before returned to a client
|
7
|
+
module Response
|
8
|
+
# TODO: Add config_manager options for out bound serialization validation
|
9
|
+
|
10
|
+
# @param headers [Hash] The hash of response headers.
|
11
|
+
# @param body [Hash | String] The ruby hash mimicking jsonapi or
|
12
|
+
# a JSON document to check for compliance
|
13
|
+
# @return [Nilclass] if no errors are found
|
14
|
+
# @raise [InvalidDocument | InvalidHeader] depending on what errors were found
|
15
|
+
def self.validate(headers, body)
|
16
|
+
# TODO: Spec checks based on collections which can be refered from the location header
|
17
|
+
# returned by the server
|
18
|
+
JSONAPI::Exceptions::HeadersExceptions.check_compliance(headers.transform_keys(&:to_s).transform_keys(&:upcase))
|
19
|
+
JSONAPI::Exceptions::DocumentExceptions.check_compliance(body)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,158 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module JSONAPI
|
4
|
+
|
5
|
+
# A collection of resued logic throughout the gem.
|
6
|
+
module Utility
|
7
|
+
|
8
|
+
class << self
|
9
|
+
|
10
|
+
# To hash method for a JSONAPI collection (like Attributes)
|
11
|
+
# @param collection [Inumerable] The collection to hashify
|
12
|
+
def to_h_collection(collection)
|
13
|
+
to_return = {}
|
14
|
+
collection.each do |mem|
|
15
|
+
h_val = JSONAPI::Utility.to_h_value(mem)
|
16
|
+
to_return[mem.name.to_sym] = h_val
|
17
|
+
end
|
18
|
+
to_return
|
19
|
+
end
|
20
|
+
|
21
|
+
# Helper method for #to_h_collection
|
22
|
+
# @param val [Any] The value to call to hash on.
|
23
|
+
# @return a hash value member
|
24
|
+
def to_h_value(val)
|
25
|
+
case val
|
26
|
+
when String
|
27
|
+
val
|
28
|
+
when JSONAPI::Collection
|
29
|
+
obj_hash = {}
|
30
|
+
val.each { |i| obj_hash[i.name.to_sym] = to_h_value(i) }
|
31
|
+
obj_hash
|
32
|
+
else
|
33
|
+
v = val.value
|
34
|
+
case v
|
35
|
+
when String
|
36
|
+
to_h_value(v)
|
37
|
+
when Array
|
38
|
+
v.map { |e| to_h_value(e) }
|
39
|
+
else
|
40
|
+
v.to_h
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
# Helper for #to_h for classes that arent collection and have a set number
|
46
|
+
# of instance variables to hashify
|
47
|
+
# @param hash_to_add_to [Hash] The hash to return
|
48
|
+
# @param obj_member [Any] The instance variable to hashify
|
49
|
+
# @param obj_member_name [Symbol] The hash key to store the object under
|
50
|
+
# @return [Hash] The hash for a specific instance variable
|
51
|
+
def to_h_member(hash_to_add_to, obj_member, obj_member_name)
|
52
|
+
return if obj_member.nil?
|
53
|
+
case obj_member
|
54
|
+
when String
|
55
|
+
hash_to_add_to[obj_member_name] = obj_member
|
56
|
+
when Array
|
57
|
+
hash_arr = obj_member.map(&:to_h)
|
58
|
+
hash_to_add_to[obj_member_name] = hash_arr
|
59
|
+
else
|
60
|
+
hash_to_add_to[obj_member_name] = obj_member.to_h
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
# Helper method for #to_s that stringifys a collection
|
65
|
+
# @param collection [Inumerable] An array type of collection
|
66
|
+
# @param delimiter [String] The delimieter to separate each item string
|
67
|
+
# @param pre_string [String] The string to precede the collection string
|
68
|
+
# @param post_string [String] The string to follow the collection
|
69
|
+
def to_string_collection(collection, delimiter: ', ', pre_string: '', post_string: '')
|
70
|
+
to_return = pre_string
|
71
|
+
first = true
|
72
|
+
collection.each do |item|
|
73
|
+
if first
|
74
|
+
to_return += item.to_s
|
75
|
+
first = false
|
76
|
+
else
|
77
|
+
to_return += "#{delimiter}#{item}"
|
78
|
+
end
|
79
|
+
end
|
80
|
+
to_return += post_string
|
81
|
+
end
|
82
|
+
|
83
|
+
# Helper for #to_s where collections are hashes and members should not
|
84
|
+
# be included if they are nil. It also accounts for arrays.
|
85
|
+
# @param str_name [String | Symbol] The name of hash member
|
86
|
+
# @param member [Any] The value of the hash member
|
87
|
+
# @param first_member [TrueClass | FalseClass] Whether or not this is the
|
88
|
+
# first member in the hash.
|
89
|
+
def member_to_s(str_name, member, first_member: false)
|
90
|
+
return '' if member.nil?
|
91
|
+
member = "\"#{member}\"" if member.is_a? String
|
92
|
+
if first_member
|
93
|
+
"\"#{str_name}\": #{array_to_s(member)}"
|
94
|
+
else
|
95
|
+
", \"#{str_name}\": #{array_to_s(member)}"
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
# Returns the proper to_s for members regardless of
|
100
|
+
# whether they are stored as an array or member object
|
101
|
+
def array_to_s(obj_arr)
|
102
|
+
return obj_arr.to_s unless obj_arr.is_a? Array
|
103
|
+
to_return = '['
|
104
|
+
first = true
|
105
|
+
obj_arr.each do |obj|
|
106
|
+
if first
|
107
|
+
to_return += obj.to_s
|
108
|
+
first = false
|
109
|
+
else
|
110
|
+
to_return += ", #{obj}"
|
111
|
+
end
|
112
|
+
end
|
113
|
+
to_return += ']'
|
114
|
+
end
|
115
|
+
|
116
|
+
# Get resource type from path
|
117
|
+
# @param path [String] The url path
|
118
|
+
# @return [String] The resource type
|
119
|
+
def path_to_res_type(path)
|
120
|
+
path_arr = path.split('/')
|
121
|
+
if integer?(path_arr[-1]) || uuid?(path_arr[-1])
|
122
|
+
path_arr[-2]
|
123
|
+
else
|
124
|
+
path_arr[-1]
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
# Check if an input is an integer
|
129
|
+
# @param str [String | Integer]
|
130
|
+
def integer?(str)
|
131
|
+
# integers cannot be valid symbols, so assume string or integer input
|
132
|
+
return true if str.is_a?(Integer) ||
|
133
|
+
str =~ /\A\d+\z/
|
134
|
+
false
|
135
|
+
end
|
136
|
+
|
137
|
+
# Use regix to test whether the input is a valid gen 4 uuid.
|
138
|
+
# @param uuid [String]
|
139
|
+
# @return [TrueClass | FalseClass]
|
140
|
+
def uuid?(uuid)
|
141
|
+
# uuids cannot be valid symbols, so assume string
|
142
|
+
return true if uuid =~ /\A[\da-f]{8}-[\da-f]{4}-[\da-f]{4}-[\da-f]{4}-[\da-f]{12}\z/i ||
|
143
|
+
uuid =~ /\A[\dA-F]{8}-[\dA-F]{4}-[\dA-F]{4}-[\dA-F]{4}-[\dA-F]{12}\z/i
|
144
|
+
false
|
145
|
+
end
|
146
|
+
|
147
|
+
# The hash method #dig throws an error if an array appears in the path specified,
|
148
|
+
# this method returns false for such a senario.
|
149
|
+
# @param hash [Hash] The hash being inspected
|
150
|
+
# @param args [Array<Symbol | String>] The hash keys making up the path
|
151
|
+
def all_hash_path?(hash, args)
|
152
|
+
return false if (args.size.positive? && !hash.is_a?(Hash)) || hash.nil?
|
153
|
+
return true if args.size.zero? && !hash.nil?
|
154
|
+
all_hash_path?(hash[args.first], args[1..])
|
155
|
+
end
|
156
|
+
end
|
157
|
+
end
|
158
|
+
end
|