traffic_light_controller 0.0.4 → 0.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- traffic_light_controller (0.0.3)
4
+ traffic_light_controller (0.0.5)
5
5
  arduino
6
6
  hashie
7
7
  json
@@ -1,3 +1,3 @@
1
1
  #!/usr/bin/env ruby
2
2
  require 'traffic_light_controller'
3
- TrafficLightController::CLI.new
3
+ TrafficLightController::CLI.run
@@ -1,7 +1,102 @@
1
1
  module TrafficLightController
2
2
  class CLI
3
+ class << self
4
+ def run
5
+ cli = self.new
6
+ cli.process_command_line_options
7
+ cli.run
8
+ end
9
+ end
10
+
3
11
  def initialize
4
- TrafficLightController::Server.new.work
12
+ @server = Server.new
13
+ end
14
+
15
+ def process_command_line_options
16
+ @options = {}
17
+
18
+ GetoptLong.new(*options_possible).each do |opt, arg|
19
+ case opt
20
+ when '--help'
21
+ show_help_and_exit
22
+ when '--version'
23
+ puts version_info
24
+ exit
25
+ end
26
+ end
27
+ end
28
+
29
+ def run
30
+ server.work
31
+ end
32
+
33
+ private
34
+
35
+ attr_reader :server
36
+
37
+ def options_possible
38
+ [
39
+ ['--help', '-h', GetoptLong::NO_ARGUMENT],
40
+ ['--version', '-V', GetoptLong::NO_ARGUMENT],
41
+ ]
42
+ end
43
+
44
+ def show_help_and_exit
45
+ STDOUT.puts help_info
46
+ exit
47
+ end
48
+
49
+ def help_info
50
+ <<-EOH
51
+ Usage: #{prog_name} [options]
52
+ #{short_hand_options}
53
+
54
+ Options:
55
+ #{option_details}
56
+ #{version_info}
57
+ EOH
58
+ end
59
+
60
+ def prog_name
61
+ File.basename($0)
62
+ end
63
+
64
+ def short_hand_options
65
+ "[#{options_possible.map{ |o| short_hand_option(o)}.join('], [')}]"
66
+ end
67
+
68
+ def short_hand_option(option)
69
+ if option[2] == GetoptLong::REQUIRED_ARGUMENT
70
+ [option[0], option[1]].join('|') << " argument"
71
+ else
72
+ [option[0], option[1]].join('|')
73
+ end
74
+ end
75
+
76
+ def option_details
77
+ <<-EOO
78
+ #{options_possible.map{ |o| expand_option(o) }.join("\n")}
79
+ EOO
80
+ end
81
+
82
+ def version_info
83
+ <<-EOV
84
+ traffic_light_controller (#{version_number})
85
+ https://github.com/jcmuller/traffic_light_controller
86
+ (c) 2012 Juan C. Muller
87
+ EOV
88
+ end
89
+
90
+ def version_number
91
+ VERSION
92
+ end
93
+
94
+ def longest_width
95
+ @max_width ||= options_possible.map{ |o| o[0] }.max{ |a, b| a.length <=> b.length }.length
96
+ end
97
+
98
+ def expand_option(option)
99
+ sprintf(" %-#{longest_width + 6}s %s", option.first(2).join(', '), option[3])
5
100
  end
6
101
  end
7
102
  end
@@ -5,6 +5,7 @@ module TrafficLightController
5
5
  Thread.abort_on_exception = true
6
6
  @config = Config.new
7
7
  @server = TCPServer.new(config.server.address, config.server.port)
8
+ @current_path = ""
8
9
  rescue Errno::EADDRINUSE
9
10
  address_in_use_error(config.server)
10
11
  rescue Errno::EADDRNOTAVAIL, SocketError
@@ -19,28 +20,43 @@ module TrafficLightController
19
20
 
20
21
  private
21
22
 
22
- attr_reader :server, :config, :board
23
+ attr_reader :server, :config, :board, :current_path
23
24
 
24
25
  def start_thread_and_do_work
25
- Thread.start(server.accept) do |client|
26
- work_with_client(client)
26
+ Thread.start(server.accept) do |request|
27
+ accept_request(request)
27
28
  end
28
29
  end
29
30
 
30
- def work_with_client(client)
31
- puts "work_with_client"
32
- process_path(process_request(client))
31
+ def accept_request(request)
32
+ process_request(request)
33
33
  rescue => e
34
- puts "Got #{e.class}: #{e}!"
34
+ STDERR.puts "Got #{e.class}: #{e}!
35
+
36
+ #{e.backtrace.join($/)}"
35
37
  ensure
36
- client.close
38
+ request.close
37
39
  end
38
40
 
39
- def process_request(client)
40
- puts "process_request"
41
- path = nil
41
+ def process_request(request)
42
+ path = path_from_request(request)
42
43
 
43
- while(line = client.readline) do
44
+ if config.arduino.lights.has_key?(path)
45
+ if path != current_path
46
+ @current_path = path
47
+ change_pins(path)
48
+ respond_200(request, path)
49
+ else
50
+ respond_304(request, path)
51
+ end
52
+ else
53
+ respond_404(request, path)
54
+ end
55
+ end
56
+
57
+ def path_from_request(request)
58
+ path = ""
59
+ while(line = request.readline) do
44
60
  break if line == "\r\n"
45
61
  if match = line.match(%r{GET /+(?<path>\w*) HTTP/1\.})
46
62
  path = match[:path]
@@ -50,28 +66,28 @@ module TrafficLightController
50
66
  path
51
67
  end
52
68
 
53
- def process_path(path)
54
- puts "process_path"
55
- if config.arduino.lights.has_key?(path)
56
- change_pins(path)
57
- client.print "HTTP/1.1 200 OK\r\nContent-type:text/plain\r\n\r\n"
58
- client.puts path
59
- else
60
- client.print "HTTP/1.1 404 Not Found\r\nContent-type:text/plain\r\n\r\n"
61
- client.puts "The requested path doesn't exist"
62
- end
63
- end
64
-
65
69
  def change_pins(path)
66
- puts "change_pins"
67
70
  init_board
68
71
  board.turnOff
69
72
  board.setHigh(config.arduino.lights[path]) unless path == "off"
70
73
  board.close
71
74
  end
72
75
 
76
+ def respond_200(request, path)
77
+ request.print "HTTP/1.1 200 OK\r\nContent-type:text/plain\r\n\r\n"
78
+ request.puts path
79
+ end
80
+
81
+ def respond_304(request, path)
82
+ request.puts "HTTP/1.1 304 Not Modified\r\nContent-type:text/plain\r\n\r\n"
83
+ end
84
+
85
+ def respond_404(request, path)
86
+ request.print "HTTP/1.1 404 Not Found\r\nContent-type:text/plain\r\n\r\n"
87
+ request.puts "The requested path doesn't exist"
88
+ end
89
+
73
90
  def init_board
74
- puts "board"
75
91
  @board = Arduino.new(config.arduino.port)
76
92
  rescue Errno::ENOENT
77
93
  STDERR.puts "The port #{config.arduino.port} doesn't exist"
@@ -1,3 +1,3 @@
1
1
  module TrafficLightController
2
- VERSION = "0.0.4"
2
+ VERSION = "0.0.5"
3
3
  end
@@ -1,5 +1,6 @@
1
1
  require "rubygems"
2
2
  require "arduino"
3
+ require "getoptlong"
3
4
  require "hashie"
4
5
  require "socket"
5
6
  require "yaml"
@@ -8,5 +9,5 @@ module TrafficLightController
8
9
  autoload :Config, "traffic_light_controller/config"
9
10
  autoload :CLI, "traffic_light_controller/cli"
10
11
  autoload :Server, "traffic_light_controller/server"
11
- autoload :VERION, "traffic_light_controller/version"
12
+ autoload :VERSION, "traffic_light_controller/version"
12
13
  end
@@ -1,12 +1,42 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe TrafficLightController::CLI do
4
- describe "#work" do
4
+ let(:config) { mock }
5
+ let(:server) { mock }
6
+
7
+ before do
8
+ TrafficLightController::Config.stub(:new).and_return(config)
9
+ TrafficLightController::Server.stub(:new).and_return(server)
10
+
11
+ config.stub_chain(:server, :address).and_return("127.0.0.1")
12
+ config.stub_chain(:server, :port).and_return(5678)
13
+ end
14
+
15
+ describe ".run" do
5
16
  it "should initialize server and call work on it" do
6
17
  server = mock
7
18
  TrafficLightController::Server.should_receive(:new).and_return(server)
8
19
  server.should_receive(:work)
9
- described_class.new
20
+ described_class.run
21
+ end
22
+ end
23
+
24
+ describe "show_help_and_exit" do
25
+ it "should show help" do
26
+ STDOUT.stub(:puts)
27
+ subject.should_receive(:help_info)
28
+ expect{ subject.send(:show_help_and_exit) }.to raise_error SystemExit
29
+ end
30
+ end
31
+
32
+ describe "#help_info" do
33
+ it "should return the nice string" do
34
+ subject.should_receive(:prog_name)
35
+ subject.should_receive(:short_hand_options)
36
+ subject.should_receive(:option_details)
37
+ subject.should_receive(:version_info)
38
+
39
+ subject.send(:help_info)
10
40
  end
11
41
  end
12
42
  end
@@ -69,28 +69,25 @@ describe TrafficLightController::Server do
69
69
  describe "#start_thread_and_do_work" do
70
70
  it "should start a thread" do
71
71
  Thread.should_receive(:start).and_yield(client)
72
- subject.should_receive(:work_with_client).with(client)
72
+ subject.should_receive(:accept_request).with(client)
73
73
  subject.send(:start_thread_and_do_work)
74
74
  end
75
75
  end
76
76
 
77
- describe "#work_with_client" do
77
+ describe "#accept_request" do
78
78
  it "should call process path" do
79
79
  subject.should_receive(:process_request).with(client).and_return(:processed)
80
- subject.should_receive(:process_path).with(:processed)
81
80
  client.should_receive(:close)
82
81
 
83
- subject.send(:work_with_client, client)
82
+ subject.send(:accept_request, client)
84
83
  end
85
84
 
86
- it "should rescue from all exceptions and log them to STDOUT" do
85
+ it "should rescue from all exceptions and log them to STDERR" do
87
86
  subject.should_receive(:process_request).and_raise RuntimeError
88
-
89
- STDOUT.should_receive(:puts).with("Got RuntimeError: RuntimeError!")
90
-
87
+ STDERR.should_receive(:puts)
91
88
  client.should_receive(:close)
92
89
 
93
- subject.send(:work_with_client, client)
90
+ subject.send(:accept_request, client)
94
91
  end
95
92
  end
96
93
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: traffic_light_controller
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.4
4
+ version: 0.0.5
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors: