<commit_before>module ActsAsTaggableOn::Taggable
  module Core
    def self.included(base)
      base.extend ActsAsTaggableOn::Taggable::Core::ClassMethods

      base.class_eval do
        attr_writer :custom_contexts
        after_save :save_tags
      end

      base.initialize_acts_as_taggable_on_core
    end

    module ClassMethods
      def initialize_acts_as_taggable_on_core
        include taggable_mixin
        tag_types.map(&:to_s).each do |tags_type|
          tag_type = tags_type.to_s.singularize
          context_taggings = "#{tag_type}_taggings".to_sym
          context_tags = tags_type.to_sym
          taggings_order = (preserve_tag_order? ? "#{ActsAsTaggableOn::Tagging.table_name}.id" : [])

          class_eval do
            # when preserving tag order, include order option so that for a 'tags' context
            # the associations tag_taggings & tags are always returned in created order
            has_many context_taggings, -> { includes(:tag).order(taggings_order).where(context: tags_type) },
                     as: :taggable,
                     class_name: ActsAsTaggableOn::Tagging,
                     dependent: :destroy

            has_many context_tags, -> { order(taggings_order) },
                     class_name: ActsAsTaggableOn::Tag,
                     through: context_taggings,
                     source: :tag
          end

          taggable_mixin.class_eval <<-RUBY, __FILE__, __LINE__ + 1
            def #{tag_type}_list
              tag_list_on('#{tags_type}')
            end

            def #{tag_type}_list=(new_tags)
              set_tag_list_on('#{tags_type}', new_tags)
            end

            def all_#{tags_type}_list
              all_tags_list_on('#{tags_type}')
            end
          RUBY
        end
      end

      def taggable_on(preserve_tag_order, *tag_types)
        super(preserve_tag_order, *tag_types)
        initialize_acts_as_taggable_on_core
      end

      # all column names are necessary for PostgreSQL group clause
      def grouped_column_names_for(object)
        object.column_names.map { |column| "#{object.table_name}.#{column}" }.join(', ')
      end

      ##
      # Return a scope of objects that are tagged with the specified tags.
      #
      # @param tags The tags that we want to query for
      # @param [Hash] options A hash of options to alter you query:
      #                       * <tt>:exclude</tt> - if set to true, return objects that are *NOT* tagged with the specified tags
      #                       * <tt>:any</tt> - if set to true, return objects that are tagged with *ANY* of the specified tags
      #                       * <tt>:order_by_matching_tag_count</tt> - if set to true and used with :any, sort by objects matching the most tags, descending
      #                       * <tt>:match_all</tt> - if set to true, return objects that are *ONLY* tagged with the specified tags
      #                       * <tt>:owned_by</tt> - return objects that are *ONLY* owned by the owner
      #                       * <tt>:start_at</tt> - Restrict the tags to those created after a certain time
      #                       * <tt>:end_at</tt> - Restrict the tags to those created before a certain time
      #
      # Example:
      #   User.tagged_with(["awesome", "cool"])                     # Users that are tagged with awesome and cool
      #   User.tagged_with(["awesome", "cool"], :exclude => true)   # Users that are not tagged with awesome or cool
      #   User.tagged_with(["awesome", "cool"], :any => true)       # Users that are tagged with awesome or cool
      #   User.tagged_with(["awesome", "cool"], :any => true, :order_by_matching_tag_count => true)  # Sort by users who match the most tags, descending
      #   User.tagged_with(["awesome", "cool"], :match_all => true) # Users that are tagged with just awesome and cool
      #   User.tagged_with(["awesome", "cool"], :owned_by => foo ) # Users that are tagged with just awesome and cool by 'foo'
      #   User.tagged_with(["awesome", "cool"], :owned_by => foo, :start_at => Date.today ) # Users that are tagged with just awesome, cool by 'foo' and starting today
      def tagged_with(tags, options = {})
        tag_list = ActsAsTaggableOn.default_parser.new(tags).parse
        options = options.dup
        empty_result = where('1 = 0')

        return empty_result if tag_list.empty?

        joins = []
        conditions = []
        having = []
        select_clause = []
        order_by = []

        context = options.delete(:on)
        owned_by = options.delete(:owned_by)
        alias_base_name = undecorated_table_name.gsub('.', '_')
        # FIXME use ActiveRecord's connection quote_column_name
        quote = ActsAsTaggableOn::Utils.using_postgresql? ? '"' : ''

        if options.delete(:exclude)
          if options.delete(:wild)
            tags_conditions = tag_list.map { |t| sanitize_sql(["#{ActsAsTaggableOn::Tag.table_name}.name #{ActsAsTaggableOn::Utils.like_operator} ? ESCAPE '!'", "%#{ActsAsTaggableOn::Utils.escape_like(t)}%"]) }.join(' OR ')
          else
            tags_conditions = tag_list.map { |t| sanitize_sql(["#{ActsAsTaggableOn::Tag.table_name}.name #{ActsAsTaggableOn::Utils.like_operator} ?", t]) }.join(' OR ')
          end

          conditions << "#{table_name}.#{primary_key} NOT IN (SELECT #{ActsAsTaggableOn::Tagging.table_name}.taggable_id FROM #{ActsAsTaggableOn::Tagging.table_name} JOIN #{ActsAsTaggableOn::Tag.table_name} ON #{ActsAsTaggableOn::Tagging.table_name}.tag_id = #{ActsAsTaggableOn::Tag.table_name}.#{ActsAsTaggableOn::Tag.primary_key} AND (#{tags_conditions}) WHERE #{ActsAsTaggableOn::Tagging.table_name}.taggable_type = #{quote_value(base_class.name, nil)})"

          if owned_by
            joins <<  "JOIN #{ActsAsTaggableOn::Tagging.table_name}" +
                      "  ON #{ActsAsTaggableOn::Tagging.table_name}.taggable_id = #{quote}#{table_name}#{quote}.#{primary_key}" +
                      " AND #{ActsAsTaggableOn::Tagging.table_name}.taggable_type = #{quote_value(base_class.name, nil)}" +
                      " AND #{ActsAsTaggableOn::Tagging.table_name}.tagger_id = #{quote_value(owned_by.id, nil)}" +
                      " AND #{ActsAsTaggableOn::Tagging.table_name}.tagger_type = #{quote_value(owned_by.class.base_class.to_s, nil)}"

            joins << " AND " + sanitize_sql(["#{ActsAsTaggableOn::Tagging.table_name}.created_at >= ?", options.delete(:start_at)]) if options[:start_at]
            joins << " AND " + sanitize_sql(["#{ActsAsTaggableOn::Tagging.table_name}.created_at <= ?", options.delete(:end_at)])   if options[:end_at]
          end

        elsif any = options.delete(:any)
          # get tags, drop out if nothing returned (we need at least one)
          tags = if options.delete(:wild)
                   ActsAsTaggableOn::Tag.named_like_any(tag_list)
                 else
                   ActsAsTaggableOn::Tag.named_any(tag_list)
                 end

          return empty_result if tags.length == 0

          # setup taggings alias so we can chain, ex: items_locations_taggings_awesome_cool_123
          # avoid ambiguous column name
          taggings_context = context ? "_#{context}" : ''

          taggings_alias = adjust_taggings_alias(
              "#{alias_base_name[0..4]}#{taggings_context[0..6]}_taggings_#{ActsAsTaggableOn::Utils.sha_prefix(tags.map(&:name).join('_'))}"
          )

          tagging_cond = "#{ActsAsTaggableOn::Tagging.table_name} #{taggings_alias}" +
                          " WHERE #{taggings_alias}.taggable_id = #{quote}#{table_name}#{quote}.#{primary_key}" +
                          " AND #{taggings_alias}.taggable_type = #{quote_value(base_class.name, nil)}"

          tagging_cond << " AND " + sanitize_sql(["#{taggings_alias}.created_at >= ?", options.delete(:start_at)]) if options[:start_at]
          tagging_cond << " AND " + sanitize_sql(["#{taggings_alias}.created_at <= ?", options.delete(:end_at)])   if options[:end_at]

          tagging_cond << " AND " + sanitize_sql(["#{taggings_alias}.context = ?", context.to_s]) if context

          # don't need to sanitize sql, map all ids and join with OR logic
          tag_ids = tags.map { |t| quote_value(t.id, nil) }.join(', ')
          tagging_cond << " AND #{taggings_alias}.tag_id in (#{tag_ids})"
          select_clause << " #{table_name}.*" unless context and tag_types.one?
