<commit_before># Feature:  QMF feature entity
#
# Copyright (c) 2009--2010 Red Hat, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

require 'spqr/spqr'
require 'rhubarb/rhubarb'
require 'mrg/grid/config/Parameter'
require 'mrg/grid/config/ArcLabel'
require 'mrg/grid/config/ArcUtils'
require 'mrg/grid/config/DataValidating'
require 'mrg/grid/config/InconsistencyDetecting'

require 'mrg/grid/util/graph'

require 'set'

module Mrg
  module Grid
    module Config
      class Feature
        include ::Rhubarb::Persisting
        include ::SPQR::Manageable
        include DataValidating

        qmf_package_name 'com.redhat.grid.config'
        qmf_class_name 'Feature'
        ### Property method declarations
        # property uid uint32 
        
        declare_column :name, :string
        declare_index_on :name
        qmf_property :name, :sstr, :desc=>"This feature's name"
        
        def uid
          @row_id
        end
        
        def Feature.find_by_uid(u)
          find(u)
        end
        
        qmf_property :uid, :uint32, :index=>true
        ### Schema method declarations
        
        def eql?(other)
          return self.class == other.class && self.row_id == other.row_id
        end
        
        # setName 
        # * name (sstr/I)
        def setName(name)
          # Print values of input parameters
          log.debug "setName: name => #{name.inspect}"
          fail(Errors.make(Errors::NAME_ALREADY_IN_USE, Errors::FEATURE), "Feature name #{name} is taken") if (self.name != name and Feature.find_first_by_name(name))
          self.name = name
        end
        
        expose :setName do |args|
          args.declare :name, :sstr, :in, "A new name for this feature; this name must not already be in use by another feature."
        end
        
        # modifyIncludedFeatures 
        # * command (sstr/I)
        #   Valid commands are 'ADD', 'REMOVE', and 'REPLACE'.
        # * features (map/I)
        #   A list of other feature names a feature includes
        def modifyIncludedFeatures(command,features,options=nil)
          # Print values of input parameters
          log.debug "modifyFeatures: command => #{command.inspect}"
          log.debug "modifyFeatures: features => #{features.inspect}"
          log.debug "modifyFeatures: options => #{options.inspect}"
          fl = features
                    
          invalid_fl = Feature.select_invalid(fl)
          
          options ||= {}          
          skip_validation = options["skip_validation"] && %w{true yes}.include?(options["skip_validation"].downcase)
          
          
          fail(Errors.make(Errors::NONEXISTENT_ENTITY, Errors::FEATURE), "Invalid features supplied for inclusion:  #{invalid_fl.inspect}") if invalid_fl != []
          
          detect_inconsistencies(:includedFeatures, command, features) unless skip_validation
          
          modify_arcs(command,fl,options,:included_features,:included_features=,:explain=>"include",:preserve_order=>true,:xc=>:x_includes)
          self_to_dirty_list
        end
        
        expose :modifyIncludedFeatures do |args|
          args.declare :command, :sstr, :in, "Valid commands are 'ADD', 'REMOVE', and 'REPLACE'."
          args.declare :features, :list, :in, "A list, in inverse priority order, of the names of features that this feature should include (in the case of ADD or REPLACE), or should not include (in the case of REMOVE)."
          args.declare :options, :map, :in, "No options are supported at this time."
        end
        
        qmf_property :params, :map, :desc=>"A map from parameter names to their values as set in this feature"
        qmf_property :param_meta, :map, :desc=>"A map from parameter names used in this feature to maps of metadata about those params"
        
        def clearParams
          log.debug "clearParams called on feature #{self.inspect}"
          FeatureParams.find_by(:feature=>self).map {|fp| fp.delete}
          self_to_dirty_list
          0
        end
        
        expose :clearParams do |args|
          args.declare :ret, :int, :out, "0 if successful."
        end
        
        # modifyParams 
        # * command (sstr/I)
        #   Valid commands are 'ADD', 'REMOVE', and 'REPLACE'.
        # * params (map/I)
        #   A map(paramName, value) of parameters and their corresponding values that is specific to a group
        def modifyParams(command,pvmap,options=nil)
          # Print values of input parameters
          log.debug "modifyParams: command => #{command.inspect}"
          log.debug "modifyParams: params => #{pvmap.inspect}"
          
          pvmap ||= {}
          
          options ||= {}          
          skip_validation = options["skip_validation"] && %w{true yes}.include?(options["skip_validation"].downcase)
          # XXX: would be nice to use Parameter.select_invalid, but we don't want to look up each param twice
          invalid_params = []
          
          params = pvmap.keys.map do |pn|
            prow = Parameter.find_first_by_name(pn)
            invalid_params << pn unless prow
            prow
          end

          fail(Errors.make(Errors::NONEXISTENT_ENTITY, Errors::PARAMETER), "Invalid parameters supplied to feature #{self.name}:  #{invalid_params}") if invalid_params != []
          
          command = command.upcase
          
          unless skip_validation
            failures = validate_params(command, pvmap.keys) 
            gerund = command.downcase.sub(/(E|)$/, "ing")
            if failures.size > 0
              fail(Errors::make(Errors::PARAMETER, Errors::FEATURE, Errors::INVALID_RELATIONSHIP), "#{gerund} #{pvmap.inspect} to #{self.name} would introduce the following errors:\n" + failures.join("\n"))
            end
          end
          
          case command
          when "ADD", "REMOVE" then
            params.each do |prow|
              pn = prow.name

              attributes = {:feature=>self, :param=>prow}

              # Delete any prior mappings for each supplied param in either case
              FeatureParams.find_by(attributes).map {|fp| fp.delete}
              
              if pvmap[pn].is_a? String
                attributes[:given_value] = pvmap[pn]
              else
                attributes[:uses_default] = true
              end
              
              # Add new mappings when requested
              FeatureParams.create(attributes) if command == "ADD"
            end
          when "REPLACE"
            self.clearParams
            self.modifyParams("ADD",pvmap,options)
          else fail(Errors.make(Errors::BAD_COMMAND), "invalid command #{command}")<commit_msg>Fix for inconsistent behavior in Feature#modifyParams.<commit_after># Feature:  QMF feature entity
