Code Smells: Your Refactoring Cheat Codes

Code Smells: Your Refactoring Cheat Codes

Sure, the TDD cycle is red-green-refactor but what exactly are we refactoring? We just wrote the code, it's green, and it seems reasonable to us. Let's move onto the next test. We're have a deadline, remember?

Whether we're working with code we just wrote or opening up a project for the first time, being able to listen to the hints the code is trying to give you about how it wants to be constructed is the most direct path toward successful refactoring. What the code is telling you nuanced however: no code smell is absolute and none in itself is an indication of a problem. How do we know we need to refactor? What are the code smells telling us to do? How do we balance our short terms needs of shipping our software with the long term maintainability of the code base? In this talk we'll talk through some of the classical code smells and dive into examples of how to put these smells to work for you.

03e04db3b6880c3a2f8114649312f733?s=128

John Pignata

April 04, 2013
Tweet

Transcript

  1. 3.
  2. 5.
  3. 16.

    queue = Queue.new client = HTTPClient.new socket = UDPSocket.new 10.times

    do Thread.new do while data = queue.pop client.post("https://android.googleapis.com/gcm/send", data, { "Authorization" => "key=AIzaSyCABSTd47XeIH", "Content-Type" => "application/json" }) end end end socket.bind("0.0.0.0", 6889) while data = socket.recvfrom(4096) case data[0].split.first when "PING" socket.send("PONG", 0, data[1][3], data[1][1]) when "SEND" data[0][5..-1].match(/([a-zA-Z0-9_\-]*) "([^"]*)/) json = JSON.generate({ "registration_ids" => [$1], "data" => { "alert" => $2 } }) queue << json end end
  4. 17.

    PING it responds with PONG SEND it delivers the message

    to the Google Cloud Messaging API Commands
  5. 21.

    PING ✔ it responds with PONG SEND it delivers the

    message to the Google Cloud Messaging API Commands
  6. 23.
  7. 24.

    PING ✔ it responds with PONG SEND ✔ it delivers

    the message to the Google Cloud Messaging API Commands
  8. 25.

    describe "Push Daemon" do let(:socket) { UDPSocket.new } before(:all) do

    Thread.new { load "./pushd.rb" } end describe "commands" do describe "PING" do it "responds with PONG" end describe "SEND" do it "delivers the message to the Google Cloud Messaging API" end end end
  9. 26.

    it "responds with PONG" do socket.send("PING", 0, "127.0.0.1", 6889) response,

    _ = socket.recvfrom(8) response.should eq("PONG") end
  10. 27.

    it "delivers the message to the Google Cloud Messaging API"

    do stub_request :post, "https://android.googleapis.com/gcm/send" socket.send('SEND t0k3n "Steve: What is up?"', 0, "127.0.0.1", 6889) assert_requested :post, "https://android.googleapis.com/gcm/send", { body: { "registration_ids" => ["t0k3n"], "data" => { "alert" => "Steve: What is up?" } }.to_json } end
  11. 28.

    jp@oeuf:~/workspace/mwrc(master)$ rspec Push Daemon commands PING responds with PONG SEND

    delivers the message to the Google Cloud Messaging API Finished in 0.06854 seconds 2 examples, 0 failures
  12. 29.

    queue = Queue.new client = HTTPClient.new socket = UDPSocket.new 10.times

    do Thread.new do while data = queue.pop client.post("https://android.googleapis.com/gcm/send", data, { "Authorization" => "key=AIzaSyCABSTd47XeIH", "Content-Type" => "application/json" }) end end end socket.bind("0.0.0.0", 6889) while data = socket.recvfrom(4096) case data[0].split.first when "PING" socket.send("PONG", 0, data[1][3], data[1][1]) when "SEND" data[0][5..-1].match(/([a-zA-Z0-9_\-]*) "([^"]*)/) json = JSON.generate({ "registration_ids" => [$1], "data" => { "alert" => $2 } }) queue << json end end
  13. 31.

    queue = Queue.new client = HTTPClient.new socket = UDPSocket.new 10.times

    do Thread.new do while data = queue.pop client.post("https://android.googleapis.com/gcm/send", data, { "Authorization" => "key=AIzaSyCABSTd47XeIH", "Content-Type" => "application/json" }) end end end socket.bind("0.0.0.0", 6889) while data = socket.recvfrom(4096) case data[0].split.first when "PING" socket.send("PONG", 0, data[1][3], data[1][1]) when "SEND" data[0][5..-1].match(/([a-zA-Z0-9_\-]*) "([^"]*)/) json = JSON.generate({ "registration_ids" => [$1], "data" => { "alert" => $2 } }) queue << json end end Collaborator Instantiation [
  14. 33.

    queue = Queue.new client = HTTPClient.new socket = UDPSocket.new 10.times

    do Thread.new do while data = queue.pop client.post("https://android.googleapis.com/gcm/send", data, { "Authorization" => "key=AIzaSyCABSTd47XeIH", "Content-Type" => "application/json" }) end end end socket.bind("0.0.0.0", 6889) while data = socket.recvfrom(4096) case data[0].split.first when "PING" socket.send("PONG", 0, data[1][3], data[1][1]) when "SEND" data[0][5..-1].match(/([a-zA-Z0-9_\-]*) "([^"]*)/) json = JSON.generate({ "registration_ids" => [$1], "data" => { "alert" => $2 } }) queue << json end end Thread Pool Initialization [ Collaborator Instantiation [
  15. 35.

    queue = Queue.new client = HTTPClient.new socket = UDPSocket.new 10.times

    do Thread.new do while data = queue.pop client.post("https://android.googleapis.com/gcm/send", data, { "Authorization" => "key=AIzaSyCABSTd47XeIH", "Content-Type" => "application/json" }) end end end socket.bind("0.0.0.0", 6889) while data = socket.recvfrom(4096) case data[0].split.first when "PING" socket.send("PONG", 0, data[1][3], data[1][1]) when "SEND" data[0][5..-1].match(/([a-zA-Z0-9_\-]*) "([^"]*)/) json = JSON.generate({ "registration_ids" => [$1], "data" => { "alert" => $2 } }) queue << json end end Thread Pool Initialization [ Service Request Creation and Delivery [ Collaborator Instantiation [
  16. 37.

    queue = Queue.new client = HTTPClient.new socket = UDPSocket.new 10.times

    do Thread.new do while data = queue.pop client.post("https://android.googleapis.com/gcm/send", data, { "Authorization" => "key=AIzaSyCABSTd47XeIH", "Content-Type" => "application/json" }) end end end socket.bind("0.0.0.0", 6889) while data = socket.recvfrom(4096) case data[0].split.first when "PING" socket.send("PONG", 0, data[1][3], data[1][1]) when "SEND" data[0][5..-1].match(/([a-zA-Z0-9_\-]*) "([^"]*)/) json = JSON.generate({ "registration_ids" => [$1], "data" => { "alert" => $2 } }) queue << json end end Thread Pool Initialization [ Service Request Creation and Delivery [ [ Server Socket Setup Collaborator Instantiation [
  17. 39.

    queue = Queue.new client = HTTPClient.new socket = UDPSocket.new 10.times

    do Thread.new do while data = queue.pop client.post("https://android.googleapis.com/gcm/send", data, { "Authorization" => "key=AIzaSyCABSTd47XeIH", "Content-Type" => "application/json" }) end end end socket.bind("0.0.0.0", 6889) while data = socket.recvfrom(4096) case data[0].split.first when "PING" socket.send("PONG", 0, data[1][3], data[1][1]) when "SEND" data[0][5..-1].match(/([a-zA-Z0-9_\-]*) "([^"]*)/) json = JSON.generate({ "registration_ids" => [$1], "data" => { "alert" => $2 } }) queue << json end end Thread Pool Initialization [ Service Request Creation and Delivery [ [ Server Socket Setup [ Command Dispatch Collaborator Instantiation [
  18. 41.

    queue = Queue.new client = HTTPClient.new socket = UDPSocket.new 10.times

    do Thread.new do while data = queue.pop client.post("https://android.googleapis.com/gcm/send", data, { "Authorization" => "key=AIzaSyCABSTd47XeIH", "Content-Type" => "application/json" }) end end end socket.bind("0.0.0.0", 6889) while data = socket.recvfrom(4096) case data[0].split.first when "PING" socket.send("PONG", 0, data[1][3], data[1][1]) when "SEND" data[0][5..-1].match(/([a-zA-Z0-9_\-]*) "([^"]*)/) json = JSON.generate({ "registration_ids" => [$1], "data" => { "alert" => $2 } }) queue << json end end Thread Pool Initialization [ Service Request Creation and Delivery [ [ Server Socket Setup [ Command Dispatch [ Parameter Extraction Collaborator Instantiation [
  19. 43.

    queue = Queue.new client = HTTPClient.new socket = UDPSocket.new 10.times

    do Thread.new do while data = queue.pop client.post("https://android.googleapis.com/gcm/send", data, { "Authorization" => "key=AIzaSyCABSTd47XeIH", "Content-Type" => "application/json" }) end end end socket.bind("0.0.0.0", 6889) while data = socket.recvfrom(4096) case data[0].split.first when "PING" socket.send("PONG", 0, data[1][3], data[1][1]) when "SEND" data[0][5..-1].match(/([a-zA-Z0-9_\-]*) "([^"]*)/) json = JSON.generate({ "registration_ids" => [$1], "data" => { "alert" => $2 } }) queue << json end end Thread Pool Initialization [ Service Request Creation and Delivery [ [ Server Socket Setup [ Command Dispatch [ Parameter Extraction Collaborator Instantiation [
  20. 46.

    queue = Queue.new client = HTTPClient.new socket = UDPSocket.new 10.times

    do Thread.new do while data = queue.pop client.post("https://android.googleapis.com/gcm/send", data, { "Authorization" => "key=AIzaSyCABSTd47XeIH", "Content-Type" => "application/json" }) end end end socket.bind("0.0.0.0", 6889) while data = socket.recvfrom(4096) case data[0].split.first when "PING" socket.send("PONG", 0, data[1][3], data[1][1]) when "SEND" data[0][5..-1].match(/([a-zA-Z0-9_\-]*) "([^"]*)/) json = JSON.generate({ "registration_ids" => [$1], "data" => { "alert" => $2 } }) queue << json end end
  21. 48.

    10.times do Thread.new do while json = queue.pop client.post("https://android.googleapis.com/gcm/send", json,

    "Authorization" => "key=AIzaSyCABSTd47XeIH", "Content-Type" => "application/json" ) end end end socket.bind("0.0.0.0", 6889) while data = socket.recvfrom(4096) case data[0].split.first when "PING" socket.send("PONG", 0, data[1][3], data[1][1]) when "SEND" data[0][5..-1].match(/([a-zA-Z0-9_\-]*) "([^"]*)/) json = JSON.generate({ "registration_ids" => [$1], "data" => { "alert" => $2 } }) queue << json end end
  22. 49.

    def start 10.times do Thread.new do while json = @queue.pop

    @client.post("https://android.googleapis.com/gcm/send", json, "Authorization" => "key=AIzaSyCABSTd47XeIH", "Content-Type" => "application/json" ) end end end @socket.bind("0.0.0.0", 6889) while data = @socket.recvfrom(4096) case data[0].split.first when "PING" @socket.send("PONG", 0, data[1][3], data[1][1]) when "SEND" data[0][5..-1].match(/([a-zA-Z0-9_\-]*) "([^"]*)/) json = JSON.generate({ "registration_ids" => [$1], "data" => { "alert" => $2 } }) @queue << json end end end
  23. 51.

    def start 10.times do Thread.new do while json = @queue.pop

    @client.post("https://android.googleapis.com/gcm/send", json, "Authorization" => "key=AIzaSyCABSTd47XeIH", "Content-Type" => "application/json" ) end end end @socket.bind("0.0.0.0", 6889) while data = @socket.recvfrom(4096) case data[0].split.first when "PING" @socket.send("PONG", 0, data[1][3], data[1][1]) when "SEND" data[0][5..-1].match(/([a-zA-Z0-9_\-]*) "([^"]*)/) json = JSON.generate({ "registration_ids" => [$1], "data" => { "alert" => $2 } }) @queue << json end end end [ Spawn Workers [ Bind [ Loop and Process Incoming Requests
  24. 53.

    def spawn_workers 10.times do Thread.new do while json = @queue.pop

    @client.post("https://android.googleapis.com/gcm/send", json, "Authorization" => "key=AIzaSyCABSTd47XeIH", "Content-Type" => "application/json" ) end end end end
  25. 55.

    def process_request data = @socket.recvfrom(4096) case data[0].split.first when "PING" @socket.send("PONG",

    0, data[1][3], data[1][1]) when "SEND" data[0][5..-1].match(/([a-zA-Z0-9_\-]*) "([^"]*)/) json = JSON.generate({ "registration_ids" => [$1], "data" => { "alert" => $2 } }) @queue << json end end
  26. 56.

    class PushDaemon def initialize @queue = Queue.new @client = HTTPClient.new

    @socket = UDPSocket.new end def start spawn_workers bind loop { process_request } end private def spawn_workers; end def bind; end def process_request; end end
  27. 57.

    ➡ Update authorization key ➡ Increase thread pool size ➡

    Swap HTTP client ➡ Use a different transport protocol ➡ Modify wire protocol format ➡ Add commands ➡ Add a different push notification service ➡ Move UDP port ➡ Use x-www-form-urlencoded instead of JSON ➡ Lower maximum payload size ➡ Bind to a specific interface address ➡ Update push service URL
  28. 60.

    def spawn_workers 10.times do Thread.new do while json = @queue.pop

    @client.post("https://android.googleapis.com/gcm/send", json, "Authorization" => "key=AIzaSyCABSTd47XeIH", "Content-Type" => "application/json" ) end end end end
  29. 64.

    def process_request data = @socket.recvfrom(4096) case data[0].split.first when "PING" @socket.send("PONG",

    0, data[1][3], data[1][1]) when "SEND" data[0][5..-1].match(/([a-zA-Z0-9_\-]*) "([^"]*)/) json = JSON.generate({ "registration_ids" => [$1], "data" => { "alert" => $2 } }) @queue << json end end
  30. 66.

    def process_request data = @socket.recvfrom(4096) case data[0].split.first when "PING" @socket.send("PONG",

    0, data[1][3], data[1][1]) when "SEND" data[0][5..-1].match(/([a-zA-Z0-9_\-]*) "([^"]*)/) json = JSON.generate({ "registration_ids" => [$1], "data" => { "alert" => $2 } }) @queue << json end end
  31. 67.

    def process_request data = @socket.recvfrom(4096) case data[0].split.first when "PING" @socket.send("PONG",

    0, data[1][3], data[1][1]) when "SEND" data[0][5..-1].match(/([a-zA-Z0-9_\-]*) "([^"]*)/) json = JSON.generate({ "registration_ids" => [$1], "data" => { "alert" => $2 } }) @worker << json end end
  32. 68.

    def spawn_workers 10.times do Thread.new do while json = @queue.pop

    @client.post("https://android.googleapis.com/gcm/send", json, { "Authorization" => "key=AIzaSyCABSTd47XeIH", "Content-Type" => "application/json" }) end end end end
  33. 69.

    class Worker def initialize @queue = Queue.new @client = HTTPClient.new

    end def spawn(count) count.times do Thread.new do while json = @queue.pop @client.post("https://android.googleapis.com/gcm/send", json, { "Authorization" => "key=AIzaSyCABSTd47XeIH", "Content-Type" => "application/json" }) end end end end def <<(json) @queue << json end end
  34. 70.

    class PushDaemon def initialize @worker = Worker.new @socket = UDPSocket.new

    end def start spawn_workers bind loop { process_request } end private def spawn_workers; end def bind; end def process_request; end end
  35. 71.

    class PushDaemon def initialize @worker = Worker.new @socket = UDPSocket.new

    end def start @worker.spawn(10) bind loop { process_request } end private def bind; end def process_request; end end
  36. 72.

    class PushDaemon def initialize @worker = Worker.new @socket = UDPSocket.new

    end def start @worker.spawn(10) bind loop { process_request } end private def bind; end def process_request; end end
  37. 73.

    def bind @socket.bind("0.0.0.0", 6889) end def process_request data = @socket.recvfrom(4096)

    case data[0].split.first when "PING" @socket.send("PONG", 0, data[1][3], data[1][1]) when "SEND" data[0][5..-1].match(/([a-zA-Z0-9_\-]*) "([^"]*)/) json = JSON.generate({ "registration_ids" => [$1], "data" => { "alert" => $2 } }) @worker << json end end [ Bind [ Receive [ Send
  38. 75.

    def bind @socket.bind("0.0.0.0", 6889) end def process_request data = @socket.recvfrom(4096)

    case data[0].split.first when "PING" @socket.send("PONG", 0, data[1][3], data[1][1]) when "SEND" data[0][5..-1].match(/([a-zA-Z0-9_\-]*) "([^"]*)/) json = JSON.generate({ "registration_ids" => [$1], "data" => { "alert" => $2 } }) @worker << json end end [ Bind [ Receive [ Send
  39. 76.

    class UDPServer def initialize @socket = UDPSocket.new end def bind(port)

    @socket.bind("0.0.0.0", port) end def receive @socket.recvfrom(4096) end def send(message, address, port) @socket.send(message, 0, address, port) end end
  40. 77.

    class PushDaemon def initialize @worker = Worker.new @socket = UDPSocket.new

    end def start @worker.spawn(10) bind loop { process_request } end private def bind; end def process_request; end end
  41. 78.

    class PushDaemon def initialize @worker = Worker.new @server = UDPServer.new

    end def start @worker.spawn(10) bind loop { process_request } end private def bind; end def process_request; end end
  42. 79.

    class PushDaemon def initialize @worker = Worker.new @server = UDPServer.new

    end def start @worker.spawn(10) bind loop { process_request } end private def bind; end def process_request; end end
  43. 80.

    class PushDaemon def initialize @worker = Worker.new @server = UDPServer.new

    end def start @worker.spawn(10) @server.bind(6889) loop { process_request } end private def process_request; end end
  44. 81.

    def process_request data = @socket.recvfrom(4096) case data[0].split.first when "PING" @socket.send("PONG",

    0, data[1][3], data[1][1]) when "SEND" data[0][5..-1].match(/([a-zA-Z0-9_\-]*) "([^"]*)/) json = JSON.generate({ "registration_ids" => [$1], "data" => { "alert" => $2 } }) @queue << json end end
  45. 82.

    def process_request data = @server.receive case data[0].split.first when "PING" @server.send("PONG",

    data[1][3], data[1][1]) when "SEND" data[0][5..-1].match(/([a-zA-Z0-9_\-]*) "([^"]*)/) json = JSON.generate({ "registration_ids" => [$1], "data" => { "alert" => $2 } }) @queue << json end end
  46. 83.

    class PushDaemon def initialize @worker = Worker.new @server = UDPServer.new

    end def start @worker.spawn(10) @server.bind(6889) loop { process_request } end private def process_request data = @server.receive case data[0].split.first when "PING" @server.send("PONG", 0, data[1][3], data[1][1]) when "SEND" data[0][5..-1].match(/([a-zA-Z0-9_\-]*) "([^"]*)/) json = JSON.generate({ "registration_ids" => [$1], "data" => { "alert" => $2 } }) @worker << json end end end
  47. 87.

    class PushDaemon def initialize @worker = Worker.new @server = UDPServer.new

    end def start @worker.spawn(10) @server.bind(6889) loop { process_request } end private def process_request data = @server.receive case data[0].split.first when "PING" @server.send("PONG", 0, data[1][3], data[1][1]) when "SEND" data[0][5..-1].match(/([a-zA-Z0-9_\-]*) "([^"]*)/) json = JSON.generate({ "registration_ids" => [$1], "data" => { "alert" => $2 } }) @worker << json end end end
  48. 88.

    class PushDaemon def initialize @worker = Worker.new @server = UDPServer.new(self)

    end def start @worker.spawn(10) @server.bind(6889) loop { process_request } end private def process_request data = @server.receive case data[0].split.first when "PING" @server.send("PONG", 0, data[1][3], data[1][1]) when "SEND" data[0][5..-1].match(/([a-zA-Z0-9_\-]*) "([^"]*)/) json = JSON.generate({ "registration_ids" => [$1], "data" => { "alert" => $2 } }) @worker << json end end end
  49. 89.

    class PushDaemon def initialize @worker = Worker.new @server = UDPServer.new(self)

    end def start @worker.spawn(10) @server.bind(6889) loop { process_request } end private def process_request data = @server.receive case data[0].split.first when "PING" @server.send("PONG", 0, data[1][3], data[1][1]) when "SEND" data[0][5..-1].match(/([a-zA-Z0-9_\-]*) "([^"]*)/) json = JSON.generate({ "registration_ids" => [$1], "data" => { "alert" => $2 } }) @worker << json end end end
  50. 90.

    class PushDaemon def initialize @worker = Worker.new @server = UDPServer.new(self)

    end def start @worker.spawn(10) @server.bind(6889) @server.listen end private def process_request data = @server.receive case data[0].split.first when "PING" @server.send("PONG", 0, data[1][3], data[1][1]) when "SEND" data[0][5..-1].match(/([a-zA-Z0-9_\-]*) "([^"]*)/) json = JSON.generate({ "registration_ids" => [$1], "data" => { "alert" => $2 } }) @worker << json end end end
  51. 91.

    class PushDaemon def initialize @worker = Worker.new @server = UDPServer.new(self)

    end def start @worker.spawn(10) @server.bind(6889) @server.listen end private def process_request data = @server.receive case data[0].split.first when "PING" @server.send("PONG", 0, data[1][3], data[1][1]) when "SEND" data[0][5..-1].match(/([a-zA-Z0-9_\-]*) "([^"]*)/) json = JSON.generate({ "registration_ids" => [$1], "data" => { "alert" => $2 } }) @worker << json end end end
  52. 92.

    class PushDaemon def initialize @worker = Worker.new @server = UDPServer.new(self)

    end def start @worker.spawn(10) @server.listen(6889) end private def process_request data = @server.receive case data[0].split.first when "PING" @server.send("PONG", 0, data[1][3], data[1][1]) when "SEND" data[0][5..-1].match(/([a-zA-Z0-9_\-]*) "([^"]*)/) json = JSON.generate({ "registration_ids" => [$1], "data" => { "alert" => $2 } }) @worker << json end end end
  53. 93.

    class PushDaemon def initialize @worker = Worker.new @server = UDPServer.new(self)

    end def start @worker.spawn(10) @server.listen(6889) end private def process_request data = @server.receive case data[0].split.first when "PING" @server.send("PONG", 0, data[1][3], data[1][1]) when "SEND" data[0][5..-1].match(/([a-zA-Z0-9_\-]*) "([^"]*)/) json = JSON.generate({ "registration_ids" => [$1], "data" => { "alert" => $2 } }) @worker << json end end end
  54. 94.

    class PushDaemon def initialize @worker = Worker.new @server = UDPServer.new(self)

    end def start @worker.spawn(10) @server.listen(6889) end def process_request(data) case data[0].split.first when "PING" @server.send("PONG", 0, data[1][3], data[1][1]) when "SEND" data[0][5..-1].match(/([a-zA-Z0-9_\-]*) "([^"]*)/) json = JSON.generate({ "registration_ids" => [$1], "data" => { "alert" => $2 } }) @worker << json end end end
  55. 95.

    class PushDaemon def initialize @worker = Worker.new @server = UDPServer.new(self)

    end def start @worker.spawn(10) @server.listen(6889) end def process_request(data) case data[0].split.first when "PING" @server.send("PONG", 0, data[1][3], data[1][1]) when "SEND" data[0][5..-1].match(/([a-zA-Z0-9_\-]*) "([^"]*)/) json = JSON.generate({ "registration_ids" => [$1], "data" => { "alert" => $2 } }) @worker << json end end end
  56. 96.

    class PushDaemon def initialize @worker = Worker.new @server = UDPServer.new(self)

    end def start @worker.spawn(10) @server.listen(6889) end def call(data) case data[0].split.first when "PING" @server.send("PONG", 0, data[1][3], data[1][1]) when "SEND" data[0][5..-1].match(/([a-zA-Z0-9_\-]*) "([^"]*)/) json = JSON.generate({ "registration_ids" => [$1], "data" => { "alert" => $2 } }) @worker << json end end end
  57. 97.

    class UDPServer def initialize @socket = UDPSocket.new end def bind(port)

    @socket.bind("0.0.0.0", port) end def receive @socket.recvfrom(4096) end def send(message, address, port) @socket.send(message, 0, address, port) end end
  58. 98.

    class UDPServer def initialize(app) @app = app @socket = UDPSocket.new

    end def bind(port) @socket.bind("0.0.0.0", port) end def receive @socket.recvfrom(4096) end def send(message, address, port) @socket.send(message, 0, address, port) end end
  59. 99.

    class UDPServer def initialize(app) @app = app @socket = UDPSocket.new

    end def bind(port) @socket.bind("0.0.0.0", port) end def receive @socket.recvfrom(4096) end def send(message, address, port) @socket.send(message, 0, address, port) end end
  60. 100.

    class UDPServer def initialize(app) @app = app @socket = UDPSocket.new

    end def listen(port) @socket.bind("0.0.0.0", port) loop { @app.call(receive) } end def receive @socket.recvfrom(4096) end def send(message, address, port) @socket.send(message, 0, address, port) end end
  61. 101.

    class PushDaemon def initialize @worker = Worker.new @server = UDPServer.new(self)

    end def start @worker.spawn(10) @server.listen(6889) end def call(data) case data[0].split.first when "PING" @server.send("PONG", 0, data[1][3], data[1][1]) when "SEND" data[0][5..-1].match(/([a-zA-Z0-9_\-]*) "([^"]*)/) json = JSON.generate({ "registration_ids" => [$1], "data" => { "alert" => $2 } }) @worker << json end end end
  62. 103.

    class PushDaemon def initialize @worker = Worker.new @server = UDPServer.new(self)

    end def start @worker.spawn(10) @server.listen(6889) end def call(data) case data[0].split.first when "PING" @server.send("PONG", 0, data[1][3], data[1][1]) when "SEND" data[0][5..-1].match(/([a-zA-Z0-9_\-]*) "([^"]*)/) json = JSON.generate({ "registration_ids" => [$1], "data" => { "alert" => $2 } }) @worker << json end end end
  63. 105.

    def call(data) case data[0].split.first when "PING" @server.send("PONG", data[1][3], data[1][1]) when

    "SEND" data[0][5..-1].match(/([a-zA-Z0-9_\-]*) "([^"]*)/) json = JSON.generate({ "registration_ids" => [$1], "data" => { "alert" => $2 } }) @worker << json end end
  64. 106.

    module Jobs class Ping def initialize(data, server) @data = data

    @server = server end def run @server.send("PONG", @data[1][3], @data[1][1]) end end end
  65. 107.

    def call(data) case data[0].split.first when "PING" @server.send("PONG", data[1][3], data[1][1]) when

    "SEND" data[0][5..-1].match(/([a-zA-Z0-9_\-]*) "([^"]*)/) json = JSON.generate({ "registration_ids" => [$1], "data" => { "alert" => $2 } }) @worker << json end end
  66. 108.

    def call(data) case data[0].split.first when "PING" Jobs::Ping.new(data, @server).run when "SEND"

    data[0][5..-1].match(/([a-zA-Z0-9_\-]*) "([^"]*)/) json = JSON.generate({ "registration_ids" => [$1], "data" => { "alert" => $2 } }) @worker << json end end
  67. 109.

    def call(data) case data[0].split.first when "PING" Jobs::Ping.new(data, @server).run when "SEND"

    data[0][5..-1].match(/([a-zA-Z0-9_\-]*) "([^"]*)/) json = JSON.generate({ "registration_ids" => [$1], "data" => { "alert" => $2 } }) @worker << json end end
  68. 110.

    module Jobs class Send def initialize(data, server) @data = data

    @server = server end def run @data[0][5..-1].match(/([a-zA-Z0-9_\-]*) "([^"]*)/) JSON.generate({ "registration_ids" => [$1], "data" => { "alert" => $2 } }) end end end
  69. 111.

    def call(data) case data[0].split.first when "PING" Jobs::Ping.new(data, @server).run when "SEND"

    json = Jobs::Send.new(data, @server).run @worker << json end end
  70. 112.

    class Worker def initialize @queue = Queue.new @client = HTTPClient.new

    end def spawn(count) count.times do Thread.new do while json = @queue.pop @client.post("https://android.googleapis.com/gcm/send", json, { "Authorization" => "key=AIzaSyCABSTd47XeIH", "Content-Type" => "application/json" }) end end end end def <<(json) @queue << json end end
  71. 113.

    class Worker def initialize @queue = Queue.new @client = HTTPClient.new

    end def spawn(count) count.times do Thread.new do while json = @queue.pop @client.post("https://android.googleapis.com/gcm/send", json, { "Authorization" => "key=AIzaSyCABSTd47XeIH", "Content-Type" => "application/json" }) end end end end def <<(json) @queue << json end end
  72. 114.

    module Jobs class Send def self.client @client ||= HTTPClient.new end

    def initialize(data, server) @data = data @server = server end def run @data[0][5..-1].match(/([a-zA-Z0-9_\-]*) "([^"]*)/) json = JSON.generate({ "registration_ids" => [$1], "data" => { "alert" => $2 } }) self.class.client.post("https://android.googleapis.com/gcm/send", json, { "Authorization" => "key=AIzaSyCABSTd47XeIH-ERx9rvHUSF9DIJ7DCwdk", "Content-Type" => "application/json" }) end end end
  73. 115.

    class Worker def initialize @queue = Queue.new end def spawn(count)

    count.times do Thread.new { work } end end def <<(job) @queue << job end private def work while job = @queue.pop job.run end end end
  74. 116.

    class PushDaemon def initialize @worker = Worker.new @server = UDPServer.new(self)

    end def start @worker.spawn(10) @server.listen(6889) end def call(data) case data[0].split.first when "PING" Jobs::Ping.new(data, @server).run when "SEND" json = Jobs::Send.new(data, @server).run @worker << json end end end
  75. 117.

    class PushDaemon def initialize @worker = Worker.new @server = UDPServer.new(self)

    end def start @worker.spawn(10) @server.listen(6889) end def call(data) job = case data[0].split.first when "PING" Jobs::Ping.new(data, @server) when "SEND" Jobs::Send.new(data, @server) end if job @worker << job end end end
  76. 119.

    class PushDaemon def initialize @worker = Worker.new @server = UDPServer.new(self)

    end def start @worker.spawn(10) @server.bind(6889) @server.listen end def call(data) job = case data[0].split.first when "PING" Jobs::Ping.new(data, @server) when "SEND" Jobs::Send.new(data, @server) end if job @worker << job end end end
  77. 120.
  78. 121.

    module Jobs JOBS = { "PING" => Ping, "SEND" =>

    Send } def self.factory(data, server) command = data[0].split.first.upcase klass = JOBS[command] if klass klass.new(data, server) end end end
  79. 122.

    class PushDaemon def initialize @worker = Worker.new @server = UDPServer.new(self)

    end def start @worker.spawn(10) @server.bind(6889) @server.listen end def call(data) job = case data[0].split.first when "PING" Jobs::Ping.new(data, @server) when "SEND" Jobs::Send.new(data, @server) end if job @worker << job end end end
  80. 123.

    class PushDaemon def initialize @worker = Worker.new @server = UDPServer.new(self)

    end def start @worker.spawn(10) @server.listen(6889) end def call(data) job = Jobs.factory(data, @server) if job @worker << job end end end
  81. 124.

    module Jobs class Ping def initialize(data, server) @data = data

    @server = server end def run @server.send("PONG", @data[1][3], @data[1][1]) end end end
  82. 127.

    class Client def initialize(sockaddr) @addrinfo = Addrinfo.new(sockaddr) end def address

    @addrinfo.ip_address end def port @addrinfo.ip_port end end
  83. 128.

    class UDPServer def initialize(app) @app = app @socket = UDPSocket.new

    end def listen(port) @socket.bind("0.0.0.0", port) loop { @app.call(receive) } end def receive @socket.recvfrom(4096) end def send(message, address, port) @socket.send(message, 0, address, port) end end
  84. 129.

    class UDPServer def initialize(app) @app = app @socket = UDPSocket.new

    end def listen(port) @socket.bind("0.0.0.0", port) loop do message, sockaddr = @socket.recvfrom(4096) client = Client.new(sockaddr) @app.call(client, message) end end def send(message, address, port) @socket.send(message, 0, address, port) end end
  85. 130.

    class PushDaemon def initialize @worker = Worker.new @server = UDPServer.new(self)

    end def start @worker.spawn(10) @server.listen(6889) end def call(data) job = Jobs.factory(data, @server) if job @worker << job end end end
  86. 132.

    class PushDaemon def initialize @worker = Worker.new @server = UDPServer.new(self)

    end def start @worker.spawn(10) @server.listen(6889) end def call(data) job = Jobs.factory(data, @server) if job @worker << job end end end
  87. 133.

    class PushDaemon def initialize @worker = Worker.new @server = UDPServer.new(self)

    end def start @worker.spawn(10) @server.listen(6889) end def call(client, message) job = Jobs.factory(client, message, @server) if job @worker << job end end end
  88. 134.

    module Jobs class Ping def initialize(client, message, server) @client =

    client @message = message @server = server end def run @server.send("PONG", @client.address, @client.port) end end end
  89. 137.

    class Client def initialize(sockaddr) @addrinfo = Addrinfo.new(sockaddr) end def address

    @addrinfo.ip_address end def port @addrinfo.ip_port end end
  90. 138.

    class Client def initialize(sockaddr, server) @addrinfo = Addrinfo.new(sockaddr) @server =

    server end def address @addrinfo.ip_address end def port @addrinfo.ip_port end end
  91. 139.

    class Client def initialize(sockaddr, server) @addrinfo = Addrinfo.new(sockaddr) @server =

    server end def send(message) @server.send(message, address, port) end def address @addrinfo.ip_address end def port @addrinfo.ip_port end end
  92. 140.

    class UDPServer def initialize(app) @app = app @socket = UDPSocket.new

    end def listen @socket.bind("0.0.0.0", port) loop do message, sockaddr = @socket.recvfrom(4096) client = Client.new(sockaddr) @app.call(client, message) end end def send(message, address, port) @socket.send(message, 0, address, port) end end
  93. 141.

    class UDPServer def initialize(app) @app = app @socket = UDPSocket.new

    end def listen @socket.bind("0.0.0.0", port) loop do message, sockaddr = @socket.recvfrom(4096) client = Client.new(sockaddr, self) @app.call(client, message) end end def send(message, address, port) @socket.send(message, 0, address, port) end end
  94. 142.

    module Jobs class Ping def initialize(client, message, server) @client =

    client @message = message @server = server end def run @server.send("PONG", @client.address, @client.port) end end end
  95. 143.

    module Jobs class Ping def initialize(client, message, server) @client =

    client @message = message @server = server end def run @client.send("PONG") end end end
  96. 144.

    module Jobs class Ping def initialize(client, message, server) @client =

    client @message = message @server = server end def run @client.send("PONG") end end end
  97. 145.

    module Jobs class Ping def initialize(client, message) @client = client

    @message = message end def run @client.send("PONG") end end end
  98. 146.

    class PushDaemon def initialize @worker = Worker.new @server = UDPServer.new(self)

    end def start @worker.spawn(10) @server.listen(6889) end def call(client, message) job = Jobs.factory(client, message, @server) if job @worker << job end end end
  99. 147.

    class PushDaemon def initialize @worker = Worker.new @server = UDPServer.new(self)

    end def start @worker.spawn(10) @server.listen(6889) end def call(client, message) job = Jobs.factory(client, message) if job @worker << job end end end
  100. 148.

    module Jobs class Send def self.client @client ||= HTTPClient.new end

    def initialize(client, message) @client = client @message = message end def run @message[5..-1].match(/([a-zA-Z0-9_\-]*) "([^"]*)/) json = JSON.generate({ "registration_ids" => [$1], "data" => { "alert" => $2 } }) self.class.client.post("https://android.googleapis.com/gcm/send", json, { "Authorization" => "key=AIzaSyCABSTd47XeIH-ERx9rvHUSF9DIJ7DCwdk", "Content-Type" => "application/json" }) end end end
  101. 150.

    module Jobs class Send def self.client @client ||= HTTPClient.new end

    def initialize(client, message) @client = client @message = message end def run @message[5..-1].match(/([a-zA-Z0-9_\-]*) "([^"]*)/) json = JSON.generate({ "registration_ids" => [$1], "data" => { "alert" => $2 } }) self.class.client.post("https://android.googleapis.com/gcm/send", json, { "Authorization" => "key=AIzaSyCABSTd47XeIH-ERx9rvHUSF9DIJ7DCwdk", "Content-Type" => "application/json" }) end end end HTTP Client [ Server Client [
  102. 151.

    module Jobs class Send def self.client @client ||= HTTPClient.new end

    def initialize(client, message) @client = client @message = message end def run @message[5..-1].match(/([a-zA-Z0-9_\-]*) "([^"]*)/) json = JSON.generate({ "registration_ids" => [$1], "data" => { "alert" => $2 } }) self.class.client.post("https://android.googleapis.com/gcm/send", json, { "Authorization" => "key=AIzaSyCABSTd47XeIH", "Content-Type" => "application/json" }) end end end
  103. 152.

    class PushNotification def self.client @client ||= HTTPClient.new end def initialize(registration_id,

    alert) @registration_id = registration_id @alert = alert end def deliver self.class.client.post("https://android.googleapis.com/gcm/send", to_json, "Authorization" => "key=AIzaSyCABSTd47XeIH", "Content-Type" => "application/json" ) end def to_json { "registration_ids" => [@registration_id], "data" => { "alert" => @alert } }.to_json end end
  104. 153.

    module Jobs class Send def initialize(client, message) @client = client

    @message = message end def run @message[5..-1].match(/([a-zA-Z0-9_\-]*) "([^"]*)/) PushNotification.new($1, $2).deliver end end end
  105. 159.
  106. 160.

    class Request def initialize(message) @tokens = Shellwords.split(message) end def command

    @tokens[0].to_s.upcase end def parameters Array(@tokens[1..-1]) end end
  107. 161.

    class PushDaemon def initialize @worker = Worker.new @server = UDPServer.new(self)

    end def start @worker.spawn(10) @server.listen(6889) end def call(client, message) job = Jobs.factory(client, message) if job @worker << job end end end
  108. 162.

    class PushDaemon def initialize @worker = Worker.new @server = UDPServer.new(self)

    end def start @worker.spawn(10) @server.listen(6889) end def call(client, message) request = Request.new(message) job = Jobs.factory(client, request) if job @worker << job end end end
  109. 163.

    module Jobs JOBS = { "PING" => Ping, "SEND" =>

    Send } def self.factory(client, message) command = message.split.first.upcase klass = JOBS[command] if klass klass.new(client, message) end end end
  110. 164.

    module Jobs JOBS = { "PING" => Ping, "SEND" =>

    Send } def self.factory(client, request) klass = JOBS[request.command] if klass klass.new(client, request) end end end
  111. 165.

    module Jobs class Send def initialize(client, request) @client = client

    @request = request end def run PushNotification.new(registration_id, alert).deliver end private def registration_id @request.parameters[0] end def alert @request.parameters[1] end end end
  112. 167.

    module Jobs JOBS = { "PING" => Ping, "SEND" =>

    Send } def self.factory(client, request) klass = JOBS[request.command] if klass klass.new(client, request) end end end Possible nil from hash [
  113. 168.

    class PushDaemon def initialize @server = UDPServer.new(self) @worker = Worker.new

    end def start @worker.spawn(10) @server.listen(6889) end def call(client, message) request = Request.new(message) job = Jobs.factory(client, request) if job @worker << job end end end Possible nil from factory [
  114. 172.

    module Jobs JOBS = { "PING" => Ping, "SEND" =>

    Send } def self.factory(client, request) klass = JOBS[request.command] if klass klass.new(client, request) end end end
  115. 173.

    module Jobs JOBS = { "PING" => Ping, "SEND" =>

    Send } JOBS.default = NullJob def self.factory(client, request) JOBS[request.command].new(client, request) end end
  116. 174.

    class PushDaemon def initialize @worker = Worker.new @server = UDPServer.new(self)

    end def start @worker.spawn(10) @server.listen(6889) end def call(client, message) request = Request.new(message) job = Jobs.factory(client, request) if job @worker << job end end end
  117. 175.

    class PushDaemon def initialize @worker = Worker.new @server = UDPServer.new(self)

    end def start @worker.spawn(10) @server.listen(6889) end def call(client, message) request = Request.new(message) job = Jobs.factory(client, request) @worker << job end end
  118. 176.

    module Jobs class Ping def initialize(client, request) @client = client

    @request = request end def run @client.send("PONG") end def >>(worker) worker << self end end end
  119. 178.

    class PushDaemon def initialize @worker = Worker.new @server = UDPServer.new(self)

    end def start @worker.spawn(10) @server.listen(6889) end def call(client, message) request = Request.new(message) job = Jobs.factory(client, request) @worker << job end end
  120. 179.

    class PushDaemon def initialize @worker = Worker.new @server = UDPServer.new(self)

    end def start @worker.spawn(10) @server.listen(6889) end def call(client, message) request = Request.new(message) job = Jobs.factory(client, request) job >> @worker end end