rad 0.2.9 → 0.3.0

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.
@@ -1,3 +1,8 @@
1
+ == 0.3.0 2008-09-22
2
+ * Pushing to rubyforge..
3
+ - added rad install arduino
4
+ - added rad test arduino
5
+
1
6
  == 0.2.5 2008-07-21
2
7
  * 1ish large post Bastille Day update:
3
8
  - added i2c capability
@@ -37,6 +37,7 @@ lib/examples/motor_knob.rb
37
37
  lib/examples/servo_buttons.rb
38
38
  lib/examples/servo_calibrate_continuous.rb
39
39
  lib/examples/servo_throttle.rb
40
+ lib/examples/software_serial.rb
40
41
  lib/examples/sparkfun_lcd.rb
41
42
  lib/examples/spectra_soft_pot.rb
42
43
  lib/examples/times_method.rb
@@ -104,6 +105,7 @@ lib/rad/generators/makefile/makefile.erb
104
105
  lib/rad/generators/makefile/makefile.rb
105
106
  lib/rad/hardware_library.rb
106
107
  lib/rad/init.rb
108
+ lib/rad/progressbar.rb
107
109
  lib/rad/rad_processor.rb
108
110
  lib/rad/rad_rewriter.rb
109
111
  lib/rad/rad_type_checker.rb
@@ -123,6 +125,8 @@ spec/models/sketch_compiler_spec.rb
123
125
  spec/models/spec_helper.rb
124
126
  spec/sim/hello_world_spec.rb
125
127
  spec/spec.opts
128
+ test/hello_world_test/Makefile
129
+ test/hello_world_test/hello_world.cpp
126
130
  test/test_array_processing.rb
127
131
  test/test_plugin_loading.rb
128
132
  test/test_translation_post_processing.rb
data/bin/rad CHANGED
@@ -9,8 +9,11 @@ end
9
9
  require 'optparse'
10
10
  require 'fileutils'
11
11
  require 'yaml'
12
+ require 'open-uri'
13
+ require 'readline'
12
14
 
13
15
  require File.expand_path(File.dirname(__FILE__)) + "/../lib/rad/version.rb"
16
+ require File.expand_path(File.dirname(__FILE__)) + "/../lib/rad/progressbar.rb"
14
17
 
15
18
  class OptionParser #:nodoc:
16
19
 
@@ -23,7 +26,7 @@ class OptionParser #:nodoc:
23
26
  "physical_reset" => false
24
27
  },
25
28
  "software" => {
26
- "arduino_root" => "/Applications/arduino-0011"
29
+ "arduino_root" => "/Applications/arduino-0012"
27
30
  }
28
31
  }
29
32
 
@@ -90,158 +93,218 @@ end
90
93
  #
91
94
 
92
95
 
93
- # Handle options:
94
- options, parser = OptionParser.parse(ARGV)
95
- sketch_name = ARGV[0]
96
- parser.parse!(["-h"]) unless sketch_name
96
+ if ARGV[0] == "install"
97
+ raise "Sorry. Can only install Arduino on Mac OS X. See here for Linux instructions: http://www.arduino.cc/playground/Learning/Linux" unless RUBY_PLATFORM =~ /darwin/
98
+ puts "Downloading arduino-0012 for Mac from Arduino.cc"
99
+ File.open("/Applications/arduino-0012.zip", "w") do |file|
100
+ pbar = nil
101
+ file << open("http://www.arduino.cc/files/arduino-0012-mac.zip",
102
+ :content_length_proc => lambda {|t|
103
+ if t && 0 < t
104
+ pbar = ProgressBar.new(" Progress", t)
105
+ pbar.file_transfer_mode
106
+ end
107
+ },
108
+ :progress_proc => lambda {|s|
109
+ pbar.set s if pbar
110
+ }).read
111
+ pbar.finish
112
+ end
113
+ puts "Unzipping..."
114
+ `cd /Applications; unzip arduino-0012.zip`
115
+ `rm /Applications/arduino-0012.zip`
116
+ puts "installed Arduino here: /Applications/arduino-0012"
117
+ elsif ARGV[0] == "test"
118
+ test_dir = File.expand_path(File.dirname(__FILE__)) + "/../test/hello_world_test"
119
+ puts "Compiling hello_world.cpp to test your Arduino."
120
+ puts "cd #{test_dir}; make depend; make;"
121
+ `cd #{test_dir}; make depend; make;`
122
+ puts
123
+ puts "Compilation successful."
124
+ puts
125
+ puts "Make sure your Arduino is connected and then hit return."
126
+ Readline::readline('')
97
127
 
