easy-jsonapi 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (91) hide show
  1. checksums.yaml +7 -0
  2. data/.github/workflows/publish-gem.yml +60 -0
  3. data/.github/workflows/rake.yml +35 -0
  4. data/.rspec +3 -0
  5. data/.ruby-version +1 -0
  6. data/CHANGELOG.md +5 -0
  7. data/CODE_OF_CONDUCT.md +74 -0
  8. data/Gemfile +5 -0
  9. data/Gemfile.lock +106 -0
  10. data/LICENSE.txt +21 -0
  11. data/README.md +209 -0
  12. data/Rakefile +20 -0
  13. data/UsingTheRequestObject.md +74 -0
  14. data/UsingUserConfigurations.md +95 -0
  15. data/bin/bundle +114 -0
  16. data/bin/console +15 -0
  17. data/bin/htmldiff +29 -0
  18. data/bin/kramdown +29 -0
  19. data/bin/ldiff +29 -0
  20. data/bin/license_finder +29 -0
  21. data/bin/license_finder_pip.py +29 -0
  22. data/bin/maruku +29 -0
  23. data/bin/marutex +29 -0
  24. data/bin/nokogiri +29 -0
  25. data/bin/racc +29 -0
  26. data/bin/rackup +29 -0
  27. data/bin/rake +29 -0
  28. data/bin/redcarpet +29 -0
  29. data/bin/reverse_markdown +29 -0
  30. data/bin/rspec +29 -0
  31. data/bin/rubocop +29 -0
  32. data/bin/ruby-parse +29 -0
  33. data/bin/ruby-rewrite +29 -0
  34. data/bin/setup +8 -0
  35. data/bin/solargraph +29 -0
  36. data/bin/thor +29 -0
  37. data/bin/tilt +29 -0
  38. data/bin/yard +29 -0
  39. data/bin/yardoc +29 -0
  40. data/bin/yri +29 -0
  41. data/easy-jsonapi.gemspec +39 -0
  42. data/lib/easy/jsonapi.rb +12 -0
  43. data/lib/easy/jsonapi/collection.rb +144 -0
  44. data/lib/easy/jsonapi/config_manager.rb +144 -0
  45. data/lib/easy/jsonapi/config_manager/config.rb +49 -0
  46. data/lib/easy/jsonapi/document.rb +71 -0
  47. data/lib/easy/jsonapi/document/error.rb +48 -0
  48. data/lib/easy/jsonapi/document/error/error_member.rb +15 -0
  49. data/lib/easy/jsonapi/document/jsonapi.rb +26 -0
  50. data/lib/easy/jsonapi/document/jsonapi/jsonapi_member.rb +15 -0
  51. data/lib/easy/jsonapi/document/links.rb +36 -0
  52. data/lib/easy/jsonapi/document/links/link.rb +15 -0
  53. data/lib/easy/jsonapi/document/meta.rb +26 -0
  54. data/lib/easy/jsonapi/document/meta/meta_member.rb +14 -0
  55. data/lib/easy/jsonapi/document/resource.rb +56 -0
  56. data/lib/easy/jsonapi/document/resource/attributes.rb +37 -0
  57. data/lib/easy/jsonapi/document/resource/attributes/attribute.rb +29 -0
  58. data/lib/easy/jsonapi/document/resource/relationships.rb +40 -0
  59. data/lib/easy/jsonapi/document/resource/relationships/relationship.rb +50 -0
  60. data/lib/easy/jsonapi/document/resource_id.rb +28 -0
  61. data/lib/easy/jsonapi/exceptions.rb +27 -0
  62. data/lib/easy/jsonapi/exceptions/document_exceptions.rb +619 -0
  63. data/lib/easy/jsonapi/exceptions/headers_exceptions.rb +156 -0
  64. data/lib/easy/jsonapi/exceptions/naming_exceptions.rb +36 -0
  65. data/lib/easy/jsonapi/exceptions/query_params_exceptions.rb +67 -0
  66. data/lib/easy/jsonapi/exceptions/user_defined_exceptions.rb +253 -0
  67. data/lib/easy/jsonapi/field.rb +43 -0
  68. data/lib/easy/jsonapi/header_collection.rb +38 -0
  69. data/lib/easy/jsonapi/header_collection/header.rb +11 -0
  70. data/lib/easy/jsonapi/item.rb +88 -0
  71. data/lib/easy/jsonapi/middleware.rb +158 -0
  72. data/lib/easy/jsonapi/name_value_pair.rb +72 -0
  73. data/lib/easy/jsonapi/name_value_pair_collection.rb +78 -0
  74. data/lib/easy/jsonapi/parser.rb +38 -0
  75. data/lib/easy/jsonapi/parser/document_parser.rb +196 -0
  76. data/lib/easy/jsonapi/parser/headers_parser.rb +33 -0
  77. data/lib/easy/jsonapi/parser/rack_req_params_parser.rb +117 -0
  78. data/lib/easy/jsonapi/request.rb +40 -0
  79. data/lib/easy/jsonapi/request/query_param_collection.rb +56 -0
  80. data/lib/easy/jsonapi/request/query_param_collection/fields_param.rb +32 -0
  81. data/lib/easy/jsonapi/request/query_param_collection/fields_param/fieldset.rb +34 -0
  82. data/lib/easy/jsonapi/request/query_param_collection/filter_param.rb +28 -0
  83. data/lib/easy/jsonapi/request/query_param_collection/filter_param/filter.rb +34 -0
  84. data/lib/easy/jsonapi/request/query_param_collection/include_param.rb +119 -0
  85. data/lib/easy/jsonapi/request/query_param_collection/page_param.rb +55 -0
  86. data/lib/easy/jsonapi/request/query_param_collection/query_param.rb +47 -0
  87. data/lib/easy/jsonapi/request/query_param_collection/sort_param.rb +25 -0
  88. data/lib/easy/jsonapi/response.rb +22 -0
  89. data/lib/easy/jsonapi/utility.rb +158 -0
  90. data/lib/easy/jsonapi/version.rb +8 -0
  91. 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