<commit_msg>:warning: assigned but unused variable - any<commit_after>module ActsAsTaggableOn::Taggable
  module Core
    def self.included(base)
      base.extend ActsAsTaggableOn::Taggable::Core::ClassMethods

      base.class_eval do
        attr_writer :custom_contexts
        after_save :save_tags
      end

      base.initialize_acts_as_taggable_on_core
    end

    module ClassMethods
      def initialize_acts_as_taggable_on_core
        include taggable_mixin
        tag_types.map(&:to_s).each do |tags_type|
          tag_type = tags_type.to_s.singularize
          context_taggings = "#{tag_type}_taggings".to_sym
          context_tags = tags_type.to_sym
          taggings_order = (preserve_tag_order? ? "#{ActsAsTaggableOn::Tagging.table_name}.id" : [])

          class_eval do
            # when preserving tag order, include order option so that for a 'tags' context
            # the associations tag_taggings & tags are always returned in created order
            has_many context_taggings, -> { includes(:tag).order(taggings_order).where(context: tags_type) },
                     as: :taggable,
                     class_name: ActsAsTaggableOn::Tagging,
                     dependent: :destroy

            has_many context_tags, -> { order(taggings_order) },
                     class_name: ActsAsTaggableOn::Tag,
                     through: context_taggings,
                     source: :tag
          end

          taggable_mixin.class_eval <<-RUBY, __FILE__, __LINE__ + 1
            def #{tag_type}_list
              tag_list_on('#{tags_type}')
            end

            def #{tag_type}_list=(new_tags)
              set_tag_list_on('#{tags_type}', new_tags)
            end

            def all_#{tags_type}_list
              all_tags_list_on('#{tags_type}')
            end
          RUBY
        end
      end

      def taggable_on(preserve_tag_order, *tag_types)
        super(preserve_tag_order, *tag_types)
        initialize_acts_as_taggable_on_core
      end

      # all column names are necessary for PostgreSQL group clause
      def grouped_column_names_for(object)
        object.column_names.map { |column| "#{object.table_name}.#{column}" }.join(', ')
      end

      ##
      # Return a scope of objects that are tagged with the specified tags.
      #
      # @param tags The tags that we want to query for
      # @param [Hash] options A hash of options to alter you query:
      #                       * <tt>:exclude</tt> - if set to true, return objects that are *NOT* tagged with the specified tags
      #                       * <tt>:any</tt> - if set to true, return objects that are tagged with *ANY* of the specified tags
      #                       * <tt>:order_by_matching_tag_count</tt> - if set to true and used with :any, sort by objects matching the most tags, descending
      #                       * <tt>:match_all</tt> - if set to true, return objects that are *ONLY* tagged with the specified tags
      #                       * <tt>:owned_by</tt> - return objects that are *ONLY* owned by the owner
      #                       * <tt>:start_at</tt> - Restrict the tags to those created after a certain time
      #                       * <tt>:end_at</tt> - Restrict the tags to those created before a certain time
      #
      # Example:
      #   User.tagged_with(["awesome", "cool"])                     # Users that are tagged with awesome and cool
      #   User.tagged_with(["awesome", "cool"], :exclude => true)   # Users that are not tagged with awesome or cool
      #   User.tagged_with(["awesome", "cool"], :any => true)       # Users that are tagged with awesome or cool
      #   User.tagged_with(["awesome", "cool"], :any => true, :order_by_matching_tag_count => true)  # Sort by users who match the most tags, descending
      #   User.tagged_with(["awesome", "cool"], :match_all => true) # Users that are tagged with just awesome and cool
      #   User.tagged_with(["awesome", "cool"], :owned_by => foo ) # Users that are tagged with just awesome and cool by 'foo'
      #   User.tagged_with(["awesome", "cool"], :owned_by => foo, :start_at => Date.today ) # Users that are tagged with just awesome, cool by 'foo' and starting today
      def tagged_with(tags, options = {})
        tag_list = ActsAsTaggableOn.default_parser.new(tags).parse
        options = options.dup
        empty_result = where('1 = 0')

        return empty_result if tag_list.empty?

        joins = []
        conditions = []
        having = []
        select_clause = []
        order_by = []

        context = options.delete(:on)
        owned_by = options.delete(:owned_by)
        alias_base_name = undecorated_table_name.gsub('.', '_')
        # FIXME use ActiveRecord's connection quote_column_name
        quote = ActsAsTaggableOn::Utils.using_postgresql? ? '"' : ''

        if options.delete(:exclude)
          if options.delete(:wild)
            tags_conditions = tag_list.map { |t| sanitize_sql(["#{ActsAsTaggableOn::Tag.table_name}.name #{ActsAsTaggableOn::Utils.like_operator} ? ESCAPE '!'", "%#{ActsAsTaggableOn::Utils.escape_like(t)}%"]) }.join(' OR ')
          else
            tags_conditions = tag_list.map { |t| sanitize_sql(["#{ActsAsTaggableOn::Tag.table_name}.name #{ActsAsTaggableOn::Utils.like_operator} ?", t]) }.join(' OR ')
          end

          conditions << "#{table_name}.#{primary_key} NOT IN (SELECT #{ActsAsTaggableOn::Tagging.table_name}.taggable_id FROM #{ActsAsTaggableOn::Tagging.table_name} JOIN #{ActsAsTaggableOn::Tag.table_name} ON #{ActsAsTaggableOn::Tagging.table_name}.tag_id = #{ActsAsTaggableOn::Tag.table_name}.#{ActsAsTaggableOn::Tag.primary_key} AND (#{tags_conditions}) WHERE #{ActsAsTaggableOn::Tagging.table_name}.taggable_type = #{quote_value(base_class.name, nil)})"

          if owned_by
            joins <<  "JOIN #{ActsAsTaggableOn::Tagging.table_name}" +
                      "  ON #{ActsAsTaggableOn::Tagging.table_name}.taggable_id = #{quote}#{table_name}#{quote}.#{primary_key}" +
                      " AND #{ActsAsTaggableOn::Tagging.table_name}.taggable_type = #{quote_value(base_class.name, nil)}" +
                      " AND #{ActsAsTaggableOn::Tagging.table_name}.tagger_id = #{quote_value(owned_by.id, nil)}" +
                      " AND #{ActsAsTaggableOn::Tagging.table_name}.tagger_type = #{quote_value(owned_by.class.base_class.to_s, nil)}"

            joins << " AND " + sanitize_sql(["#{ActsAsTaggableOn::Tagging.table_name}.created_at >= ?", options.delete(:start_at)]) if options[:start_at]
            joins << " AND " + sanitize_sql(["#{ActsAsTaggableOn::Tagging.table_name}.created_at <= ?", options.delete(:end_at)])   if options[:end_at]
          end

        elsif options.delete(:any)
          # get tags, drop out if nothing returned (we need at least one)
          tags = if options.delete(:wild)
                   ActsAsTaggableOn::Tag.named_like_any(tag_list)
                 else
                   ActsAsTaggableOn::Tag.named_any(tag_list)
                 end

          return empty_result if tags.length == 0

          # setup taggings alias so we can chain, ex: items_locations_taggings_awesome_cool_123
          # avoid ambiguous column name
          taggings_context = context ? "_#{context}" : ''

          taggings_alias = adjust_taggings_alias(
              "#{alias_base_name[0..4]}#{taggings_context[0..6]}_taggings_#{ActsAsTaggableOn::Utils.sha_prefix(tags.map(&:name).join('_'))}"
          )

          tagging_cond = "#{ActsAsTaggableOn::Tagging.table_name} #{taggings_alias}" +
                          " WHERE #{taggings_alias}.taggable_id = #{quote}#{table_name}#{quote}.#{primary_key}" +
                          " AND #{taggings_alias}.taggable_type = #{quote_value(base_class.name, nil)}"

          tagging_cond << " AND " + sanitize_sql(["#{taggings_alias}.created_at >= ?", options.delete(:start_at)]) if options[:start_at]
          tagging_cond << " AND " + sanitize_sql(["#{taggings_alias}.created_at <= ?", options.delete(:end_at)])   if options[:end_at]

          tagging_cond << " AND " + sanitize_sql(["#{taggings_alias}.context = ?", context.to_s]) if context

          # don't need to sanitize sql, map all ids and join with OR logic
          tag_ids = tags.map { |t| quote_value(t.id, nil) }.join(', ')
          tagging_cond << " AND #{taggings_alias}.tag_id in (#{tag_ids})"
          select_clause << " #{table_name}.*" unless context and tag_types.one?

{'fraction_non_alphanumeric': 0.11947346673750074, 'fraction_numerical': 0.001298624638451095, 'mean_word_length': 2.5547629039026436, 'pattern_counts': {'":': 0, '<': 75, '<?xml version=': 0, '>': 55, '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': '6706523', 'n_tokens_mistral': 5358, 'n_tokens_neox': 5187, 'n_words': 1126}