Playfair cipher

You are encouraged to solve this task according to the task description, using any language you may know.
Task

Implement a  Playfair cipher for encryption and decryption.



The user must be able to choose   J  =  I     or   no   Q   in the alphabet.

The output of the encrypted and decrypted message must be in capitalized digraphs, separated by spaces.



Output example

                HI DE TH EG OL DI NT HE TR EX ES TU MP



func playfair(key, from = 'J', to = (from == 'J' ? 'I' : '')) {
 
    func canon(str) {
        str.gsub(/[^[:alpha:]]/, '').uc.gsub(from, to)
    }
 
    var m = canon(key + ('A'..'Z' -> join)).chars.uniq.slices(5)
 
    var :ENC = gather {
        m.each { |r|
            for i,j in (^r ~X ^r) {
                i == j && next
                take(Pair("#{r[i]}#{r[j]}", "#{r[(i+1)%5]}#{r[(j+1)%5]}"))
            }
        }
 
        ^5 -> each { |k|
            var c = m.map {|a| a[k] }
            for i,j in (^c ~X ^c) {
                i == j && next
                take(Pair("#{c[i]}#{c[j]}", "#{c[(i+1)%5]}#{c[(j+1)%5]}"))
            }
        }
 
        cartesian([^5, ^5, ^5, ^5], {|i1,j1,i2,j2|
            i1 == i2 && next
            j1 == j2 && next
            take(Pair("#{m[i1][j1]}#{m[i2][j2]}", "#{m[i1][j2]}#{m[i2][j1]}"))
        })
    }.map { (.key, .value) }...
 
    var DEC = ENC.flip
 
    func enc(red) {
        gather {
            var str = canon(red)
            while (var m = (str =~ /(.)(?(?=\1)|(.?))/g)) {
                take("#{m[0]}#{m[1] == '' ? 'X' : m[1]}")
            }
        }.map { ENC{_} }.join(' ')
    }
 
    func dec(black) {
        canon(black).split(2).map { DEC{_} }.join(' ')
    }
 
    return(enc, dec)
}
 
var (encode, decode) = playfair('Playfair example')
 
var orig = "Hide the gold in...the TREESTUMP!!!"
say " orig:\t#{orig}"
 
var black = encode(orig)
say "black:\t#{black}"
 
var red = decode(black)
say "  red:\t#{red}"