# frozen_string_literal: true module Stripe module APIOperations # Adds methods to help manipulate a subresource from its parent resource so # that it's possible to do so from a static context (i.e. without a # pre-existing collection of subresources on the parent). # # For example, a transfer gains the static methods for reversals so that the # methods `.create_reversal`, `.retrieve_reversal`, `.update_reversal`, # etc. all become available. module NestedResource def nested_resource_class_methods(resource, path: nil, operations: nil, resource_plural: nil) resource_plural ||= "#{resource}s" path ||= resource_plural raise ArgumentError, "operations array required" if operations.nil? resource_url_method = :"#{resource}s_url" define_singleton_method(resource_url_method) do |id, nested_id = nil| url = "#{resource_url}/#{CGI.escape(id)}/#{CGI.escape(path)}" url += "/#{CGI.escape(nested_id)}" unless nested_id.nil? url end operations.each do |operation| define_operation( resource, operation, resource_url_method, resource_plural ) end end # rubocop:disable Metrics/MethodLength private def define_operation( resource, operation, resource_url_method, resource_plural ) case operation when :create define_singleton_method(:"create_#{resource}") \ do |id, params = {}, opts = {}| request_stripe_object( method: :post, path: send(resource_url_method, id), params: params, opts: opts ) end when :retrieve # TODO: (Major) Split params_or_opts to params and opts and get rid of the complicated way to add params define_singleton_method(:"retrieve_#{resource}") \ do |id, nested_id, params_or_opts = {}, definitely_opts = nil| opts = nil params = nil if definitely_opts.nil? unrecognized_key = params_or_opts.keys.find { |k| !Util::OPTS_USER_SPECIFIED.include?(k) } if unrecognized_key raise ArgumentError, "Unrecognized request option: #{unrecognized_key}. Did you mean to specify this as " \ "retrieve params? " \ "If so, you must explicitly pass an opts hash as a fourth argument. " \ "For example: .retrieve(#{id}, #{nested_id}, {#{unrecognized_key}: 'foo'}, {})" end opts = params_or_opts else opts = definitely_opts params = params_or_opts end request_stripe_object( method: :get, path: send(resource_url_method, id, nested_id), params: params, opts: opts ) end when :update define_singleton_method(:"update_#{resource}") \ do |id, nested_id, params = {}, opts = {}| request_stripe_object( method: :post, path: send(resource_url_method, id, nested_id), params: params, opts: opts ) end when :delete define_singleton_method(:"delete_#{resource}") \ do |id, nested_id, params = {}, opts = {}| request_stripe_object( method: :delete, path: send(resource_url_method, id, nested_id), params: params, opts: opts ) end when :list define_singleton_method(:"list_#{resource_plural}") \ do |id, params = {}, opts = {}| request_stripe_object( method: :get, path: send(resource_url_method, id), params: params, opts: opts ) end else raise ArgumentError, "Unknown operation: #{operation.inspect}" end end # rubocop:enable Metrics/MethodLength end end end