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 +1 -1
- data/bin/traffic_light_controller +1 -1
- data/lib/traffic_light_controller/cli.rb +96 -1
- data/lib/traffic_light_controller/server.rb +42 -26
- data/lib/traffic_light_controller/version.rb +1 -1
- data/lib/traffic_light_controller.rb +2 -1
- data/spec/lib/traffic_light_controller/cli_spec.rb +32 -2
- data/spec/lib/traffic_light_controller/server_spec.rb +6 -9
- metadata +1 -1
data/Gemfile.lock
CHANGED
@@ -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
|
-
|
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 |
|
26
|
-
|
26
|
+
Thread.start(server.accept) do |request|
|
27
|
+
accept_request(request)
|
27
28
|
end
|
28
29
|
end
|
29
30
|
|
30
|
-
def
|
31
|
-
|
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
|
-
|
38
|
+
request.close
|
37
39
|
end
|
38
40
|
|
39
|
-
def process_request(
|
40
|
-
|
41
|
-
path = nil
|
41
|
+
def process_request(request)
|
42
|
+
path = path_from_request(request)
|
42
43
|
|
43
|
-
|
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,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 :
|
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
|
-
|
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.
|
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(:
|
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 "#
|
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(:
|
82
|
+
subject.send(:accept_request, client)
|
84
83
|
end
|
85
84
|
|
86
|
-
it "should rescue from all exceptions and log them to
|
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(:
|
90
|
+
subject.send(:accept_request, client)
|
94
91
|
end
|
95
92
|
end
|
96
93
|
end
|