#
# Copyright (c) 2009--2010 Red Hat, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

require 'spqr/spqr'
require 'rhubarb/rhubarb'
require 'mrg/grid/config/Parameter'
require 'mrg/grid/config/ArcLabel'
require 'mrg/grid/config/ArcUtils'
require 'mrg/grid/config/DataValidating'
require 'mrg/grid/config/InconsistencyDetecting'

require 'mrg/grid/util/graph'

require 'set'

module Mrg
  module Grid
    module Config
      class Feature
        include ::Rhubarb::Persisting
        include ::SPQR::Manageable
        include DataValidating

        qmf_package_name 'com.redhat.grid.config'
        qmf_class_name 'Feature'
        ### Property method declarations
        # property uid uint32 
        
        declare_column :name, :string
        declare_index_on :name
        qmf_property :name, :sstr, :desc=>"This feature's name"
        
        def uid
          @row_id
        end
        
        def Feature.find_by_uid(u)
          find(u)
        end
        
        qmf_property :uid, :uint32, :index=>true
        ### Schema method declarations
        
        def eql?(other)
          return self.class == other.class && self.row_id == other.row_id
        end
        
        # setName 
        # * name (sstr/I)
        def setName(name)
          # Print values of input parameters
          log.debug "setName: name => #{name.inspect}"
          fail(Errors.make(Errors::NAME_ALREADY_IN_USE, Errors::FEATURE), "Feature name #{name} is taken") if (self.name != name and Feature.find_first_by_name(name))
          self.name = name
        end
        
        expose :setName do |args|
          args.declare :name, :sstr, :in, "A new name for this feature; this name must not already be in use by another feature."
        end
        
        # modifyIncludedFeatures 
        # * command (sstr/I)
        #   Valid commands are 'ADD', 'REMOVE', and 'REPLACE'.
        # * features (map/I)
        #   A list of other feature names a feature includes
        def modifyIncludedFeatures(command,features,options=nil)
          # Print values of input parameters
          log.debug "modifyFeatures: command => #{command.inspect}"
          log.debug "modifyFeatures: features => #{features.inspect}"
          log.debug "modifyFeatures: options => #{options.inspect}"
          fl = features
                    
          invalid_fl = Feature.select_invalid(fl)
          
          options ||= {}          
          skip_validation = options["skip_validation"] && %w{true yes}.include?(options["skip_validation"].downcase)
          
          
          fail(Errors.make(Errors::NONEXISTENT_ENTITY, Errors::FEATURE), "Invalid features supplied for inclusion:  #{invalid_fl.inspect}") if invalid_fl != []
          
          detect_inconsistencies(:includedFeatures, command, features) unless skip_validation
          
          modify_arcs(command,fl,options,:included_features,:included_features=,:explain=>"include",:preserve_order=>true,:xc=>:x_includes)
          self_to_dirty_list
        end
        
        expose :modifyIncludedFeatures do |args|
          args.declare :command, :sstr, :in, "Valid commands are 'ADD', 'REMOVE', and 'REPLACE'."
          args.declare :features, :list, :in, "A list, in inverse priority order, of the names of features that this feature should include (in the case of ADD or REPLACE), or should not include (in the case of REMOVE)."
          args.declare :options, :map, :in, "No options are supported at this time."
        end
        
        qmf_property :params, :map, :desc=>"A map from parameter names to their values as set in this feature"
        qmf_property :param_meta, :map, :desc=>"A map from parameter names used in this feature to maps of metadata about those params"
        
        def clearParams
          log.debug "clearParams called on feature #{self.inspect}"
          FeatureParams.find_by(:feature=>self).map {|fp| fp.delete}
          self_to_dirty_list
          0
        end
        
        expose :clearParams do |args|
          args.declare :ret, :int, :out, "0 if successful."
        end
        
        # modifyParams 
        # * command (sstr/I)
        #   Valid commands are 'ADD', 'REMOVE', and 'REPLACE'.
        # * params (map/I)
        #   A map(paramName, value) of parameters and their corresponding values that is specific to a group
        def modifyParams(command,pvmap,options=nil)
          # Print values of input parameters
          log.debug "modifyParams: command => #{command.inspect}"
          log.debug "modifyParams: params => #{pvmap.inspect}"
          
          pvmap ||= {}
          
          options ||= {}          
          skip_validation = options["skip_validation"] && %w{true yes}.include?(options["skip_validation"].downcase)
          # XXX: would be nice to use Parameter.select_invalid, but we don't want to look up each param twice
          invalid_params = []
          
          params = pvmap.keys.map do |pn|
            prow = Parameter.find_first_by_name(pn)
            invalid_params << pn unless prow
            prow
          end

          fail(Errors.make(Errors::NONEXISTENT_ENTITY, Errors::PARAMETER), "Invalid parameters supplied to feature #{self.name}:  #{invalid_params}") if invalid_params != []
          
          command = command.upcase
          
          unless skip_validation
            failures = validate_params(command, pvmap.keys) 
            gerund = command.downcase.sub(/(E|)$/, "ing")
            if failures.size > 0
              fail(Errors::make(Errors::PARAMETER, Errors::FEATURE, Errors::INVALID_RELATIONSHIP), "#{gerund} #{pvmap.inspect} to #{self.name} would introduce the following errors:\n" + failures.join("\n"))
            end
          end
          
          case command
          when "ADD", "REMOVE" then
            params.each do |prow|
              pn = prow.name

              attributes = {:feature=>self, :param=>prow}

              # Delete any prior mappings for each supplied param in either case
              FeatureParams.find_by(attributes).map {|fp| fp.delete}
              
              if pvmap[pn] == 0
                attributes[:uses_default] = true
              elsif pvmap[pn].is_a? String
                attributes[:given_value] = pvmap[pn]
              else
                log.warn("supplied value for param #{pn} is a #{pvmap[pn].class.to_s} (#{pvmap[pn].inspect}); converting to string")
                attributes[:given_value] = pvmap[pn].to_s
              end
              
              # Add new mappings when requested
              FeatureParams.create(attributes) if command == "ADD"
            end
          when "REPLACE"
            self.clearParams
            self.modifyParams("ADD",pvmap,options)
          else fail(Errors.make(Errors::BAD_COMMAND), "invalid command #{command}")
{'fraction_non_alphanumeric': 0.09839754517558813, 'fraction_numerical': 0.002659393112853733, 'mean_word_length': 2.197296708088075, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 37, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, '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': '6694385', 'n_tokens_mistral': 4048, 'n_tokens_neox': 3987, 'n_words': 1189}