apes 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.
Files changed (122) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +7 -0
  3. data/.rubocop.yml +82 -0
  4. data/.travis-gemfile +15 -0
  5. data/.travis.yml +15 -0
  6. data/.yardopts +1 -0
  7. data/CHANGELOG.md +3 -0
  8. data/Gemfile +22 -0
  9. data/README.md +177 -0
  10. data/Rakefile +44 -0
  11. data/apes.gemspec +34 -0
  12. data/doc/Apes.html +130 -0
  13. data/doc/Apes/Concerns.html +127 -0
  14. data/doc/Apes/Concerns/Errors.html +1089 -0
  15. data/doc/Apes/Concerns/Pagination.html +636 -0
  16. data/doc/Apes/Concerns/Request.html +766 -0
  17. data/doc/Apes/Concerns/Response.html +940 -0
  18. data/doc/Apes/Controller.html +1100 -0
  19. data/doc/Apes/Errors.html +125 -0
  20. data/doc/Apes/Errors/AuthenticationError.html +133 -0
  21. data/doc/Apes/Errors/BadRequestError.html +157 -0
  22. data/doc/Apes/Errors/BaseError.html +320 -0
  23. data/doc/Apes/Errors/InvalidDataError.html +157 -0
  24. data/doc/Apes/Errors/MissingDataError.html +157 -0
  25. data/doc/Apes/Model.html +378 -0
  26. data/doc/Apes/PaginationCursor.html +2138 -0
  27. data/doc/Apes/RuntimeConfiguration.html +909 -0
  28. data/doc/Apes/Serializers.html +125 -0
  29. data/doc/Apes/Serializers/JSON.html +389 -0
  30. data/doc/Apes/Serializers/JWT.html +452 -0
  31. data/doc/Apes/Serializers/List.html +347 -0
  32. data/doc/Apes/UrlsParser.html +1432 -0
  33. data/doc/Apes/Validators.html +125 -0
  34. data/doc/Apes/Validators/BaseValidator.html +278 -0
  35. data/doc/Apes/Validators/BooleanValidator.html +494 -0
  36. data/doc/Apes/Validators/EmailValidator.html +350 -0
  37. data/doc/Apes/Validators/PhoneValidator.html +375 -0
  38. data/doc/Apes/Validators/ReferenceValidator.html +372 -0
  39. data/doc/Apes/Validators/TimestampValidator.html +640 -0
  40. data/doc/Apes/Validators/UuidValidator.html +372 -0
  41. data/doc/Apes/Validators/ZipCodeValidator.html +372 -0
  42. data/doc/Apes/Version.html +189 -0
  43. data/doc/ApplicationController.html +547 -0
  44. data/doc/Concerns.html +128 -0
  45. data/doc/Concerns/ErrorHandling.html +826 -0
  46. data/doc/Concerns/PaginationHandling.html +463 -0
  47. data/doc/Concerns/RequestHandling.html +512 -0
  48. data/doc/Concerns/ResponseHandling.html +579 -0
  49. data/doc/Errors.html +126 -0
  50. data/doc/Errors/AuthenticationError.html +123 -0
  51. data/doc/Errors/BadRequestError.html +147 -0
  52. data/doc/Errors/BaseError.html +289 -0
  53. data/doc/Errors/InvalidDataError.html +147 -0
  54. data/doc/Errors/MissingDataError.html +147 -0
  55. data/doc/Model.html +315 -0
  56. data/doc/PaginationCursor.html +764 -0
  57. data/doc/Serializers.html +126 -0
  58. data/doc/Serializers/JSON.html +253 -0
  59. data/doc/Serializers/JWT.html +253 -0
  60. data/doc/Serializers/List.html +245 -0
  61. data/doc/Validators.html +126 -0
  62. data/doc/Validators/BaseValidator.html +209 -0
  63. data/doc/Validators/BooleanValidator.html +391 -0
  64. data/doc/Validators/EmailValidator.html +298 -0
  65. data/doc/Validators/PhoneValidator.html +313 -0
  66. data/doc/Validators/ReferenceValidator.html +284 -0
  67. data/doc/Validators/TimestampValidator.html +476 -0
  68. data/doc/Validators/UuidValidator.html +310 -0
  69. data/doc/Validators/ZipCodeValidator.html +310 -0
  70. data/doc/_index.html +435 -0
  71. data/doc/class_list.html +58 -0
  72. data/doc/css/common.css +1 -0
  73. data/doc/css/full_list.css +57 -0
  74. data/doc/css/style.css +339 -0
  75. data/doc/file.README.html +252 -0
  76. data/doc/file_list.html +60 -0
  77. data/doc/frames.html +26 -0
  78. data/doc/index.html +252 -0
  79. data/doc/js/app.js +219 -0
  80. data/doc/js/full_list.js +181 -0
  81. data/doc/js/jquery.js +4 -0
  82. data/doc/method_list.html +615 -0
  83. data/doc/top-level-namespace.html +112 -0
  84. data/lib/apes.rb +40 -0
  85. data/lib/apes/concerns/errors.rb +111 -0
  86. data/lib/apes/concerns/pagination.rb +81 -0
  87. data/lib/apes/concerns/request.rb +237 -0
  88. data/lib/apes/concerns/response.rb +74 -0
  89. data/lib/apes/controller.rb +77 -0
  90. data/lib/apes/errors.rb +38 -0
  91. data/lib/apes/model.rb +94 -0
  92. data/lib/apes/pagination_cursor.rb +152 -0
  93. data/lib/apes/runtime_configuration.rb +80 -0
  94. data/lib/apes/serializers.rb +88 -0
  95. data/lib/apes/urls_parser.rb +233 -0
  96. data/lib/apes/validators.rb +234 -0
  97. data/lib/apes/version.rb +24 -0
  98. data/spec/apes/concerns/errors_spec.rb +141 -0
  99. data/spec/apes/concerns/pagination_spec.rb +114 -0
  100. data/spec/apes/concerns/request_spec.rb +244 -0
  101. data/spec/apes/concerns/response_spec.rb +79 -0
  102. data/spec/apes/controller_spec.rb +54 -0
  103. data/spec/apes/errors_spec.rb +14 -0
  104. data/spec/apes/models_spec.rb +148 -0
  105. data/spec/apes/pagination_cursor_spec.rb +113 -0
  106. data/spec/apes/runtime_configuration_spec.rb +100 -0
  107. data/spec/apes/serializers_spec.rb +70 -0
  108. data/spec/apes/urls_parser_spec.rb +150 -0
  109. data/spec/apes/validators_spec.rb +237 -0
  110. data/spec/spec_helper.rb +30 -0
  111. data/views/_included.json.jbuilder +9 -0
  112. data/views/_pagination.json.jbuilder +9 -0
  113. data/views/collection.json.jbuilder +4 -0
  114. data/views/errors/400.json.jbuilder +9 -0
  115. data/views/errors/403.json.jbuilder +7 -0
  116. data/views/errors/404.json.jbuilder +6 -0
  117. data/views/errors/422.json.jbuilder +19 -0
  118. data/views/errors/500.json.jbuilder +12 -0
  119. data/views/errors/501.json.jbuilder +7 -0
  120. data/views/layouts/general.json.jbuilder +36 -0
  121. data/views/object.json.jbuilder +4 -0
  122. metadata +262 -0
