ruby.onl / secret-operators

The Flip-Flop Operator: Perl's Weirdest Gift to Ruby

2026-02-26

Ruby inherited Perl's flip-flop operator directly. It's a stateful boolean that turns true when the first condition matches and stays true until the second condition matches. If you've ever used print if /START/ .. /END/ in Perl, congratulations, you already know this one. If you haven't, prepare to have your mind slightly bent.

Part 1: Basic Usage

# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # Print lines between START and END markers # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ARGF.each_line do |line| puts line if line =~ %r~START~ .. line =~ %r~END~ end # Perl: perl -ne 'print if /START/ .. /END/' # Ruby: ruby -ne 'puts $_ if /START/ .. /END/'
Identical behavior in both languages. The flip-flop remembers its state between iterations.

Part 2: How It Works

The flip-flop has two states:
  1. Off: Evaluates only the LEFT condition. When left becomes true, switches to "on" state.
  2. On: Evaluates only the RIGHT condition. When right becomes true, switches back to "off" state.

The line that triggers each transition IS included in the output. So you get the START line, everything in between, and the END line.

Part 3: Two Dots vs Three Dots

# With .. (two dots): # If START and END appear on the SAME line, it matches just that line puts line if line =~ %r~START~ .. line =~ %r~END~ # With ... (three dots): # Even if END appears on the START line, it won't stop until a later END puts line if line =~ %r~START~ ... line =~ %r~END~
In practice you almost always want ... The ... variant is for when your markers might overlap on a single line and you want to keep going.

Part 4: Line Number Ranges

# Print lines 3 through 15 ARGF.each_line do |line| puts line if ($. == 3)..($. == 15) end # One-liner version: ruby -ne 'puts $_ if ($. == 3)..($. == 15)' file.txt

Part 5: Practical Examples

Extract a section from an INI config file:
# Extract [database] section from INI file ARGF.each_line do |line| puts line if line =~ %r~\[database\]~ .. line =~ %r~^\[~ end
Extract between timestamps in a log:
# Print log lines between two times ARGF.each_line do |line| puts line if line =~ %r~10:00:00~ .. line =~ %r~11:00:00~ end
Extract block content:
# Print content between BEGIN and END markers in a config ARGF.each_line do |line| puts line if line =~ %r~^BEGIN~ .. line =~ %r~^END~ end

Part 6: Gotchas

  1. The flip-flop is STATEFUL. It remembers its state between iterations.
  2. Each flip-flop instance has its own state.
  3. The start and end lines ARE included in the output.
  4. If the start condition never matches, nothing is output.
  5. If the start matches but end never does, everything from start to EOF is output.

Part 7: One-Liner Examples

# Extract lines between markers ruby -ne 'puts $_ if /BEGIN/../END/' file.txt # Print lines 5-10 ruby -ne 'puts $_ if ($. == 5)..($. == 10)' file.txt # Extract Apache virtual host config ruby -ne 'puts $_ if /VirtualHost/../\/VirtualHost/' httpd.conf
The flip-flop is one of those operators that seems obscure until you need to extract a section from a file. Then it's the only tool you want.

Created By: Wildcard Wizard. Copyright 2026