Home > Blockchain >  Replace Instance variable with another instance variable conditionally
Replace Instance variable with another instance variable conditionally

Time:07-22

I am assigning values to my class' instance variable, My scenario is that I have to call function atleast 3 times and each call requires the answer to be store in separate instance variable. Keeping in mind the rubocop errors.

My class

class Major

  attr_accessor :max_temp, :min_temp, :max_humid, :max_t_day, :min_temp_day, :max_humid_day

  def initialize
    @max_temp = -440
    @min_temp = 1000
    @max_humid = -500
    @max_t_day = 'fahad'
    @min_temp_day = 'fahad'
    @max_humid_day = 'fahad'
  end

  def day_wise_results
    _arg, year, path, _month = ARGV
    arr = Dir.entries(path).select { |x| x.include?(year) }
    # max_temp_day, min_temp_day, max_humid_day = ''

    arr.each do |yc|
      collection = file_collection("#{path}/#{yc}")
      collection.shift

      temperature_with_day(collection, 1, true, '>')
      temperature_with_day_min(collection, 3, false, '<')
      temperature_with_day_humid(collection, 7, true, '>')
end

and the functions that have exact same code just the instance variable are different and I dont want to repeat code

Functions

  def temperature_with_day(collection, col, is_max, operator)
    if separete_collections(collection, col, is_max).public_send(
      operator, @max_temp
    )
      @max_temp = separete_collections(collection, col,
                                       is_max)
    end
    collection.each do |row|
      @max_t_day = row[0] if row[col].to_i.eql?(@max_temp)
    end
  end

  def temperature_with_day_min(collection, col, is_max, operator)
    if separete_collections(collection, col, is_max).public_send(
      operator, @min_temp
    )
      @min_temp = separete_collections(collection, col,
                                       is_max)
    end
    collection.each do |row|
      @min_temp_day = row[0] if row[col].to_i.eql?(@min_temp)
    end
  end

  def temperature_with_day_humid(collection, col, is_max, operator)
    if separete_collections(collection, col, is_max).public_send(
      operator, @max_humid
    )
      @max_humid = separete_collections(collection, col,
                                        is_max)
    end
    collection.each do |row|
      @max_humid_day = row[0] if row[col].to_i.eql?(@max_humid)
    end
  end

As you can see everything is same inside these three functions, Is there anyway where I don't have to repeat code and I can go with single instance variable and avoid rubocop errors.

also mentioning my final output is all these three instance variables having some value

CodePudding user response:

Could you use a hash instead, passing a symbol to indicate which value you want to use? Something like this, which adds the extra value as the first argument for the method, here called type.

  def initialize
    @temp = { max: -440, min: 1000, humid: -500 }
    @temp_day = { max: 'fahad', min: 'fahad', humid: 'fahad' }
  end

...

  def temperature_with_day(type, collection, col, is_max, operator)
    if separete_collections(collection, col, is_max).public_send(
      operator, @temp[type]
    )
      @temp[type] = separete_collections(collection, col, is_max)
    end
    collection.each do |row|
      @temp_day = row[0] if row[col].to_i.eql?(@temp[type])
    end
  end

If you still need separate methods to set and return the three values, you can add these explicitly instead of relying on the automatic accessors, something like this:

def max_temp=(value)
  @temp[:max] = value
end

def max_t_day
  return @temp_day[:max]
end

and so on.

(PS Your method separete_collections should probably be called separate_collections, I think - just a spelling mistake in "separate"!)

CodePudding user response:

You can use some constant

SETTINGS = {
  max_temp: {
    col: 1,
    is_max: true,
    operator: :>
  },
  # ...
}

And then iterate over its

SETTINGS.each do |temp, opts|
  separete_collections = separete_collections(collection, opts[:col], opts[:is_max])

  if separete_collections.public_send(opts[:operator], public_send(temp))
    public_send("#{temp}=", separete_collections)
  end
end

if (row = collection.find { |row| row[col].to_i == @max_humid })
  public_send("#{temp}=", row[0])
end
  •  Tags:  
  • ruby
  • Related