ruby-nxt 0.8.1
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/LICENSE +340 -0
- data/README +49 -0
- data/examples/commands.rb +180 -0
- data/examples/drb_client.rb +11 -0
- data/examples/drb_server.rb +40 -0
- data/examples/mary.rb +78 -0
- data/examples/move_by_degrees.rb +42 -0
- data/examples/nxt_comm_demo.rb +65 -0
- data/examples/nxt_remote_control.rb +70 -0
- data/examples/socket_server.rb +37 -0
- data/lib/autodetect_nxt.rb +36 -0
- data/lib/brick.rb +53 -0
- data/lib/commands.rb +40 -0
- data/lib/commands/light_sensor.rb +82 -0
- data/lib/commands/mixins/motor.rb +84 -0
- data/lib/commands/mixins/sensor.rb +38 -0
- data/lib/commands/motor.rb +136 -0
- data/lib/commands/move.rb +210 -0
- data/lib/commands/rotation_sensor.rb +72 -0
- data/lib/commands/sound.rb +102 -0
- data/lib/commands/sound_sensor.rb +67 -0
- data/lib/commands/touch_sensor.rb +84 -0
- data/lib/commands/ultrasonic_sensor.rb +84 -0
- data/lib/motor.rb +235 -0
- data/lib/nxt.rb +189 -0
- data/lib/nxt_comm.rb +596 -0
- data/lib/sensors/light_sensor.rb +45 -0
- data/lib/sensors/sensor.rb +93 -0
- data/lib/sensors/sound_sensor.rb +48 -0
- data/lib/sensors/touch_sensor.rb +35 -0
- data/lib/sensors/ultrasonic_sensor.rb +95 -0
- data/lib/ultrasonic_comm.rb +102 -0
- data/test/bt_test.rb +10 -0
- data/test/interactive/interactive_test_helper.rb +89 -0
- data/test/interactive/test_sensors.rb +236 -0
- data/test/test.rb +22 -0
- data/test/test_helper.rb +1 -0
- data/test/unit/motor_test.rb +177 -0
- data/test/unit/nxt_comm_test.rb +155 -0
- data/test/unit/nxt_test.rb +60 -0
- metadata +95 -0
@@ -0,0 +1,45 @@
|
|
1
|
+
# ruby-nxt Control Mindstorms NXT via Bluetooth Serial Port Connection
|
2
|
+
# Copyright (C) 2006 Matt Zukowski <matt@roughest.net>
|
3
|
+
#
|
4
|
+
# This program is free software; you can redistribute it and/or modify
|
5
|
+
# it under the terms of the GNU General Public License as published by
|
6
|
+
# the Free Software Foundation; either version 2 of the License
|
7
|
+
#
|
8
|
+
# This program is distributed in the hope that it will be useful,
|
9
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
10
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
11
|
+
# GNU General Public License for more details.
|
12
|
+
#
|
13
|
+
# You should have received a copy of the GNU General Public License
|
14
|
+
# along with this program; if not, write to the Free Software Foundation,
|
15
|
+
# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
16
|
+
|
17
|
+
require 'yaml'
|
18
|
+
|
19
|
+
require File.dirname(File.expand_path(__FILE__))+'/sensor'
|
20
|
+
|
21
|
+
class LightSensor < Sensor
|
22
|
+
|
23
|
+
def initialize(nxt, port = NXTComm::SENSOR_3)
|
24
|
+
super(nxt, port)
|
25
|
+
use_illuminated_mode
|
26
|
+
end
|
27
|
+
|
28
|
+
# Get the current light level as a float from 0 to 1.0.
|
29
|
+
# 1.0 is maximum, 0 is minimum.
|
30
|
+
def get_light_level
|
31
|
+
# TODO: probably need to calibrate this... light level never really reaches 1023
|
32
|
+
(read_data[:value_scaled]).to_f / 1023.to_f
|
33
|
+
end
|
34
|
+
|
35
|
+
|
36
|
+
def use_illuminated_mode
|
37
|
+
set_input_mode(NXTComm::LIGHT_ACTIVE, NXTComm::RAWMODE)
|
38
|
+
end
|
39
|
+
|
40
|
+
|
41
|
+
def use_ambient_mode
|
42
|
+
set_input_mode(NXTComm::LIGHT_INACTIVE, NXTComm::RAWMODE)
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
@@ -0,0 +1,93 @@
|
|
1
|
+
# ruby-nxt Control Mindstorms NXT via Bluetooth Serial Port Connection
|
2
|
+
# Copyright (C) 2006 Matt Zukowski <matt@roughest.net>
|
3
|
+
#
|
4
|
+
# This program is free software; you can redistribute it and/or modify
|
5
|
+
# it under the terms of the GNU General Public License as published by
|
6
|
+
# the Free Software Foundation; either version 2 of the License
|
7
|
+
#
|
8
|
+
# This program is distributed in the hope that it will be useful,
|
9
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
10
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
11
|
+
# GNU General Public License for more details.
|
12
|
+
#
|
13
|
+
# You should have received a copy of the GNU General Public License
|
14
|
+
# along with this program; if not, write to the Free Software Foundation,
|
15
|
+
# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
16
|
+
|
17
|
+
require 'yaml'
|
18
|
+
|
19
|
+
require File.dirname(File.expand_path(__FILE__))+'/../brick'
|
20
|
+
|
21
|
+
# Controls and reads an NXT sensor.
|
22
|
+
class Sensor < Brick
|
23
|
+
|
24
|
+
POLL_INTERVAL = 0.25
|
25
|
+
|
26
|
+
# TODO: internal sensor numbering is 0x00 to 0x03, but sensor ports on the brick are marked 1 to 4...
|
27
|
+
# need to come up with some way to make sure there isn't confusion (or maybe it's okay, since
|
28
|
+
# if the user probably never uses the Sensor classes directly, only interacting via the NXT
|
29
|
+
# class?)
|
30
|
+
|
31
|
+
|
32
|
+
def initialize(nxt, port)
|
33
|
+
super(nxt, port)
|
34
|
+
@port = port
|
35
|
+
end
|
36
|
+
|
37
|
+
def name
|
38
|
+
"#{@port + 1}"
|
39
|
+
end
|
40
|
+
|
41
|
+
def set_input_mode(type, mode)
|
42
|
+
@nxt.set_input_mode(@port, type, mode)
|
43
|
+
end
|
44
|
+
|
45
|
+
def read_data
|
46
|
+
data = @nxt.get_input_values(@port)
|
47
|
+
|
48
|
+
debug(data.inspect, :read_data)
|
49
|
+
return data
|
50
|
+
end
|
51
|
+
|
52
|
+
# Continuously evalutes the given block until it returns at
|
53
|
+
# least the given value (that is, until the block returns a
|
54
|
+
# value equal or greater than the given argument). If no
|
55
|
+
# value is specified, the block will be continuously
|
56
|
+
# evaluated until it returns true. Optionally, a comparison
|
57
|
+
# operator can be specified as the second parameter,
|
58
|
+
# otherwise >= is used (or == if expected value is Boolean).
|
59
|
+
#
|
60
|
+
# Simple example:
|
61
|
+
#
|
62
|
+
# ts = TouchSensor.new(@nxt)
|
63
|
+
# ts.wait_for_event { ts.is_pressed? }
|
64
|
+
#
|
65
|
+
# Example with an expected value:
|
66
|
+
#
|
67
|
+
# ls = LightSensor.new(@nxt)
|
68
|
+
# ls.wait_for_event(0.55) do
|
69
|
+
# ls.get_light_level
|
70
|
+
# end
|
71
|
+
#
|
72
|
+
def wait_for_event(expected = true, operator = nil)
|
73
|
+
if operator
|
74
|
+
comp = operator
|
75
|
+
elsif expected.respond_to? '>='.intern
|
76
|
+
comp = ">="
|
77
|
+
else
|
78
|
+
comp = "=="
|
79
|
+
end
|
80
|
+
|
81
|
+
while true
|
82
|
+
value = yield
|
83
|
+
return value if eval("value #{comp} expected")
|
84
|
+
sleep(POLL_INTERVAL)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
def off
|
89
|
+
# Turns off the sensor.
|
90
|
+
set_input_mode(NXTComm::NO_SENSOR, NXTComm::RAWMODE)
|
91
|
+
end
|
92
|
+
|
93
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
# ruby-nxt Control Mindstorms NXT via Bluetooth Serial Port Connection
|
2
|
+
# Copyright (C) 2006 Matt Zukowski <matt@roughest.net>
|
3
|
+
#
|
4
|
+
# This program is free software; you can redistribute it and/or modify
|
5
|
+
# it under the terms of the GNU General Public License as published by
|
6
|
+
# the Free Software Foundation; either version 2 of the License
|
7
|
+
#
|
8
|
+
# This program is distributed in the hope that it will be useful,
|
9
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
10
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
11
|
+
# GNU General Public License for more details.
|
12
|
+
#
|
13
|
+
# You should have received a copy of the GNU General Public License
|
14
|
+
# along with this program; if not, write to the Free Software Foundation,
|
15
|
+
# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
16
|
+
|
17
|
+
require 'yaml'
|
18
|
+
|
19
|
+
require File.dirname(File.expand_path(__FILE__))+'/sensor'
|
20
|
+
|
21
|
+
class SoundSensor < Sensor
|
22
|
+
|
23
|
+
def initialize(nxt, port = NXTComm::SENSOR_2)
|
24
|
+
super(nxt, port)
|
25
|
+
use_adjusted_mode
|
26
|
+
end
|
27
|
+
|
28
|
+
# Get the current sound level as a float from 0 to 1.0.
|
29
|
+
# 1.0 is maximum, 0 is minimum.
|
30
|
+
def get_sound_level
|
31
|
+
# TODO: should probably do some basic calibration here...
|
32
|
+
read_data[:value_normal] / 1023.to_f
|
33
|
+
end
|
34
|
+
|
35
|
+
# Sound level measurement is NOT adjusted to match the psychoacoustic properties
|
36
|
+
# of human hearing. Sounds that may not be loud to the human ear may show up as loud
|
37
|
+
# and vice versa.
|
38
|
+
def use_unadjusted_mode
|
39
|
+
set_input_mode(NXTComm::SOUND_DB, NXTComm::RAWMODE)
|
40
|
+
end
|
41
|
+
|
42
|
+
# Sound level measurement is adjusted to match the psychoacoustic properties of
|
43
|
+
# human hearing. This is on by default.
|
44
|
+
def use_adjusted_mode
|
45
|
+
set_input_mode(NXTComm::SOUND_DBA, NXTComm::RAWMODE)
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# ruby-nxt Control Mindstorms NXT via Bluetooth Serial Port Connection
|
2
|
+
# Copyright (C) 2006 Matt Zukowski <matt@roughest.net>
|
3
|
+
#
|
4
|
+
# This program is free software; you can redistribute it and/or modify
|
5
|
+
# it under the terms of the GNU General Public License as published by
|
6
|
+
# the Free Software Foundation; either version 2 of the License
|
7
|
+
#
|
8
|
+
# This program is distributed in the hope that it will be useful,
|
9
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
10
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
11
|
+
# GNU General Public License for more details.
|
12
|
+
#
|
13
|
+
# You should have received a copy of the GNU General Public License
|
14
|
+
# along with this program; if not, write to the Free Software Foundation,
|
15
|
+
# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
16
|
+
|
17
|
+
require 'yaml'
|
18
|
+
|
19
|
+
require File.dirname(File.expand_path(__FILE__))+'/sensor'
|
20
|
+
|
21
|
+
class TouchSensor < Sensor
|
22
|
+
|
23
|
+
def initialize(nxt, port = NXTComm::SENSOR_1)
|
24
|
+
super(nxt, port)
|
25
|
+
set_input_mode(NXTComm::SWITCH, NXTComm::BOOLEANMODE)
|
26
|
+
end
|
27
|
+
|
28
|
+
# Returns true if the touch sensor is pressed, false otherwise.
|
29
|
+
# (The sensor seems to read as "pressed" when it is pushed in about half way)
|
30
|
+
def is_pressed?
|
31
|
+
read_data[:value_scaled] > 0
|
32
|
+
end
|
33
|
+
alias_method :pressed?, :is_pressed?
|
34
|
+
|
35
|
+
end
|
@@ -0,0 +1,95 @@
|
|
1
|
+
# ruby-nxt Control Mindstorms NXT via Bluetooth Serial Port Connection
|
2
|
+
# Copyright (C) 2006 Matt Zukowski <matt@roughest.net>
|
3
|
+
#
|
4
|
+
# This program is free software; you can redistribute it and/or modify
|
5
|
+
# it under the terms of the GNU General Public License as published by
|
6
|
+
# the Free Software Foundation; either version 2 of the License
|
7
|
+
#
|
8
|
+
# This program is distributed in the hope that it will be useful,
|
9
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
10
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
11
|
+
# GNU General Public License for more details.
|
12
|
+
#
|
13
|
+
# You should have received a copy of the GNU General Public License
|
14
|
+
# along with this program; if not, write to the Free Software Foundation,
|
15
|
+
# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
16
|
+
#
|
17
|
+
require File.dirname(File.expand_path(__FILE__))+'/sensor'
|
18
|
+
require File.dirname(File.expand_path(__FILE__))+'/../ultrasonic_comm'
|
19
|
+
|
20
|
+
class UltrasonicSensor < Sensor
|
21
|
+
|
22
|
+
INCHES_PER_CM = 0.3937008
|
23
|
+
|
24
|
+
def initialize(nxt, port = NXTComm::SENSOR_4)
|
25
|
+
super(nxt, port)
|
26
|
+
|
27
|
+
# The Ultrasonic sensor is digital and unlike the other sensors it
|
28
|
+
# uses the lowspeed communication protocol.
|
29
|
+
set_input_mode(NXTComm::LOWSPEED_9V, NXTComm::RAWMODE)
|
30
|
+
|
31
|
+
# Read the sensor in case there was some garbage data in the buffer waiting to be read
|
32
|
+
@nxt.ls_read(@port)
|
33
|
+
|
34
|
+
# Set the sensor to continuously send pings
|
35
|
+
@nxt.ls_write(@port, UltrasonicComm.continuous_measurement_command)
|
36
|
+
end
|
37
|
+
|
38
|
+
# Return the measured distance in the default units (the default units being centimeters).
|
39
|
+
# A value of 255 is returned when the sensor cannot get an accurate reading (because
|
40
|
+
# the object is out of range, or there is too much interference, etc.)
|
41
|
+
# Note that the sensor's real-world range is at best 175 cm. At larger distances it
|
42
|
+
# will almost certainly just return 255.
|
43
|
+
def get_distance
|
44
|
+
@nxt.ls_write(@port, UltrasonicComm.read_measurement_byte(0))
|
45
|
+
|
46
|
+
# Keep checking until we have 1 byte of data to read
|
47
|
+
while @nxt.ls_get_status(@port)[0] < 1
|
48
|
+
sleep(0.1)
|
49
|
+
@nxt.ls_write(@port, UltrasonicComm.read_measurement_byte(0))
|
50
|
+
# TODO: implement timeout so we don't get stuck if the expected data never comes
|
51
|
+
end
|
52
|
+
|
53
|
+
resp = @nxt.ls_read(@port)
|
54
|
+
# TODO: probably need a better error message here...
|
55
|
+
raise "ls_read returned more than one byte!" if resp[:bytes_read] > 1
|
56
|
+
raise "ls_read did not return any data!" if resp[:bytes_read] < 1
|
57
|
+
|
58
|
+
# If the sensor cannot determine the distance, it will return
|
59
|
+
# 0xff (255)... this usually means that the object is out of
|
60
|
+
# sensor range, but it can also mean that there is too much
|
61
|
+
# interference or that the object is too close to the sensor.
|
62
|
+
# I considered returning nil or false under such cases, but
|
63
|
+
# this makes numeric comparison (i.e. greather than/less than)
|
64
|
+
# more difficult
|
65
|
+
d = resp[:data][0]
|
66
|
+
end
|
67
|
+
alias_method :get_distance_in_cm, :get_distance
|
68
|
+
|
69
|
+
# Return the measured distance in inches.
|
70
|
+
def get_distance_in_inches
|
71
|
+
get_distance.to_f * INCHES_PER_CM
|
72
|
+
end
|
73
|
+
|
74
|
+
# Same as get_distance, but raises an UnmeasurableDistance
|
75
|
+
# exception when the sensor cannot accurately determine
|
76
|
+
# the distance.
|
77
|
+
def get_distance!
|
78
|
+
d = get_distance
|
79
|
+
if d == 255
|
80
|
+
raise UnmeasurableDistance
|
81
|
+
else
|
82
|
+
return d
|
83
|
+
end
|
84
|
+
end
|
85
|
+
alias_method :get_distance_in_cm!, :get_distance!
|
86
|
+
|
87
|
+
def get_distance_in_inches!
|
88
|
+
get_distance!.to_f * INCHES_PER_CM
|
89
|
+
end
|
90
|
+
|
91
|
+
# Exception thrown by get_distance! and related methods when
|
92
|
+
# the sensor cannot determine the distance.
|
93
|
+
class UnmeasurableDistance < Exception; end
|
94
|
+
|
95
|
+
end
|
@@ -0,0 +1,102 @@
|
|
1
|
+
# ruby-nxt Control Mindstorms NXT via Bluetooth Serial Port Connection
|
2
|
+
# Copyright (C) 2006 Matt Zukowski <matt@roughest.net>
|
3
|
+
#
|
4
|
+
# This program is free software; you can redistribute it and/or modify
|
5
|
+
# it under the terms of the GNU General Public License as published by
|
6
|
+
# the Free Software Foundation; either version 2 of the License
|
7
|
+
#
|
8
|
+
# This program is distributed in the hope that it will be useful,
|
9
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
10
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
11
|
+
# GNU General Public License for more details.
|
12
|
+
#
|
13
|
+
# You should have received a copy of the GNU General Public License
|
14
|
+
# along with this program; if not, write to the Free Software Foundation,
|
15
|
+
# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
16
|
+
|
17
|
+
|
18
|
+
# Low-level interface for communicating with the NXT's Ultrasonic
|
19
|
+
# sensor. Unlike the other sensors, the Ultrasonic sensor is digital
|
20
|
+
# and uses the low-speed I2C protocol for communication. This is
|
21
|
+
# defined in Appendix 7 of the Lego Mindstorms NXT SDK.
|
22
|
+
class UltrasonicComm
|
23
|
+
|
24
|
+
@@i2c_dev = 0x02
|
25
|
+
|
26
|
+
# first value is the i2c address, second value is the expected number of bytes returned
|
27
|
+
@@const_codes = {
|
28
|
+
'read_version' => [0x00, 8],
|
29
|
+
'read_product_id' => [0x08, 8],
|
30
|
+
'read_sensor_type' => [0x10, 8],
|
31
|
+
'read_factory_zero' => [0x11, 1],
|
32
|
+
'read_factory_scale_factor' => [0x12, 1],
|
33
|
+
'read_factory_scale_divisor' => [0x13, 1],
|
34
|
+
'read_measurement_units' => [0x14, 7],
|
35
|
+
}
|
36
|
+
|
37
|
+
# value is the i2c address (all of these ops always expect to return 1 byte)
|
38
|
+
@@var_codes = {
|
39
|
+
'read_continuous_measurements_interval' => 0x40,
|
40
|
+
'read_command_state' => 0x41,
|
41
|
+
'read_measurement_byte_0' => 0x42,
|
42
|
+
'read_measurement_byte_1' => 0x43,
|
43
|
+
'read_measurement_byte_2' => 0x44,
|
44
|
+
'read_measurement_byte_3' => 0x45,
|
45
|
+
'read_measurement_byte_4' => 0x46,
|
46
|
+
'read_measurement_byte_5' => 0x47,
|
47
|
+
'read_measurement_byte_6' => 0x48,
|
48
|
+
'read_measurement_byte_7' => 0x49,
|
49
|
+
'read_actual_zero' => 0x50,
|
50
|
+
'read_actual_scale_factor' => 0x51,
|
51
|
+
'read_actual_scale_divisor' => 0x52,
|
52
|
+
}
|
53
|
+
|
54
|
+
# first value is the i2c address, second value is the command
|
55
|
+
@@cmd_codes = {
|
56
|
+
'off_command' => [0x41, 0x00],
|
57
|
+
'single_shot_command' => [0x41, 0x01],
|
58
|
+
'continuous_measurement_command' => [0x41, 0x02],
|
59
|
+
'event_capture_command' => [0x41, 0x03],
|
60
|
+
'request_warm_reset' => [0x41, 0x04],
|
61
|
+
'set_continuous_measurement_interval' => [0x40],
|
62
|
+
'set_actual_zero' => [0x50],
|
63
|
+
'set_actual_scale_factor' => [0x51],
|
64
|
+
'set_actual_scale_divisor' => [0x52]
|
65
|
+
}
|
66
|
+
|
67
|
+
|
68
|
+
def self.read_measurement_byte(num)
|
69
|
+
eval "self.read_measurement_byte_#{num}"
|
70
|
+
end
|
71
|
+
|
72
|
+
def self.method_missing(name, *args)
|
73
|
+
name = name.to_s
|
74
|
+
if @@const_codes.has_key? name
|
75
|
+
type = :const
|
76
|
+
op = @@const_codes[name]
|
77
|
+
addr = op[0]
|
78
|
+
rx_len = op[1]
|
79
|
+
elsif @@var_codes.has_key? name
|
80
|
+
type = :var
|
81
|
+
op = @@var_codes[name]
|
82
|
+
addr = op
|
83
|
+
rx_len = 1
|
84
|
+
elsif @@cmd_codes.has_key? name
|
85
|
+
type = :cmd
|
86
|
+
op = @@cmd_codes[name]
|
87
|
+
addr = op[0]
|
88
|
+
if op[1] then value = op[1]
|
89
|
+
elsif args[0] then value = args[0]
|
90
|
+
else raise "Missing argument for command #{name}" end
|
91
|
+
rx_len = 0
|
92
|
+
else
|
93
|
+
raise "Unknown ultrasonic sensor command: #{name}"
|
94
|
+
end
|
95
|
+
|
96
|
+
data = [@@i2c_dev, addr]
|
97
|
+
data += [value] if type == :cmd
|
98
|
+
|
99
|
+
[data.size, rx_len] + data
|
100
|
+
end
|
101
|
+
|
102
|
+
end
|
data/test/bt_test.rb
ADDED
@@ -0,0 +1,89 @@
|
|
1
|
+
# ruby-nxt Control Mindstorms NXT via Bluetooth Serial Port Connection
|
2
|
+
# Copyright (C) 2006 Matt Zukowski <matt@roughest.net>
|
3
|
+
#
|
4
|
+
# This program is free software; you can redistribute it and/or modify
|
5
|
+
# it under the terms of the GNU General Public License as published by
|
6
|
+
# the Free Software Foundation; either version 2 of the License
|
7
|
+
#
|
8
|
+
# This program is distributed in the hope that it will be useful,
|
9
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
10
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
11
|
+
# GNU General Public License for more details.
|
12
|
+
#
|
13
|
+
# You should have received a copy of the GNU General Public License
|
14
|
+
# along with this program; if not, write to the Free Software Foundation,
|
15
|
+
# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
16
|
+
|
17
|
+
begin
|
18
|
+
require 'rubygems'
|
19
|
+
require_gem "term-ansicolor"
|
20
|
+
$COLOUR = true
|
21
|
+
rescue LoadError
|
22
|
+
$COLOUR = false
|
23
|
+
puts "Please install term-ansicolor gem to get colour output."
|
24
|
+
puts "Colour output will be disabled..."
|
25
|
+
puts
|
26
|
+
end
|
27
|
+
|
28
|
+
module InteractiveTestHelper
|
29
|
+
def info(msg)
|
30
|
+
msg = Term::ANSIColor.white(msg) if $COLOUR
|
31
|
+
puts "#{msg}"
|
32
|
+
end
|
33
|
+
|
34
|
+
def notice(msg)
|
35
|
+
msg = Term::ANSIColor.yellow(msg) if $COLOUR
|
36
|
+
puts "#{msg}"
|
37
|
+
end
|
38
|
+
|
39
|
+
def prompt(msg)
|
40
|
+
msg = Term::ANSIColor.cyan(msg) if $COLOUR
|
41
|
+
puts "#{msg}"
|
42
|
+
return gets
|
43
|
+
end
|
44
|
+
|
45
|
+
def pass(msg)
|
46
|
+
msg = Term::ANSIColor.green(msg) if $COLOUR
|
47
|
+
msg = Term::ANSIColor.bold(msg) if $COLOUR
|
48
|
+
puts "#{msg}"
|
49
|
+
end
|
50
|
+
|
51
|
+
def fail(msg)
|
52
|
+
msg = Term::ANSIColor.red(msg) if $COLOUR
|
53
|
+
msg = Term::ANSIColor.red(msg) if $COLOUR
|
54
|
+
puts "#{msg}"
|
55
|
+
end
|
56
|
+
|
57
|
+
def puts_sameline(msg)
|
58
|
+
puts "#{msg}"
|
59
|
+
puts "\e[2A"
|
60
|
+
end
|
61
|
+
|
62
|
+
def meter(value, label = "Level", threshold = nil, max = 100, min = 0)
|
63
|
+
width = 40
|
64
|
+
if value.nil?
|
65
|
+
bars = "?" * width
|
66
|
+
spaces = ""
|
67
|
+
percent_formatted = " ??? "
|
68
|
+
else
|
69
|
+
if value >= max
|
70
|
+
percent = 1.0
|
71
|
+
else
|
72
|
+
percent = ((value - min) / max.to_f)
|
73
|
+
end
|
74
|
+
bars = "|" * (percent * width)
|
75
|
+
spaces = " " * ((1 - percent) * width)
|
76
|
+
|
77
|
+
percent_formatted = "%5.1f" % (percent * 100)
|
78
|
+
end
|
79
|
+
meterbar = bars + spaces
|
80
|
+
|
81
|
+
if threshold
|
82
|
+
threshold_pos = (((threshold - min) / max.to_f) * 40).to_i
|
83
|
+
meterbar[threshold_pos] = "!"
|
84
|
+
end
|
85
|
+
|
86
|
+
puts_sameline " #{label}: (#{percent_formatted}%) [#{min}]#{meterbar}[#{max}]"
|
87
|
+
end
|
88
|
+
|
89
|
+
end
|