Ctrl+P again to print, arrows/tab to navigate results, enter to confirm

    Basic tips

    A list of short tips for easy small byte saves:

    Numbered parameters

    This feature introduced in Ruby 2.7 allows you to drop the block parameter:

    [1,2,3].map{|x|p x}
    [1,2,3].map{p _1}
    
    [[1,2],[3,4]].map{|x,y|p x+y}
    [[1,2],[3,4]].map{p _1+_2}
    

    Beware, however, as they have certain limitations in nested loops:

    a.map{|x|b.map{|y|p x+y}}  # OK
    a.map{|x|b.map{p x+_1}}    # OK
    a.map{b.map{|y|p _1+y}}    # NOT OK
    a.map{b.map{p _1+_2}}      # (VERY) NOT OK
    

    Chaining expressions

    Ruby has a strange feature that allows you to chain expressions in an obfuscated way. This allows for things like:

    b^=3;a-=1|b;a&3
    # ->
    3&a-=1|b^=3
    

    Magic variables

    Certain predefined variables like $. or $* can be abused to omit the initialization of an extra variable:

    # `$.` is always initialized to 0
    n=0;9.times{p n+=_1}
    9.times{p$.+=_1}
    
    # `$*` (a.k.a. ARGV) is an empty list if no arguments are given
    a=[];9.times{puts (a<<_1)*' '}
    9.times{puts ($*<<_1)*' '}
    

    Two other variables that are less used, but can still be useful are $/, which is "\n" by default, and $0, which is "-" by default (on code.golf).

    Subscripting integers

    To get the ith bit of an integer, simply use the subscript operator:

    n>>i&1
    n[i]
    

    Subscripts can be extended to work with ranges as well. For example, n[2..5] gives the binary bits from 2 to 5, as a decimal integer.

    Splatting

    Splatting is very flexible, and can be used in a multitude of ways. It is particularly good for grabbing the first/last/middle elements of array:

    a,*b,c=*1..5  # a=1, b=[2,3,4], c=5
    a,*,c=*1..5   # a=1, c=5
    a,=*1..5      # a=1
    *,c=*1..5     # c=5
    

    You can also use it to print an array of numbers, each on its own line, with

    p *a
    

    Note that you would use puts on an array of strings, but it doesn't require splatting:

    # Functionally identical
    puts *a
    puts a
    

    Operator methods

    Operators can in fact be used as methods. For example, 1+2*3 may be written as 1.+(2.*(3)). The precedence changes when using it is used this way, which sometimes saves a byte:

    a*(b+c)
    a.*b+c
    

    String conversion

    There are some neat ways to do string conversion, involving array multiplication. For example, say that you wanted to concatenate a number to a string:

    "#{n}"+s
    n.to_s+s
    [n,p]*s
    

    If you simply want to convert a number to a string, there is also a shorter way, but it involves an already-present string variable:

    "#{n}"
    n.to_s
    [n]*''
    [n]*s   # Assumes a defined string variable `s`
    

    filter vs grep

    By passing a lambda into grep, it can behave like a filter. This allows for a 2-byte save:

    (1..n).filter{|n|}
    (1..n).grep->n{}
    

    The downside is that the precedence of the grep version is pretty wacky, which makes it less useful.

    Looping a constant amount

    In general, n.times or eval''*n is the shortest way to loop n times. But with clever use of predefined variables, shorter alternatives exist that loop a predetermined amount:

    $:.map{}   # 8
    $:.max{}   # 7
    $:.sort{}  # 16
    $".map{}   # 45
    $".max{}   # 44
    $".sort{}  # 506
    
    # These two hold a block parameter, which contains the current index, like `.times`
    $:.fill{}  # 8 (same length as `9.times`, so what's the point?)
    $".fill{}  # 45
    

    Note that the amount of iterations illustrated above are specific to code.golf. In the case of max and sort, the return value within the block must be a number, otherwise it will cause an error.

    Obscuring 1.upto

    A rather specific (and rare) example in which combining eval and $. can match the length of 1.upto:

    1.upto(n){pred(_1)&&p(_1)}
    eval'p$.if pred($.+=1);'*n
    

    It should be noted that there are situations where the latter is shorter, such as if the space between if and pred can be reused.

    Packers

    2:1 packer

    Spoiler

    Compressor

    Note: the code size must be divisible by 2 for the compressor to work. If not, adding a trailing space should suffice.

    puts CODE.force_encoding('utf-16le').encode('utf-8')
    puts CODE.encode('utf-8', 'utf-16le')
    

    Decompressor

    Note: the overhead is 27 characters so your uncompressed code must be over 54 characters to get a benefit.

    eval'...'.encode('utf-16le').b
    

    3:1 packer

    Spoiler

    Compressor

    Use the code in the Python tips (change [101, 102, 103] to [97, 98, 99])

    Decompressor

    r="";"...".chars{|c|97.upto(99){r<<c.ord%_1+32}};eval r