<commit_before># API builder factory - calls API definitions to run controller, generate docs, etc

require 'recursive-open-struct'
require 'active_support/json'

module Flappi
  module BuilderFactory

    extend Flappi::Utils::ParamTypes

    # When we run code during a documentation pass, stub everything

    class DocumentingStub
      def to_ary
        return [DocumentingStub.new]
      end

      def method_missing(_meth_id, *_args, &_block)
        # puts "Note: #{_meth_id.id2name} missing, called from stub"
        return DocumentingStub.new
      end

      def self.method_missing(_meth_id, *_args, &_block)
        # puts "Note: class.#{_meth_id.id2name} missing, called from stub"
        return DocumentingStub.new
      end
    end

    class DefDocumenter
      def method_missing(_meth_id, *_args, &_block)
        # puts "Note: #{_meth_id.id2name} missing"
        return DocumentingStub.new
      end
    end

    # Call me from a controller to build the appropriate API response
    # and return it
    def self.build_and_respond(controller)
      endpoint_name = controller.class.name.match(/(?:::)?(\w+)Controller$/).captures.first
      full_version = controller.params[:version]

      definition_klass = DefinitionLocator.locate_class(endpoint_name)
      raise "Endpoint #{endpoint_name} is not defined to Flappi" unless definition_klass

      Rails.logger.debug "  definition_klass = #{definition_klass}" if defined?(Rails)

      controller.singleton_class.send(:include, definition_klass)
      controller.defining_class = definition_klass
      controller.mode = :response
      controller.controller_params = controller.params  # Give the mixin access to params
      controller.controller_query_parameters = controller.request.query_parameters.except(:access_token)
      controller.controller_url = controller.request.url
      Flappi::Utils::Logger.i "controller.request.url=#{controller.request.url}"
      controller.version_plan = Flappi.configuration.version_plan

      controller.endpoint    # init endpoint data from mixin

      unless endpoint_name == controller.endpoint_simple_name
        raise "BuilderFactory::build_and_respond config issue: controller defines endpoint as #{endpoint_name} and response object as #{controller.endpoint_simple_name}"
      end

      if Flappi.configuration.version_plan
        raise "BuilderFactory::build_and_respond has a version plan #{Flappi.configuration.version_plan} so needs a version from the router" unless full_version

        endpoint_supported_versions = controller.supported_versions
        Rails.logger.debug "  Does endpoint support #{full_version} in #{endpoint_supported_versions}?" if defined?(Rails)
        normalised_version = Flappi.configuration.version_plan.parse_version(full_version).normalise
        unless endpoint_supported_versions.include? normalised_version
          msg = "Version #{full_version} not supported by endpoint"
          Flappi::Utils::Logger.w msg
          controller.render json: { error: msg }.to_json, text: msg, status: :not_acceptable
          return false
        end

        controller.requested_version = normalised_version
      end

      # Merge in default values where one is defined and we don't have an actual parameter
      controller.params.merge! Hash[controller.endpoint_info[:params].select do |defined_param|
        !controller.params.key?(defined_param[:name]) && defined_param[:default]
      end.
      map do |defined_param|
        [defined_param[:name], defined_param[:default]]
      end]

      Flappi::Utils::Logger.d "After default params=#{controller.params}"<commit_msg>Set default value also when param was set to nil or empty string<commit_after># API builder factory - calls API definitions to run controller, generate docs, etc

require 'recursive-open-struct'
require 'active_support/json'

module Flappi
  module BuilderFactory

    extend Flappi::Utils::ParamTypes

    # When we run code during a documentation pass, stub everything

    class DocumentingStub
      def to_ary
        return [DocumentingStub.new]
      end

      def method_missing(_meth_id, *_args, &_block)
        # puts "Note: #{_meth_id.id2name} missing, called from stub"
        return DocumentingStub.new
      end

      def self.method_missing(_meth_id, *_args, &_block)
        # puts "Note: class.#{_meth_id.id2name} missing, called from stub"
        return DocumentingStub.new
      end
    end

    class DefDocumenter
      def method_missing(_meth_id, *_args, &_block)
        # puts "Note: #{_meth_id.id2name} missing"
        return DocumentingStub.new
      end
    end

    # Call me from a controller to build the appropriate API response
    # and return it
    def self.build_and_respond(controller)
      endpoint_name = controller.class.name.match(/(?:::)?(\w+)Controller$/).captures.first
      full_version = controller.params[:version]

      definition_klass = DefinitionLocator.locate_class(endpoint_name)
      raise "Endpoint #{endpoint_name} is not defined to Flappi" unless definition_klass

      Rails.logger.debug "  definition_klass = #{definition_klass}" if defined?(Rails)

      controller.singleton_class.send(:include, definition_klass)
      controller.defining_class = definition_klass
      controller.mode = :response
      controller.controller_params = controller.params  # Give the mixin access to params
      controller.controller_query_parameters = controller.request.query_parameters.except(:access_token)
      controller.controller_url = controller.request.url
      Flappi::Utils::Logger.i "controller.request.url=#{controller.request.url}"
      controller.version_plan = Flappi.configuration.version_plan

      controller.endpoint    # init endpoint data from mixin

      unless endpoint_name == controller.endpoint_simple_name
        raise "BuilderFactory::build_and_respond config issue: controller defines endpoint as #{endpoint_name} and response object as #{controller.endpoint_simple_name}"
      end

      if Flappi.configuration.version_plan
        raise "BuilderFactory::build_and_respond has a version plan #{Flappi.configuration.version_plan} so needs a version from the router" unless full_version

        endpoint_supported_versions = controller.supported_versions
        Rails.logger.debug "  Does endpoint support #{full_version} in #{endpoint_supported_versions}?" if defined?(Rails)
        normalised_version = Flappi.configuration.version_plan.parse_version(full_version).normalise
        unless endpoint_supported_versions.include? normalised_version
          msg = "Version #{full_version} not supported by endpoint"
          Flappi::Utils::Logger.w msg
          controller.render json: { error: msg }.to_json, text: msg, status: :not_acceptable
          return false
        end

        controller.requested_version = normalised_version
      end

      # Merge in default values where one is defined and we don't have an actual parameter
      controller.params.merge! Hash[
        controller.endpoint_info[:params].select do |defined_param|
          param = controller.params.dig(defined_param[:name])
          (param.nil? || param == "") && defined_param[:default]
        end.map do |defined_param|
          [defined_param[:name], defined_param[:default]]
        end
      ]

      Flappi::Utils::Logger.d "After default params=#{controller.params}"
{'fraction_non_alphanumeric': 0.08196057250877667, 'fraction_numerical': 0.0008101539292465569, 'mean_word_length': 3.5497542997542997, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3803490', 'n_tokens_mistral': 1999, 'n_tokens_neox': 1961, 'n_words': 526}