Business
Jobs
  • About Us
  • Solutions
    • Job Postings
      Post your job and receive qualified candidates in 48h.
    • Candidate Assessments
      500+ technical and psychological tests, plus anti-fraud.
    • Headhunting
      Tailor-made executive search from start to finish.
    • Payroll + EOR
      Payroll dispersal and EOR across 15+ LATAM countries.
  • Pricing
  • Jobs

0

285
Views
Ruby: How to add validation for a class field's << method

I understand how to implement a (validating) setter (def item=), but how do I intercept the << operation on a field?

class Bla 
  attr_reader :item

  def initialize
    @item = []
  end

  # only called for =, +=, -= operations (not <<)
  def item=(value)
    puts "Changing value to #{value}"
    # pretend that there is a conditional here
    @item = value
  end

  # This is wrong:
  #def item<<(value)
  #  puts "adding value #{value}"
  #  @item << value
  #end

end

b = Bla.new
b.item = ['one']  # works
b.item += ['one'] # works
b.item << 'two'   # bypasses my setter

I've tried def item<<(value), that doesn't seem to work.

over 4 years ago · Santiago Trujillo
3 answers
Answer question

0

When you call b.item << 'two', you are calling the << method on item directly. So you have a few options here:

  1. Implement << directly on your Bla class, then use b << 'two':

    # in class Bla
    def <<(value)
      # do validation here
      @item << value
    end
    
  2. Use some other, nicer-named wrapper method name like add_item:

    # in class Bla
    def add_item(value)
      # do validation here
      @item << value
    end
    
  3. Use a special array class for @item which has a custom definition for <<:

    class MyArray < Array
      def <<(item)
        # run validation here
        super
      end
    end
    
    # in Bla class
    def initialize
      @item = MyArray.new
    end
    

I would probably go with option 2, it's the most simple and readable.

over 4 years ago · Santiago Trujillo Report

0

Here is an alternate suggestion:

class Bla 
  # DO NOT DEFINE A READER:
  # attr_reader :item

  def initialize
    @items = []
  end

  def set_items(new_items)
    puts "Changing value to #{new_items}"
    # pretend that there is a conditional here
    @items = new_items
  end

  def remove_item(item)
    # pretend that there is a conditional here
    @items -= items
  end

  def add_item(item)
    # pretend that there is a conditional here
    @items += items
  end
end

By not exposing the @items object directly, you remain in full control of the interface for how the variable is manipulated.

(Unless a caller does something really hacky, like bla.instance_variable_get('@items')!!)

over 4 years ago · Santiago Trujillo Report

0

class Pit
  def <<(dirt)
    puts 'shovel ' + dirt
  end
end
Pit.new << 'sandy loam'
# => shovel sandy loam
over 4 years ago · Santiago Trujillo Report
Answer question
Find remote jobs

Discover the new way to find a job!

Top jobs
Top job categories
Business
Post vacancy Pricing Sales
Legal
Terms and conditions Privacy policy
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Show me some job opportunities
There's an error!