98
-
99
- # Build vendor/rad:
128
+ `cd #{test_dir}; make upload`
100
129
 
101
- FileUtils.mkdir_p "#{sketch_name}/vendor/rad"
102
- puts "Successfully created your sketch directory."
103
-
104
- FileUtils.cp_r "#{File.dirname(__FILE__)}/../lib/rad/.", "#{sketch_name}/vendor/rad"
105
- puts "Installed RAD into #{sketch_name}/vendor/rad"
106
- puts
107
-
108
- # Build vendor/libraries:
109
-
110
- FileUtils.mkdir_p "#{sketch_name}/vendor/libraries"
111
- puts "Successfully created your libraries directory."
112
- puts
113
-
114
- FileUtils.cp_r "#{File.dirname(__FILE__)}/../lib/libraries/AF_XPort/.", "#{sketch_name}/vendor/libraries/AF_XPort"
115
- puts "Installed AF_XPort into #{sketch_name}/vendor/libraries"
116
- puts
117
-
118
- FileUtils.cp_r "#{File.dirname(__FILE__)}/../lib/libraries/AFSoftSerial/.", "#{sketch_name}/vendor/libraries/AFSoftSerial"
119
- puts "Installed AFSoftSerial into #{sketch_name}/vendor/libraries"
120
- puts
121
-
122
- FileUtils.cp_r "#{File.dirname(__FILE__)}/../lib/libraries/DS1307/.", "#{sketch_name}/vendor/libraries/DS1307"
123
- puts "Installed DS1307 into #{sketch_name}/vendor/libraries"
124
- puts
125
-
126
- FileUtils.cp_r "#{File.dirname(__FILE__)}/../lib/libraries/FrequencyTimer2/.", "#{sketch_name}/vendor/libraries/FrequencyTimer2"
127
- puts "Installed FrequencyTimer2 into #{sketch_name}/vendor/libraries"
128
- puts
129
-
130
- FileUtils.cp_r "#{File.dirname(__FILE__)}/../lib/libraries/I2CEEPROM/.", "#{sketch_name}/vendor/libraries/I2CEEPROM"
131
- puts "Installed I2CEEPROM into #{sketch_name}/vendor/libraries"
132
- puts
133
-
134
- FileUtils.cp_r "#{File.dirname(__FILE__)}/../lib/libraries/LoopTimer/.", "#{sketch_name}/vendor/libraries/LoopTimer"
135
- puts "Installed LoopTimer into #{sketch_name}/vendor/libraries"
136
- puts
137
-
138
- FileUtils.cp_r "#{File.dirname(__FILE__)}/../lib/libraries/OneWire/.", "#{sketch_name}/vendor/libraries/OneWire"
139
- puts "Installed OneWire into #{sketch_name}/vendor/libraries"
140
- puts
141
-
142
- FileUtils.cp_r "#{File.dirname(__FILE__)}/../lib/libraries/Servo/.", "#{sketch_name}/vendor/libraries/Servo"
143
- puts "Installed Servo into #{sketch_name}/vendor/libraries"
144
- puts
145
-
146
- FileUtils.cp_r "#{File.dirname(__FILE__)}/../lib/libraries/Stepper/.", "#{sketch_name}/vendor/libraries/Stepper"
147
- puts "Installed Stepper into #{sketch_name}/vendor/libraries"
148
- puts
149
-
150
- FileUtils.cp_r "#{File.dirname(__FILE__)}/../lib/libraries/SWSerLCDpa/.", "#{sketch_name}/vendor/libraries/SWSerLCDpa"
151
- puts "Installed SWSerLCDpa into #{sketch_name}/vendor/libraries"
152
- puts
153
-
154
- FileUtils.cp_r "#{File.dirname(__FILE__)}/../lib/libraries/SWSerLCDsf/.", "#{sketch_name}/vendor/libraries/SWSerLCDsf"
155
- puts "Installed SWSerLCDsf into #{sketch_name}/vendor/libraries"
156
- puts
157
-
158
- FileUtils.cp_r "#{File.dirname(__FILE__)}/../lib/libraries/Wire/.", "#{sketch_name}/vendor/libraries/Wire"
159
- puts "Installed Wire into #{sketch_name}/vendor/libraries"
160
- puts
161
-
162
- # Build examples -- used for basic testing
163
-
164
- FileUtils.mkdir_p "#{sketch_name}/vendor/libraries"
165
- puts "Successfully created your examples directory."
166
-
167
- FileUtils.cp_r "#{File.dirname(__FILE__)}/../lib/examples/.", "#{sketch_name}/examples"
168
- puts "Installed examples into #{sketch_name}/examples"
169
- puts
170
-
171
- # Build test -- used testing
172
-
173
- # FIXME: this should put the tests into the vendor/tests directory instead.
174
-
175
- # FileUtils.mkdir_p "#{sketch_name}/test"
176
- # puts "Successfully created your test directory."
177
- #
178
- # FileUtils.cp_r "#{File.dirname(__FILE__)}/../lib/test/.", "#{sketch_name}/test"
179
- # puts "Installed tests into #{sketch_name}/test"
180
- # puts
181
-
182
- # Build vendor/plugins:
183
-
184
- FileUtils.mkdir_p "#{sketch_name}/vendor/plugins"
185
- puts "Successfully created your plugins directory."
186
- puts
187
-
188
- FileUtils.cp_r "#{File.dirname(__FILE__)}/../lib/plugins/.", "#{sketch_name}/vendor/plugins"
189
- puts "Installed Default plugins into #{sketch_name}/vendor/plugins"
190
- puts
191
-
192
- # Add an default sketch directory # needed to run test:compile
193
-
194
- FileUtils.mkdir_p "#{sketch_name}/#{sketch_name}"
195
- puts "Successfully created your default sketch directory."
196
- puts
197
-
198
- # Copy the README how_to to the sketch directory
199
-
200
- FileUtils.cp_r "#{File.dirname(__FILE__)}/../lib/rad/README.rdoc", "#{sketch_name}"
201
- puts "Copied README how_to into #{sketch_name}"
202
- puts
203
-
204
-
205
- # Build sketch files, etc.:
206
-
207
- FileUtils.touch "#{sketch_name}/#{sketch_name}.rb"
208
- File.open("#{sketch_name}/#{sketch_name}.rb", "w") do |file|
209
- file << <<-EOS
210
- class #{sketch_name.split("_").collect{|c| c.capitalize}.join("")} < ArduinoSketch
211
-
212
- # looking for hints? check out the examples directory
213
- # example sketches can be uploaded to your arduino with
214
- # rake make:upload sketch=examples/hello_world
215
- # just replace hello_world with other examples
216
-
217
- def loop
218
- # your code here
219
- end
130
+ # find the USB port to make sure the Arduino's actually plugged in
131
+ options, parser = OptionParser.parse(ARGV)
132
+ usb_port = options["hardware"]["serial_port"]
133
+ port_name = usb_port.split("/").last
134
+ port_dir = usb_port.split("/")[0..(usb_port.split("/").length-2)].join("/")
135
+ unless `ls #{port_dir}`.split(/\n/).any?{|d| d.match(/#{port_name}/)}
136
+ puts
137
+ puts "******************************************************"
138
+ puts "*** It looks like your Arduino is not plugged in. ***"
139
+ puts "*** Plug it in and try again. ***"
140
+ puts "*** ***"
141
+ puts "*** NOTE: If your usb port is not /dev/tty.usb* ***"
142
+ puts "*** pass it in to this script with the -p option. ***"
143
+ puts "******************************************************"
144
+ else
145
+ puts
146
+ puts "******************************************************"
147
+ puts "*** Success! ***"
148
+ puts "*** If your Arduino's light starts blinking soon, ***"
149
+ puts "*** then your Arduino environment is ***"
150
+ puts "*** correctly configured. ***"
151
+ puts "*** ***"
152
+ puts "*** Otherwise something is not hooked up properly. ***"
153
+ puts "******************************************************"
154
+ end
155
+ puts
156
+ puts "cleaning up..."
157
+ `rm #{test_dir}/hello_world.hex #{test_dir}/core.a #{test_dir}/hello_world.elf`
158
+ else
159
+ # Handle options:
160
+ options, parser = OptionParser.parse(ARGV)
161
+ sketch_name = ARGV[0]
162
+ parser.parse!(["-h"]) unless sketch_name
220
163
 
221
- end
222
- EOS
223
- end
224
- puts "Added #{sketch_name}/#{sketch_name}.rb"
225
-
226
- File.open("#{sketch_name}/Rakefile", 'w') do |file|
227
- file << <<-EOS
228
- require 'vendor/rad/init.rb'
229
- EOS
230
- end
231
- puts "Added #{sketch_name}/Rakefile"
232
-
233
- FileUtils.mkdir_p "#{sketch_name}/config"
234
- puts "Added #{sketch_name}/config"
235
-
236
- File.open("#{sketch_name}/config/hardware.yml", 'w') do |file|
237
- file << options["hardware"].to_yaml
238
- end
239
- puts "Added #{sketch_name}/config/hardware.yml"
240
-
241
- File.open("#{sketch_name}/config/software.yml", 'w') do |file|
242
- file << options["software"].to_yaml
243
- end
244
- puts "Added #{sketch_name}/config/software.yml"
164
+
165
+ # Build vendor/rad:
166
+
167
+ FileUtils.mkdir_p "#{sketch_name}/vendor/rad"
168
+ puts "Successfully created your sketch directory."
169
+
170
+ FileUtils.cp_r "#{File.dirname(__FILE__)}/../lib/rad/.", "#{sketch_name}/vendor/rad"
171
+ puts "Installed RAD into #{sketch_name}/vendor/rad"
172
+ puts
173
+
174
+ # Build vendor/libraries:
175
+
176
+ FileUtils.mkdir_p "#{sketch_name}/vendor/libraries"
177
+ puts "Successfully created your libraries directory."
178
+
179
+ FileUtils.cp_r "#{File.dirname(__FILE__)}/../lib/libraries/AF_XPort/.", "#{sketch_name}/vendor/libraries/AF_XPort"
180
+ puts "Installed AF_XPort into #{sketch_name}/vendor/libraries"
181
+ puts
245
182
 
246
- puts
247
- puts "Run 'rake -T' inside your sketch dir to learn how to compile and upload it."
183
+ FileUtils.cp_r "#{File.dirname(__FILE__)}/../lib/libraries/AFSoftSerial/.", "#{sketch_name}/vendor/libraries/AFSoftSerial"
184
+ puts "Installed AFSoftSerial into #{sketch_name}/vendor/libraries"
185
+ puts
186
+
187
+ FileUtils.cp_r "#{File.dirname(__FILE__)}/../lib/libraries/DS1307/.", "#{sketch_name}/vendor/libraries/DS1307"
188
+ puts "Installed DS1307 into #{sketch_name}/vendor/libraries"
189
+ puts
190
+
191
+ FileUtils.cp_r "#{File.dirname(__FILE__)}/../lib/libraries/FrequencyTimer2/.", "#{sketch_name}/vendor/libraries/FrequencyTimer2"
192
+ puts "Installed FrequencyTimer2 into #{sketch_name}/vendor/libraries"
193
+ puts
194
+
195
+ FileUtils.cp_r "#{File.dirname(__FILE__)}/../lib/libraries/I2CEEPROM/.", "#{sketch_name}/vendor/libraries/I2CEEPROM"
196
+ puts "Installed I2CEEPROM into #{sketch_name}/vendor/libraries"
197
+ puts
198
+
199
+ FileUtils.cp_r "#{File.dirname(__FILE__)}/../lib/libraries/LoopTimer/.", "#{sketch_name}/vendor/libraries/LoopTimer"
200
+ puts "Installed LoopTimer into #{sketch_name}/vendor/libraries"
201
+ puts
202
+
203
+ FileUtils.cp_r "#{File.dirname(__FILE__)}/../lib/libraries/OneWire/.", "#{sketch_name}/vendor/libraries/OneWire"
204
+ puts "Installed OneWire into #{sketch_name}/vendor/libraries"
205
+ puts
206
+
207
+ FileUtils.cp_r "#{File.dirname(__FILE__)}/../lib/libraries/Servo/.", "#{sketch_name}/vendor/libraries/Servo"
208
+ puts "Installed Servo into #{sketch_name}/vendor/libraries"
209
+ puts
210
+
211
+ FileUtils.cp_r "#{File.dirname(__FILE__)}/../lib/libraries/Stepper/.", "#{sketch_name}/vendor/libraries/Stepper"
212
+ puts "Installed Stepper into #{sketch_name}/vendor/libraries"
213
+ puts
214
+
215
+ FileUtils.cp_r "#{File.dirname(__FILE__)}/../lib/libraries/SWSerLCDpa/.", "#{sketch_name}/vendor/libraries/SWSerLCDpa"
216
+ puts "Installed SWSerLCDpa into #{sketch_name}/vendor/libraries"
217
+ puts
218
+
219
+ FileUtils.cp_r "#{File.dirname(__FILE__)}/../lib/libraries/SWSerLCDsf/.", "#{sketch_name}/vendor/libraries/SWSerLCDsf"
220
+ puts "Installed SWSerLCDsf into #{sketch_name}/vendor/libraries"
221
+ puts
222
+
223
+ FileUtils.cp_r "#{File.dirname(__FILE__)}/../lib/libraries/Wire/.", "#{sketch_name}/vendor/libraries/Wire"
224
+ puts "Installed Wire into #{sketch_name}/vendor/libraries"
225
+ puts
226
+
227
+ # Build examples -- used for basic testing
228
+
229
+ FileUtils.mkdir_p "#{sketch_name}/vendor/libraries"
230
+ puts "Successfully created your examples directory."
231
+
232
+ FileUtils.cp_r "#{File.dirname(__FILE__)}/../lib/examples/.", "#{sketch_name}/examples"
233
+ puts "Installed examples into #{sketch_name}/examples"
234
+ puts
235
+
236
+ # Build test -- used testing
237
+
238
+ # FIXME: this should put the tests into the vendor/tests directory instead.
239
+
240
+ # FileUtils.mkdir_p "#{sketch_name}/test"
241
+ # puts "Successfully created your test directory."
242
+ #
243
+ # FileUtils.cp_r "#{File.dirname(__FILE__)}/../lib/test/.", "#{sketch_name}/test"
244
+ # puts "Installed tests into #{sketch_name}/test"
245
+ # puts
246
+
247
+ # Build vendor/plugins:
248
+
249
+ FileUtils.mkdir_p "#{sketch_name}/vendor/plugins"
250
+ puts "Successfully created your plugins directory."
251
+
252
+ FileUtils.cp_r "#{File.dirname(__FILE__)}/../lib/plugins/.", "#{sketch_name}/vendor/plugins"
253
+ puts "Installed Default plugins into #{sketch_name}/vendor/plugins"
254
+ puts
255
+
256
+ # Add an default sketch directory # needed to run test:compile
257
+
258
+ FileUtils.mkdir_p "#{sketch_name}/#{sketch_name}"
259
+ puts "Successfully created your default sketch directory."
260
+
261
+ # Build sketch files, etc.:
262
+
263
+ FileUtils.touch "#{sketch_name}/#{sketch_name}.rb"
264
+ File.open("#{sketch_name}/#{sketch_name}.rb", "w") do |file|
265
+ file << <<-EOS
266
+ class #{sketch_name.split("_").collect{|c| c.capitalize}.join("")} < ArduinoSketch
267
+
268
+ # looking for hints? check out the examples directory
269
+ # example sketches can be uploaded to your arduino with
270
+ # rake make:upload sketch=examples/hello_world
271
+ # just replace hello_world with other examples
272
+
273
+ def loop
274
+ # your code here
275
+ end
276
+
277
+ end
278
+ EOS
279
+ end
280
+ puts "Added #{sketch_name}/#{sketch_name}.rb"
281
+
282
+ File.open("#{sketch_name}/Rakefile", 'w') do |file|
283
+ file << <<-EOS
284
+ require 'vendor/rad/init.rb'
285
+ EOS
286
+ end
287
+ puts "Added #{sketch_name}/Rakefile"
288
+
289
+ FileUtils.mkdir_p "#{sketch_name}/config"
290
+ puts "Added #{sketch_name}/config"
291
+
292
+ File.open("#{sketch_name}/config/hardware.yml", 'w') do |file|
293
+ file << options["hardware"].to_yaml
294
+ end
295
+ puts "Added #{sketch_name}/config/hardware.yml"
296
+
297
+ File.open("#{sketch_name}/config/software.yml", 'w') do |file|
298
+ file << options["software"].to_yaml
299
+ end
300
+ puts "Added #{sketch_name}/config/software.yml"
301
+
302
+ puts
303
+ puts "Run 'rake -T' inside your sketch dir to learn how to compile and upload it."
304
+
305
+ puts "***************************************************"
306
+ puts "*** Please note: This version supports ***"
307
+ puts "*** Arduino 12 only! ***"
308
+ puts "*** run rad install arduino to upgrade ***"
309
+ puts "***************************************************"
310
+ end
@@ -0,0 +1,10 @@
1
+ class SoftwareSerial < ArduinoSketch
2
+ output_pin 13, :as => :led
3
+ software_serial 6, 7, :as => :gps
4
+ serial_begin
5
+
6
+ def loop
7
+ digitalWrite(led, true)
8
+ serial_print(gps.read)
9
+ end
10
+ end
@@ -69,7 +69,7 @@ SRC = $(ARDUINO)/pins_arduino.c $(ARDUINO)/wiring.c \
69
69
  $(ARDUINO)/wiring_analog.c $(ARDUINO)/wiring_digital.c \
70
70
  $(ARDUINO)/wiring_pulse.c $(ARDUINO)/wiring_serial.c \
71
71
  $(ARDUINO)/wiring_shift.c $(ARDUINO)/WInterrupts.c <%= params['twi_c'] %>
72
- CXXSRC = $(ARDUINO)/HardwareSerial.cpp $(SOFTWARE_SERIAL)/SoftwareSerial.cpp<%= params['libraries'].collect{|l| " $(LIBRARY_ROOT)/#{ l }/#{l }.cpp"}.join('') %>
72
+ CXXSRC = $(ARDUINO)/HardwareSerial.cpp $(SOFTWARE_SERIAL)/SoftwareSerial.cpp $(ARDUINO)/Print.cpp<%= params['libraries'].collect{|l| " $(LIBRARY_ROOT)/#{ l }/#{l }.cpp"}.join('') %>
73
73
  MCU = <%= params['mcu'] %>
74
74
  <% if params['asm_files'] %>ASRC = <%= params['asm_files'].join(' ') %><% end %>
75
75
  F_CPU = 16000000
@@ -0,0 +1,236 @@
1
+ #
2
+ # Ruby/ProgressBar - a text progress bar library
3
+ #
4
+ # Copyright (C) 2001-2005 Satoru Takabayashi <satoru@namazu.org>
5
+ # All rights reserved.
6
+ # This is free software with ABSOLUTELY NO WARRANTY.
7
+ #
8
+ # You can redistribute it and/or modify it under the terms
9
+ # of Ruby's license.
10
+ #
11
+
12
+ class ProgressBar
13
+ VERSION = "0.9"
14
+
15
+ def initialize (title, total, out = STDERR)
16
+ @title = title
17
+ @total = total
18
+ @out = out
19
+ @terminal_width = 80
20
+ @bar_mark = "o"
21
+ @current = 0
22
+ @previous = 0
23
+ @finished_p = false
24
+ @start_time = Time.now
25
+ @previous_time = @start_time
26
+ @title_width = 14
27
+ @format = "%-#{@title_width}s %3d%% %s %s"
28
+ @format_arguments = [:title, :percentage, :bar, :stat]
29
+ clear
30
+ show
31
+ end
32
+ attr_reader :title
33
+ attr_reader :current
34
+ attr_reader :total
35
+ attr_accessor :start_time
36
+
37
+ private
38
+ def fmt_bar
39
+ bar_width = do_percentage * @terminal_width / 100
40
+ sprintf("|%s%s|",
41
+ @bar_mark * bar_width,
42
+ " " * (@terminal_width - bar_width))
43
+ end
44
+
45
+ def fmt_percentage
46
+ do_percentage
47
+ end
48
+
49
+ def fmt_stat
50
+ if @finished_p then elapsed else eta end
51
+ end
52
+
53
+ def fmt_stat_for_file_transfer
54
+ if @finished_p then
55
+ sprintf("%s %s %s", bytes, transfer_rate, elapsed)
56
+ else
57
+ sprintf("%s %s %s", bytes, transfer_rate, eta)
58
+ end
59
+ end
60
+
61
+ def fmt_title
62
+ @title[0,(@title_width - 1)] + ":"
63
+ end
64
+
65
+ def convert_bytes (bytes)
66
+ if bytes < 1024
67
+ sprintf("%6dB", bytes)
68
+ elsif bytes < 1024 * 1000 # 1000kb
69
+ sprintf("%5.1fKB", bytes.to_f / 1024)
70
+ elsif bytes < 1024 * 1024 * 1000 # 1000mb
71
+ sprintf("%5.1fMB", bytes.to_f / 1024 / 1024)
72
+ else
73
+ sprintf("%5.1fGB", bytes.to_f / 1024 / 1024 / 1024)
74
+ end
75
+ end
76
+
77
+ def transfer_rate
78
+ bytes_per_second = @current.to_f / (Time.now - @start_time)
79
+ sprintf("%s/s", convert_bytes(bytes_per_second))
80
+ end
81
+
82
+ def bytes
83
+ convert_bytes(@current)
84
+ end
85
+
86
+ def format_time (t)
87
+ t = t.to_i
88
+ sec = t % 60
89
+ min = (t / 60) % 60
90
+ hour = t / 3600
91
+ sprintf("%02d:%02d:%02d", hour, min, sec);
92
+ end
93
+
94
+ # ETA stands for Estimated Time of Arrival.
95
+ def eta
96
+ if @current == 0
97
+ "ETA: --:--:--"
98
+ else
99
+ elapsed = Time.now - @start_time
100
+ eta = elapsed * @total / @current - elapsed;
101
+ sprintf("ETA: %s", format_time(eta))
102
+ end
103
+ end
104
+
105
+ def elapsed
106
+ elapsed = Time.now - @start_time
107
+ sprintf("Time: %s", format_time(elapsed))
108
+ end
109
+
110
+ def eol
111
+ if @finished_p then "\n" else "\r" end
112
+ end
113
+
114
+ def do_percentage
115
+ if @total.zero?
116
+ 100
117
+ else
118
+ @current * 100 / @total
119
+ end
120
+ end
121
+
122
+ def get_width
123
+ # FIXME: I don't know how portable it is.
124
+ default_width = 80
125
+ begin
126
+ tiocgwinsz = 0x5413
127
+ data = [0, 0, 0, 0].pack("SSSS")
128
+ if @out.ioctl(tiocgwinsz, data) >= 0 then
129
+ rows, cols, xpixels, ypixels = data.unpack("SSSS")
130
+ if cols >= 0 then cols else default_width end
131
+ else
132
+ default_width
133
+ end
134
+ rescue Exception
135
+ default_width
136
+ end
137
+ end
138
+
139
+ def show
140
+ arguments = @format_arguments.map {|method|
141
+ method = sprintf("fmt_%s", method)
142
+ send(method)
143
+ }
144
+ line = sprintf(@format, *arguments)
145
+
146
+ width = get_width
147
+ if line.length == width - 1
148
+ @out.print(line + eol)
149
+ @out.flush
150
+ elsif line.length >= width
151
+ @terminal_width = [@terminal_width - (line.length - width + 1), 0].max
152
+ if @terminal_width == 0 then @out.print(line + eol) else show end
153
+ else # line.length < width - 1
154
+ @terminal_width += width - line.length + 1
155
+ show
156
+ end
157
+ @previous_time = Time.now
158
+ end
159
+
160
+ def show_if_needed
161
+ if @total.zero?
162
+ cur_percentage = 100
163
+ prev_percentage = 0
164
+ else
165
+ cur_percentage = (@current * 100 / @total).to_i
166
+ prev_percentage = (@previous * 100 / @total).to_i
167
+ end
168
+
169
+ # Use "!=" instead of ">" to support negative changes
170
+ if cur_percentage != prev_percentage ||
171
+ Time.now - @previous_time >= 1 || @finished_p
172
+ show
173
+ end
174
+ end
175
+
176
+ public
177
+ def clear
178
+ @out.print "\r"
179
+ @out.print(" " * (get_width - 1))
180
+ @out.print "\r"
181
+ end
182
+
183
+ def finish
184
+ @current = @total
185
+ @finished_p = true
186
+ show
187
+ end
188
+
189
+ def finished?
190
+ @finished_p
191
+ end
192
+
193
+ def file_transfer_mode
194
+ @format_arguments = [:title, :percentage, :bar, :stat_for_file_transfer]
195
+ end
196
+
197
+ def format= (format)
198
+ @format = format
199
+ end
200
+
201
+ def format_arguments= (arguments)
202
+ @format_arguments = arguments
203
+ end
204
+
205
+ def halt
206
+ @finished_p = true
207
+ show
208
+ end
209
+
210
+ def inc (step = 1)
211
+ @current += step
212
+ @current = @total if @current > @total
213
+ show_if_needed
214
+ @previous = @current
215
+ end
216
+
217
+ def set (count)
218
+ if count < 0 || count > @total
219
+ raise "invalid count: #{count} (total: #{@total})"
220
+ end
221
+ @current = count
222
+ show_if_needed
223
+ @previous = @current
224
+ end
225
+
226
+ def inspect
227
+ "#<ProgressBar:#{@current}/#{@total}>"
228
+ end
229
+ end
230
+
231
+ class ReversedProgressBar < ProgressBar
232
+ def do_percentage
233
+ 100 - super
234
+ end
235
+ end
236
+