@@ -0,0 +1,74 @@
1
+ #
2
+ # This file is part of the apes gem. Copyright (C) 2016 and above Shogun <shogun@cowtech.it>.
3
+ # Licensed under the MIT license, which can be found at http://www.opensource.org/licenses/mit-license.php.
4
+ #
5
+
6
+ module Apes
7
+ module Concerns
8
+ # JSON API response handling module.
9
+ module Response
10
+ attr_accessor :included
11
+
12
+ # Returns the template to use to render a object.
13
+ #
14
+ # @param object [Object] The object to render.
15
+ # @return [String] The template to use.
16
+ def response_template_for(object)
17
+ return @object_template if @object_template
18
+ object = object.first if object.respond_to?(:first)
19
+ object.class.name.underscore.gsub("/", "_")
20
+ end
21
+
22
+ # Returns the metadata for the current response.
23
+ #
24
+ # @param default [Object] Fallback data if nothing is found.
25
+ # @return [HashWithIndifferentAccess|Object|Nil] The metadata for the current response.
26
+ def response_meta(default = nil)
27
+ @meta || default || HashWithIndifferentAccess.new
28
+ end
29
+
30
+ # Returns the data for the current response.
31
+ #
32
+ # @param default [Object] Fallback data if nothing is found.
33
+ # @return [HashWithIndifferentAccess|Object|Nil] The data for the current response.
34
+ def response_data(default = nil)
35
+ @data || default || HashWithIndifferentAccess.new
36
+ end
37
+
38
+ # Returns the linked objects for the current response.
39
+ #
40
+ # @param default [Object] Fallback data if nothing is found.
41
+ # @return [HashWithIndifferentAccess|Object|Nil] The linked objects for the current response.
42
+ def response_links(default = nil)
43
+ @links || default || HashWithIndifferentAccess.new
44
+ end
45
+
46
+ # Returns the included (side-loaded) objects for the current response.
47
+ #
48
+ # @param default [Object] Fallback data if nothing is found.
49
+ # @return [HashWithIndifferentAccess|Object|Nil] The included objects for the current response.
50
+ def response_included(default = nil)
51
+ controller.included || default || HashWithIndifferentAccess.new
52
+ end
53
+
54
+ # Adds an object to the included (side-load) set.
55
+ #
56
+ # @param object [Object] The object to include.
57
+ # @param template [String] The template to use for rendering.
58
+ # @return [HashWithIndifferentAccess] A hash of objects to include. Keys are a template:id formatted strings, values are `[object, template]` pairs.
59
+ def response_include(object, template = nil)
60
+ controller.included ||= HashWithIndifferentAccess.new
61
+ controller.included[sprintf("%s:%s", response_template_for(object), object.to_param)] = [object, template]
62
+ controller.included
63
+ end
64
+
65
+ # Serializes a timestamp.
66
+ #
67
+ # @param timestamp [DateTime] The timestamp to serialize.
68
+ # @return [String] The serialized timestamp.
69
+ def response_timestamp(timestamp)
70
+ timestamp.safe_send(:strftime, "%FT%T.%L%z")
71
+ end
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,77 @@
1
+ #
2
+ # This file is part of the apes gem. Copyright (C) 2016 and above Shogun <shogun@cowtech.it>.
3
+ # Licensed under the MIT license, which can be found at http://www.opensource.org/licenses/mit-license.php.
4
+ #
5
+
6
+ module Apes
7
+ # A ready to use controller for JSON API applications.
8
+ #
9
+ # @attribute [r] current_account
10
+ # @return [Object] The current account making the request
11
+ # @attribute [r] cursor
12
+ # @return [Apes::PaginationCursor] The pagination cursor for this request.
13
+ # @attribute [r] request_cursor
14
+ # @return [Apes::PaginationCursor] The original pagination cursor sent from the client.
15
+ class Controller < ActionController::API
16
+ include ActionController::ImplicitRender
17
+ include ActionView::Layouts
18
+ include Apes::Concerns::Request
19
+ include Apes::Concerns::Response
20
+ include Apes::Concerns::Pagination
21
+ include Apes::Concerns::Errors
22
+
23
+ layout "general"
24
+ before_filter :request_handle_cors
25
+ before_filter :request_validate
26
+
27
+ attr_reader :current_account, :cursor, :request_cursor
28
+
29
+ # Exception handling
30
+ rescue_from Exception, with: :error_handle_exception
31
+ # This allows to avoid to declare all the views
32
+ rescue_from ActionView::MissingTemplate, with: :render_default_views
33
+
34
+ # Returns the default URL options for this request.
35
+ # It ensures that the host is always included and that is set properly in development mode.
36
+ #
37
+ # @return [Hash] Default URL options for the request.
38
+ def default_url_options
39
+ rv = {only_path: false}
40
+ rv = {host: request_source_host} if Apes::RuntimeConfiguration.development?
41
+ rv
42
+ end
43
+
44
+ # Tiny handle to handle CORS OPTIONS requests. It just renders nothing as headers are handle in Apes::Concerns::Response module.
45
+ #
46
+ # To enable this route, add the following to the routes.rb:
47
+ #
48
+ # # This is to enable AJAX cross domain
49
+ # match '*path', to: 'application#handle_cors', via: :options
50
+ def handle_cors
51
+ render(nothing: true, status: :no_content)
52
+ end
53
+
54
+ # Default handler to render errors.
55
+ #
56
+ # @param status [Symbol|Fixnum] The HTTP error code to return.
57
+ # @param errors [Array] The list of occurred errors.
58
+ def render_error(status, errors)
59
+ @errors = errors
60
+ status_code = status.is_a?(Fixnum) ? status : Rack::Utils::SYMBOL_TO_STATUS_CODE.fetch(status.to_sym, 500)
61
+ render("errors/#{status_code}", status: status)
62
+ end
63
+
64
+ private
65
+
66
+ # :nodoc:
67
+ def render_default_views(exception)
68
+ if defined?(@objects)
69
+ render "/collection"
70
+ elsif defined?(@object)
71
+ render "/object"
72
+ else
73
+ error_handle_exception(exception)
74
+ end
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,38 @@
1
+ #
2
+ # This file is part of the apes gem. Copyright (C) 2016 and above Shogun <shogun@cowtech.it>.
3
+ # Licensed under the MIT license, which can be found at http://www.opensource.org/licenses/mit-license.php.
4
+ #
5
+
6
+ module Apes
7
+ # Error used by the framework.
8
+ module Errors
9
+ # The base error.
10
+ class BaseError < RuntimeError
11
+ attr_reader :details
12
+
13
+ # Creates a new error.
14
+ #
15
+ # @param details [Object] The details of this error.
16
+ def initialize(details = nil)
17
+ super("")
18
+ @details = details
19
+ end
20
+ end
21
+
22
+ # Error raised when the request is not compliant with JSON API specification.
23
+ class BadRequestError < BaseError
24
+ end
25
+
26
+ # Error raised when the sent data is not valid.
27
+ class InvalidDataError < BaseError
28
+ end
29
+
30
+ # Error raised when the sent data is not missing.
31
+ class MissingDataError < BaseError
32
+ end
33
+
34
+ # Error raised when provided authentication is invalid.
35
+ class AuthenticationError < RuntimeError
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,94 @@
1
+ #
2
+ # This file is part of the apes gem. Copyright (C) 2016 and above Shogun <shogun@cowtech.it>.
3
+ # Licensed under the MIT license, which can be found at http://www.opensource.org/licenses/mit-license.php.
4
+ #
5
+
6
+ module Apes
7
+ # Some utility extensions to ActiveModel.
8
+ module Model
9
+ extend ActiveSupport::Concern
10
+
11
+ class_methods do
12
+ # Find a object by using the UUID, a handle or model specific definitions (defined using SECONDARY_KEY or SECONDARY_QUERY constants).
13
+ # Raise exception when nothing is found.
14
+ #
15
+ # @param id [Object] The value to find.
16
+ # @return [Object] The first found model.
17
+ def find_with_any!(id)
18
+ if id =~ Validators::UuidValidator::VALID_REGEX
19
+ find(id)
20
+ elsif defined?(self::SECONDARY_KEY)
21
+ find_by!(self::SECONDARY_KEY => id)
22
+ elsif defined?(self::SECONDARY_QUERY)
23
+ find_by!(self::SECONDARY_QUERY, {id: id})
24
+ else
25
+ find_by!(handle: id)
26
+ end
27
+ end
28
+
29
+ # Find a object by using the UUID, a handle or model specific definitions (defined using SECONDARY_KEY or SECONDARY_QUERY constants).
30
+ #
31
+ # @param id [Object] The value to find.
32
+ # @return [Object] The first found model.
33
+ def find_with_any(id)
34
+ find_with_any!(id)
35
+ rescue ActiveRecord::RecordNotFound
36
+ nil
37
+ end
38
+
39
+ # Performs a search on the model.
40
+ #
41
+ # @param params [Hash] The list of params for the query.
42
+ # @param query [ActiveRecord::Relation|NilClass] A model query to further scope, if any.
43
+ # @param fields [Array] The model fields where to perform search on.
44
+ # @param start_only [Boolean] Whether only match that starts with the searched value rather than just containing it.
45
+ # @param parameter [Symbol|NilClass] The field in `params` which contains the value to search. Will fallback to `params[:filter][:query]` (using `.dig`).
46
+ # @param placeholder [Symbol] The placeholder to use in prepared statement. Useful to avoid collisions. Default is `query`.
47
+ # @param method [Symbol] The operator to use for searching. Everything different from `or` will fallback to `and`.
48
+ # @param case_sensitive [Boolean] Whether to perform case sensitive search. Default is `false`.
49
+ # @return [ActiveRecord::Relation] A query relation object.
50
+ def search(params: {}, query: nil, fields: ["name"], start_only: false, parameter: nil, placeholder: :query, method: :or, case_sensitive: false)
51
+ query ||= where({})
52
+ value = parameter ? params[parameter] : params.dig(:filter, :query)
53
+ return query if value.blank?
54
+
55
+ value = "#{value}%"
56
+ value = "%#{value}" unless start_only
57
+
58
+ method = method.to_s == "or" ? " OR " : " AND "
59
+ operator = case_sensitive ? "LIKE" : "ILIKE"
60
+
61
+ sql = fields.map { |f| "#{f} #{operator} :#{placeholder}" }.join(method)
62
+ query.where(sql, {placeholder => value})
63
+ end
64
+ end
65
+
66
+ # A list of manually managed errors for the model.
67
+ #
68
+ # @return [ActiveModel::Errors] A list of manually managed errors for the model.
69
+ def additional_errors
70
+ @additional_errors ||= ActiveModel::Errors.new(self)
71
+ end
72
+
73
+ # Perform validations on the model and makes sure manually added errors are included.
74
+ def run_validations!
75
+ errors.messages.merge!(additional_errors.messages)
76
+ super
77
+ end
78
+
79
+ # A list of automatically and manually added errors for the model.
80
+ #
81
+ # @return [ActiveModel::Errors] A list of automatically and manually added errors for the model.
82
+ def all_validation_errors
83
+ additional_errors.each do |field, error|
84
+ errors.add(field, error)
85
+ end
86
+
87
+ errors.each do |field|
88
+ errors[field].uniq!
89
+ end
90
+
91
+ errors
92
+ end
93
+ end
94
+ end
@@ -0,0 +1,152 @@
1
+ #
2
+ # This file is part of the apes gem. Copyright (C) 2016 and above Shogun <shogun@cowtech.it>.
3
+ # Licensed under the MIT license, which can be found at http://www.opensource.org/licenses/mit-license.php.
4
+ #
5
+
6
+ module Apes
7
+ # A cursor that can be sent to the client, received unmodified and retrieved later to paginate results.
8
+ #
9
+ # @attribute value
10
+ # @return [String] The value obtain from previous pagination. It can either be the value of the first or last element in previous iteration.
11
+ # @attribute use_offset
12
+ # @return [Boolean] Whether to use offset based pagination rather than collection fields values.
13
+ # @attribute direction
14
+ # @return [IO|String] Which page to get in this iteration.
15
+ # @attribute size
16
+ # @return [IO|String] The size of the pagination page.
17
+ class PaginationCursor
18
+ # The default size of a pagination page.
19
+ DEFAULT_SIZE = 25
20
+
21
+ # Format to serialize timestamp when using them for pagination.
22
+ TIMESTAMP_FORMAT = "%FT%T.%6N%z".freeze
23
+
24
+ attr_accessor :value, :use_offset, :direction, :size
25
+
26
+ # Creates a new cursor.
27
+ #
28
+ # @param params [Hash] The request parameters.
29
+ # @param field [Symbol] The parameters field where to lookup for the serialized cursor.
30
+ # @param count_field [Symbol] The parameters field where to lookup for the overriding cursor size.
31
+ # @return [Apes::PaginationCursor] A new cursor instance.
32
+ def initialize(params = {}, field = :page, count_field = :count)
33
+ begin
34
+ payload = JWT.decode(params[field], jwt_secret, true, {algorithm: "HS256", verify_aud: true, aud: "pagination"}).dig(0, "sub")
35
+
36
+ extract_payload(payload)
37
+ rescue
38
+ default_payload
39
+ end
40
+
41
+ # Sanitization
42
+ sanitize(count_field, params)
43
+ end
44
+
45
+ # Get the operator (`>` or `<`) for the query according to the direction and the provided ordering.
46
+ #
47
+ # @param order [Symbol] The order to use.
48
+ # @return [String] The operator to use for the query.
49
+ def operator(order)
50
+ if direction == "next"
51
+ order == :asc ? ">" : "<" # Descending order means newer results first
52
+ else
53
+ order == :asc ? "<" : ">" # Descending order means newer results first
54
+ end
55
+ end
56
+
57
+ # Verifies whether a specific page might exist for the given collection.
58
+ #
59
+ # @param page [String] The page to check. It can be `first`, `next`, `prev` or `previous`.
60
+ # @param collection [Enumerable] The collection to analyze.
61
+ # @return [Boolean] Returns `true` if the page might exist for the collection, `false` otherwise.
62
+ def might_exist?(page, collection)
63
+ case page.to_s
64
+ when "first" then true
65
+ when "next" then collection.present?
66
+ else value.present? && collection.present? # Previous
67
+ end
68
+ end
69
+
70
+ # Serializes the cursor to send it to the client.
71
+ #
72
+ # @param collection [Enumerable] The collection to analyze.
73
+ # @param page [String] The page to return. It can be `first`, `next`, `prev` or `previous`.
74
+ # @param field [Symbol] When not using offset based pagination, the field to consider for generation.
75
+ # @param size [Fixnum] The number of results to advance when using offset based pagination.
76
+ # @param use_offset [Boolean] Whether to use offset based pagination.
77
+ # @return [String] The serialized cursor.
78
+ def save(collection, page, field: :id, size: nil, use_offset: nil)
79
+ size ||= self.size
80
+ use_offset = self.use_offset if use_offset.nil?
81
+ direction, value = use_offset ? update_with_offset(page, size) : update_with_field(page, collection, field)
82
+
83
+ value = value.strftime(TIMESTAMP_FORMAT) if value.respond_to?(:strftime)
84
+
85
+ JWT.encode({aud: "pagination", sub: {value: value, use_offset: use_offset, direction: direction, size: size}}, jwt_secret, "HS256")
86
+ end
87
+ alias_method :serialize, :save
88
+
89
+ private
90
+
91
+ # :nodoc:
92
+ def default_payload
93
+ @value = nil
94
+ @direction = "next"
95
+ @size = 0
96
+ @use_offset = false
97
+ end
98
+
99
+ # :nodoc:
100
+ def extract_payload(payload)
101
+ @value = payload["value"]
102
+ @direction = payload["direction"]
103
+ @size = payload["size"]
104
+ @use_offset = payload["use_offset"]
105
+ end
106
+
107
+ # :nodoc:
108
+ def sanitize(count_field, params)
109
+ @direction = "next" unless ["prev", "previous"].include?(@direction)
110
+ @size = params[count_field].to_integer if params[count_field].present?
111
+ @size = DEFAULT_SIZE if @size < 1
112
+ end
113
+
114
+ # :nodoc:
115
+ def update_with_field(type, collection, field)
116
+ case type.ensure_string
117
+ when "next"
118
+ direction = "next"
119
+ value = collection.last&.send(field)
120
+ when "prev", "previous"
121
+ direction = "previous"
122
+ value = collection.first&.send(field)
123
+ else # first
124
+ direction = "next"
125
+ value = nil
126
+ end
127
+
128
+ [direction, value]
129
+ end
130
+
131
+ # :nodoc:
132
+ def update_with_offset(type, size)
133
+ case type.ensure_string
134
+ when "next"
135
+ direction = "next"
136
+ value = self.value + size
137
+ when "prev", "previous"
138
+ direction = "previous"
139
+ value = [0, self.value - size].max
140
+ else # first
141
+ direction = "next"
142
+ value = nil
143
+ end
144
+
145
+ [direction, value]
146
+ end
147
+
148
+ def jwt_secret
149
+ Apes::RuntimeConfiguration.jwt_token
150
+ end
151
+ end
152
+ end
@@ -0,0 +1,80 @@
1
+ #
2
+ # This file is part of the apes gem. Copyright (C) 2016 and above Shogun <shogun@cowtech.it>.
3
+ # Licensed under the MIT license, which can be found at http://www.opensource.org/licenses/mit-license.php.
4
+ #
5
+
6
+ module Apes
7
+ # Internal class to handle runtime configuration.
8
+ class RuntimeConfiguration
9
+ class << self
10
+ # Returns the root directory of apes.
11
+ # @return [String]
12
+ def root
13
+ Pathname.new(Gem.loaded_specs["apes"].full_gem_path).to_s
14
+ end
15
+
16
+ # Returns the current Rails root directory.
17
+ #
18
+ # @param default [String] The fallback if Rails configuration is invalid.
19
+ # @return [String] The current Rails root directory.
20
+ def rails_root(default = nil)
21
+ fetch_with_fallback(default) { Rails.root.to_s }
22
+ end
23
+
24
+ # Returns the current RubyGems root directory.
25
+ #
26
+ # @param default [String] The fallback if RubyGems configuration is invalid.
27
+ # @return [String] The current RubyGems root directory.
28
+ def gems_root(default = nil)
29
+ fetch_with_fallback(default) { Pathname.new(Gem.loaded_specs["lazier"].full_gem_path).parent.to_s }
30
+ end
31
+
32
+ # Returns the current Rails environment.
33
+ #
34
+ # @param default [String] The fallback environment if Rails configuration is invalid.
35
+ # @return [String] The the current Rails environment.
36
+ def environment(default = "development")
37
+ fetch_with_fallback(default) { Rails.env }
38
+ end
39
+
40
+ # Check if Rails is in development environment.
41
+ #
42
+ # @return [Boolean] `true` if Rails is in `development` environment, `false` otherwise.
43
+ def development?
44
+ environment == "development"
45
+ end
46
+
47
+ # Returns the JWT token used by Apes. This should be defined in the Rails secrets.yml file.
48
+ #
49
+ # @param default [String] The fallback if no valid secret is found in Rails secrets file.
50
+ # @return [String] The JWT token used by Apes.
51
+ def jwt_token(default = "secret")
52
+ fetch_with_fallback(default) { Rails.application.secrets.jwt }
53
+ end
54
+
55
+ # Returns the CORS source used by Apes. This should be defined in the Rails secrets.yml file.
56
+ #
57
+ # @param default [String] The fallback if no valid CORS source is found in Rails secrets file.
58
+ # @return [String] The CORS source used by Apes.
59
+ def cors_source(default = "localhost")
60
+ fetch_with_fallback(default) { Rails.application.secrets.cors_source }
61
+ end
62
+
63
+ # Returns a map where keys are tags and values are strftime compliant formats.
64
+ #
65
+ # @param default [String] The fallback if no valid configuration is found in Rails.
66
+ # @return [Hash] A object describing valid timestamps formats.
67
+ def timestamp_formats(default = {})
68
+ fetch_with_fallback(default) { Rails.application.config.timestamp_formats }
69
+ end
70
+
71
+ private
72
+
73
+ def fetch_with_fallback(default)
74
+ yield
75
+ rescue
76
+ default
77
+ end
78
+ end
79
+ end
80
+ end