require 'recursive-open-struct' class UWaterlooAPI class Query include UWaterlooAPI::Routes def initialize(cur_route, cur_url, api_key) @api_key = api_key @cur_url = cur_url @cur_route = cur_route @retrieved_url = '' @response = @meta = nil # Define methods without parameters get_next_routes_without_params.each do |route| self.class.send :define_method, route do raise NoMethodError unless is_in_routes?("#{@cur_route}/#{route}") UWaterlooAPI::Query.new "#{@cur_route}/#{route}", "#{@cur_url}/#{route}", @api_key end end # Define methods with parameters get_next_routes_with_params.each do |route| self.class.send :define_method, route do |value| raise ArgumentError if ["", 0].include? value raise NoMethodError unless is_in_routes?("#{@cur_route}/{#{route}}") UWaterlooAPI::Query.new "#{@cur_route}/{#{route}}", "#{@cur_url}/#{value}", @api_key end end end # Get meta variables def meta(var) raise NoMethodError unless is_full_route? @cur_route raise "No request has been made yet, so meta data is not available." unless @meta @meta[var.to_s] end # Get data from server def get raise NoMethodError unless is_full_route? @cur_route @retrieved_url = @cur_url response = HTTParty.get("https://api.uwaterloo.ca/v2#{@cur_url}.json", { query: { key: @api_key, format: 'json' } }) case response.code when 400...600 raise "UWaterloo API Server returned a #{response.code} error" end @response = RecursiveOpenStruct.new response, recurse_over_arrays: true @meta = response['meta'] @response.data end def method_missing(method, *args, &block) # Get data from API server get unless just_made_request if @response.data.respond_to? method @response.data.send method, *args, &block else super end end def respond_to?(method, include_private = false) # Get data from API server get unless just_made_request if @response.data.respond_to? method true else super end end private def just_made_request @retrieved_url == @cur_url end def get_next_routes @next_routes ||= @@routes. select { |s| s.start_with?(@cur_route) }. map { |s| s[@cur_route.length..-1] }. join.split('/').uniq.delete_if(&:empty?) end def get_next_routes_without_params @next_routes_without_params ||= get_next_routes. reject { |r| r =~ /^\{.*\}$/ }.map(&:to_sym) end def get_next_routes_with_params @next_routes_with_params ||= get_next_routes. select { |r| r =~ /^\{.*\}$/ }. map { |r| r.delete('{}') }.map(&:to_sym) end def is_in_routes?(substring) @@routes.any? { |s| s.start_with?(substring) } end def is_full_route?(substring) @@routes.include? substring end end end