module Bearcat class Client < Footrest::Client module ClientModule ARG_REGEX = /:(\w+)/ attr_reader :_registered_endpoints def prefix(prefix) past_prefix = @current_prefix @current_prefix = (past_prefix || '') + prefix yield ensure @current_prefix = past_prefix end def endpoint(method, identifier, url = "", defaults: {}, &blk) if @current_prefix && !url.start_with?('/') url = url[2..-1] if url.start_with?('./') url = @current_prefix + url end args = url.to_enum(:scan, ARG_REGEX).map { Regexp.last_match } arg_names = args.map{|m| m[1]} @_registered_endpoints ||= {} @_registered_endpoints[identifier] = { symbol: identifier, method: method, url: url } # TODO: Consider generating the method using class_eval and a template - this will improve runtime performance # signature_bits = [] # logical_bits = [] # args.each do |m| # name = [1] # end # interpolated_url = url.gsub(ARG_REGEX) do |m| # '#{' + m[1] + '}' # end # class_eval <<~RUBY # def #{identifier}(*args, **kwargs) # parameters = { # } # #{method}(#{interpolated_url}) # end # RUBY define_method(identifier) do |*args, **kwargs| url_arguments = {} parameters = { }.with_indifferent_access parameters.merge!(defaults) args.each_with_index do |v, i| if arg_names[i] url_arguments[arg_names[i]] = v elsif i == arg_names.count && v.is_a?(Hash) parameters.merge!(v) else raise ArgumentError, "Too many arguments passed to #{identifier}" unless arg_names[i] end end parameters.merge!(kwargs) preq = BearcatRequest.new(url, url_arguments, parameters) yield preq if block_given? arg_names.each do |an| preq.arguments[an] = preq.parameters.delete(an) unless preq.arguments.key?(an) raise ArgumentError, "Missing argument #{an}" unless preq.arguments.key?(an) end send(method, preq.interpoated_url, preq.parameters) end end def context_types(types, &blk) types.each(&blk) end %i[get post delete put patch head].each do |mthd| define_method(mthd) do |*args, **kwargs, &blk| endpoint(mthd, *args, **kwargs, &blk) end end BearcatRequest = Struct.new(:url, :arguments, :parameters) do def interpoated_url url.gsub(ARG_REGEX) do |_| m = Regexp.last_match val = arguments[m[1]] val = val.canvas_id if val.respond_to?(:canvas_id) val = val.id if val.respond_to?(:id) val = val['id'].presence || val[:id].presence || val if val.is_a?(Hash) val end end end end end end