rad 0.2.9 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
+