smc-get 0.2.0.beta1 → 0.3.0.beta1
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/COPYING +674 -674
- data/HISTORY.rdoc +53 -31
- data/README.rdoc +162 -162
- data/VERSION.txt +1 -1
- data/bin/smc-checksum +44 -44
- data/bin/smc-checksum~ +2 -0
- data/bin/smc-get +31 -31
- data/bin/smc-repo-conv +205 -0
- data/bin/smc-repo-conv~ +155 -0
- data/config/smc-get.yml +32 -32
- data/config/smc-get.yml~ +32 -0
- data/lib/smc_get.rb +22 -22
- data/lib/smc_get/cui.rb +325 -325
- data/lib/smc_get/cui_commands/build.rb +297 -329
- data/lib/smc_get/cui_commands/command.rb +181 -117
- data/lib/smc_get/cui_commands/getinfo.rb +91 -91
- data/lib/smc_get/cui_commands/help.rb +64 -64
- data/lib/smc_get/cui_commands/install.rb +101 -101
- data/lib/smc_get/cui_commands/list.rb +101 -101
- data/lib/smc_get/cui_commands/search.rb +106 -106
- data/lib/smc_get/cui_commands/server.rb +76 -0
- data/lib/smc_get/cui_commands/uninstall.rb +77 -80
- data/lib/smc_get/cui_commands/update.rb +107 -119
- data/lib/smc_get/cui_commands/version.rb +57 -57
- data/lib/smc_get/errors.rb +166 -140
- data/lib/smc_get/gui.rb +19 -19
- data/lib/smc_get/local_repository.rb +290 -277
- data/lib/smc_get/package.rb +240 -260
- data/lib/smc_get/package_archive.rb +186 -80
- data/lib/smc_get/package_specification.rb +257 -253
- data/lib/smc_get/remote_repository.rb +272 -272
- data/lib/smc_get/repository.rb +9 -9
- data/lib/smc_get/smc_get.rb +118 -117
- data/smcpak.rdoc +331 -331
- data/test/test_smc-get-cui.rb +122 -122
- data/test/test_smc-get-lib.rb +171 -171
- metadata +25 -22
@@ -1,329 +1,297 @@
|
|
1
|
-
#
|
2
|
-
################################################################################
|
3
|
-
# This file is part of smc-get.
|
4
|
-
# Copyright (C) 2010-2011 Entertaining Software, Inc.
|
5
|
-
# Copyright (C) 2011 Marvin Gülker
|
6
|
-
#
|
7
|
-
# This program is free software: you can redistribute it and/or modify
|
8
|
-
# it under the terms of the GNU General Public License as published by
|
9
|
-
# the Free Software Foundation, either version 3 of the License, or
|
10
|
-
# (at your option) any later version.
|
11
|
-
#
|
12
|
-
# This program is distributed in the hope that it will be useful,
|
13
|
-
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
14
|
-
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
15
|
-
# GNU General Public License for more details.
|
16
|
-
#
|
17
|
-
# You should have received a copy of the GNU General Public License
|
18
|
-
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
19
|
-
################################################################################
|
20
|
-
|
21
|
-
module SmcGet
|
22
|
-
|
23
|
-
module CUICommands
|
24
|
-
|
25
|
-
class BuildCommand < Command
|
26
|
-
|
27
|
-
def self.help
|
28
|
-
<<-EOF
|
29
|
-
USAGE: #{File.basename($0)} build [DIRECTORY]
|
30
|
-
|
31
|
-
If DIRECTORY is given, validates it's structure against the SMC packaging
|
32
|
-
guidelines and then packages it into a .smcpak file. If DIRECTORY is not
|
33
|
-
given, enters an interactive process that queries you for the files you
|
34
|
-
want to include in your SMC package. In both cases you’ll end up with
|
35
|
-
a SMC package in your current directory.
|
36
|
-
|
37
|
-
Files you enter during the interrogative process are looked for in your
|
38
|
-
user-level SMC directory, i.e. ~/.smc.
|
39
|
-
EOF
|
40
|
-
end
|
41
|
-
|
42
|
-
def self.summary
|
43
|
-
"build\t\tBuild SMC packages."
|
44
|
-
end
|
45
|
-
|
46
|
-
def parse(args)
|
47
|
-
CUI.debug("Parsing #{args.count} args for build.")
|
48
|
-
raise(InvalidCommandline, "Too many arguments.") if args.count > 1
|
49
|
-
@directory = args.shift #nil if not given
|
50
|
-
end
|
51
|
-
|
52
|
-
def execute(config)
|
53
|
-
CUI.debug("Executing build.")
|
54
|
-
begin
|
55
|
-
if @directory
|
56
|
-
Package.create(@directory)
|
57
|
-
else #No directory given
|
58
|
-
puts(<<-MSG)
|
59
|
-
Welcome to the smc-get build process!
|
60
|
-
Answer the following questions properly and you'll end up with a ready-to-
|
61
|
-
install package you can either install locally or contribute to the repository
|
62
|
-
(which would make it installable via 'smc-get install' directly). When a question
|
63
|
-
asks you to input multiple files, you can end the query with an empty line.
|
64
|
-
If you like, you can specify multiple files at once by separating them
|
65
|
-
with a comma. Wildcards in filenames are allowed.
|
66
|
-
|
67
|
-
Files you don't specify via an absolute path (i.e. a path beginning with
|
68
|
-
either / on *nix or <letter>:\\ on Windows) are searched for in your
|
69
|
-
home directory's .smc directory and your SMC installation.
|
70
|
-
MSG
|
71
|
-
#All the information will be collected in this hash
|
72
|
-
spec =
|
73
|
-
|
74
|
-
#Start the questionaire
|
75
|
-
[:levels, :graphics, :music, :sounds, :worlds].each do |sym|
|
76
|
-
spec[sym]
|
77
|
-
end
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
path = path.gsub("\\", "/")
|
299
|
-
ary = []
|
300
|
-
#First check if it’s an absolute path
|
301
|
-
if RUBY_PLATFORM =~ /mswin|mingw|cygwin/ and path =~ /^[a-z]:/i
|
302
|
-
ary.replace(Dir.glob(path)) #Works even without an actual escape char like *
|
303
|
-
elsif path.start_with?("/")
|
304
|
-
ary.replace(Dir.glob(path))
|
305
|
-
else #OK, relative path
|
306
|
-
plural_name = "pixmaps" if plural_name == "graphics" #As always...
|
307
|
-
|
308
|
-
#The user level directory only contains levels, but for the
|
309
|
-
#sake of simplicity I treat it as if sounds etc existed there
|
310
|
-
#as well. It doesn’t hurt if not, because that just causes
|
311
|
-
#an empty array.
|
312
|
-
user_level_dir = CUI::USER_SMC_DIR + plural_name
|
313
|
-
smc_install_dir = @cui.local_repository.path + plural_name
|
314
|
-
global_files = Dir.glob(smc_install_dir.join(path).to_s)
|
315
|
-
user_files = Dir.glob(user_level_dir.join(path).to_s)
|
316
|
-
#In case a file with the same name exists in both paths,
|
317
|
-
#the user-level file overrides the SMC installation ones’s.
|
318
|
-
ary.replace(user_files)
|
319
|
-
global_files.each{|path| ary << path unless ary.any?{|p2| File.basename(path) == File.basename(p2)}}
|
320
|
-
end
|
321
|
-
ary
|
322
|
-
end
|
323
|
-
|
324
|
-
end
|
325
|
-
|
326
|
-
end
|
327
|
-
|
328
|
-
end
|
329
|
-
# vim:set ts=8 sts=2 sw=2 et: #
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
################################################################################
|
3
|
+
# This file is part of smc-get.
|
4
|
+
# Copyright (C) 2010-2011 Entertaining Software, Inc.
|
5
|
+
# Copyright (C) 2011 Marvin Gülker
|
6
|
+
#
|
7
|
+
# This program is free software: you can redistribute it and/or modify
|
8
|
+
# it under the terms of the GNU General Public License as published by
|
9
|
+
# the Free Software Foundation, either version 3 of the License, or
|
10
|
+
# (at your option) any later version.
|
11
|
+
#
|
12
|
+
# This program is distributed in the hope that it will be useful,
|
13
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
14
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
15
|
+
# GNU General Public License for more details.
|
16
|
+
#
|
17
|
+
# You should have received a copy of the GNU General Public License
|
18
|
+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
19
|
+
################################################################################
|
20
|
+
|
21
|
+
module SmcGet
|
22
|
+
|
23
|
+
module CUICommands
|
24
|
+
|
25
|
+
class BuildCommand < Command
|
26
|
+
|
27
|
+
def self.help
|
28
|
+
<<-EOF
|
29
|
+
USAGE: #{File.basename($0)} build [DIRECTORY]
|
30
|
+
|
31
|
+
If DIRECTORY is given, validates it's structure against the SMC packaging
|
32
|
+
guidelines and then packages it into a .smcpak file. If DIRECTORY is not
|
33
|
+
given, enters an interactive process that queries you for the files you
|
34
|
+
want to include in your SMC package. In both cases you’ll end up with
|
35
|
+
a SMC package in your current directory.
|
36
|
+
|
37
|
+
Files you enter during the interrogative process are looked for in your
|
38
|
+
user-level SMC directory, i.e. ~/.smc.
|
39
|
+
EOF
|
40
|
+
end
|
41
|
+
|
42
|
+
def self.summary
|
43
|
+
"build\t\tBuild SMC packages."
|
44
|
+
end
|
45
|
+
|
46
|
+
def parse(args)
|
47
|
+
CUI.debug("Parsing #{args.count} args for build.")
|
48
|
+
raise(InvalidCommandline, "Too many arguments.") if args.count > 1
|
49
|
+
@directory = args.shift #nil if not given
|
50
|
+
end
|
51
|
+
|
52
|
+
def execute(config)
|
53
|
+
CUI.debug("Executing build.")
|
54
|
+
begin
|
55
|
+
if @directory
|
56
|
+
Package.create(@directory)
|
57
|
+
else #No directory given
|
58
|
+
puts(<<-MSG)
|
59
|
+
Welcome to the smc-get build process!
|
60
|
+
Answer the following questions properly and you'll end up with a ready-to-
|
61
|
+
install package you can either install locally or contribute to the repository
|
62
|
+
(which would make it installable via 'smc-get install' directly). When a question
|
63
|
+
asks you to input multiple files, you can end the query with an empty line.
|
64
|
+
If you like, you can specify multiple files at once by separating them
|
65
|
+
with a comma. Wildcards in filenames are allowed.
|
66
|
+
|
67
|
+
Files you don't specify via an absolute path (i.e. a path beginning with
|
68
|
+
either / on *nix or <letter>:\\ on Windows) are searched for in your
|
69
|
+
home directory's .smc directory and your SMC installation.
|
70
|
+
MSG
|
71
|
+
#All the information will be collected in this hash
|
72
|
+
spec = {}
|
73
|
+
|
74
|
+
#Start the questionaire
|
75
|
+
[:levels, :graphics, :music, :sounds, :worlds].each do |sym|
|
76
|
+
spec[sym] = input_files(sym)
|
77
|
+
end
|
78
|
+
|
79
|
+
spec[:authors] = ask_list "Who participated in creating this package?"
|
80
|
+
spec[:dependencies] = ask_list "Enter this package's dependecy packages.", true
|
81
|
+
spec[:difficulty] = ask_string "Enter the difficulty: "
|
82
|
+
spec[:description] = ask_text "Enter the package's description."
|
83
|
+
spec[:install_message] = ask_text "Enter the installation message.", true
|
84
|
+
spec[:remove_message] = ask_text "Enter the remove message.", true
|
85
|
+
spec[:title] = ask_string "Enter the package's full title (it can contain whitespace):"
|
86
|
+
pkgname = ask_string "Enter the package's name (this mustn't contain whitespace):"
|
87
|
+
|
88
|
+
#Set the last_update spec field to now
|
89
|
+
spec[:last_update] = Time.now.utc #autoconvert to UTC
|
90
|
+
|
91
|
+
#This is all. Start building the package.
|
92
|
+
Dir.mktmpdir("smc-get-build-package") do |tmpdir|
|
93
|
+
puts "Creating package..."
|
94
|
+
tmpdir = Pathname.new(tmpdir)
|
95
|
+
pkgdir = tmpdir + pkgname
|
96
|
+
pkgdir.mkdir
|
97
|
+
#Copy all the level, music, etc. files
|
98
|
+
[:levels, :music, :sounds].each do |sym|
|
99
|
+
subdir = pkgdir + sym.to_s
|
100
|
+
subdir.mkdir
|
101
|
+
spec[sym].each{|file| FileUtils.cp(file, subdir)}
|
102
|
+
end
|
103
|
+
#Copy worlds
|
104
|
+
subdir = pkgdir + "worlds"
|
105
|
+
subdir.mkdir
|
106
|
+
spec[:worlds].each{|dir| FileUtils.cp_r(dir, subdir)}
|
107
|
+
#The graphics for whatever reason have an own name...
|
108
|
+
subdir = pkgdir + "pixmaps"
|
109
|
+
subdir.mkdir
|
110
|
+
spec[:graphics].each{|file| FileUtils.cp(file, subdir)}
|
111
|
+
|
112
|
+
#Turn the file paths in the spec to relative ones and the
|
113
|
+
#keys to strings. Compute the checksums.
|
114
|
+
puts "Creating spec and computing SHA1 checksums..."
|
115
|
+
real_spec = {"checksums" => {}}
|
116
|
+
spec.each_pair do |key, value|
|
117
|
+
real_spec[key.to_s] = case key
|
118
|
+
when :levels, :graphics, :music, :sounds
|
119
|
+
real_spec["checksums"][key.to_s] = {}
|
120
|
+
value.map do |abs_path|
|
121
|
+
basename = File.basename(abs_path)
|
122
|
+
real_spec["checksums"][key.to_s][basename] = Digest::SHA1.hexdigest(File.read(abs_path))
|
123
|
+
basename #for map
|
124
|
+
end
|
125
|
+
when :worlds
|
126
|
+
real_spec["checksums"]["worlds"] = {}
|
127
|
+
value.map do |abs_path|
|
128
|
+
basename = File.basename(abs_path)
|
129
|
+
real_spec["checksums"]["worlds"][basename] = {
|
130
|
+
"description.xml" => Digest::SHA1.hexdigest(File.read(File.join(abs_path, "description.xml"))),
|
131
|
+
"layer.xml" => Digest::SHA1.hexdigest(File.read(File.join(abs_path, "layer.xml"))),
|
132
|
+
"world.xml" => Digest::SHA1.hexdigest(File.read(File.join(abs_path, "world.xml")))
|
133
|
+
}
|
134
|
+
basename #for map
|
135
|
+
end
|
136
|
+
else
|
137
|
+
value
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
#Create the spec
|
142
|
+
File.open(pkgdir + "#{pkgname}.yml", "w"){|file| YAML.dump(real_spec, file)}
|
143
|
+
|
144
|
+
puts "Compressing..."
|
145
|
+
pkg = Package.create(pkgdir)
|
146
|
+
puts "Copying..."
|
147
|
+
FileUtils.cp(pkg.path, "./")
|
148
|
+
#compressed_file_name returns only the name of the package file,
|
149
|
+
#no path. Expanding it therefore results in the current
|
150
|
+
#working directory prepended to it.
|
151
|
+
puts "Done. Your package is at #{File.expand_path(pkg.spec.compressed_file_name)}."
|
152
|
+
end
|
153
|
+
|
154
|
+
end
|
155
|
+
rescue Errors::BrokenPackageError => e
|
156
|
+
$stderr.puts("Failed to build SMC package:")
|
157
|
+
$stderr.puts(e.message)
|
158
|
+
if CUI.debug_mode?
|
159
|
+
$stderr.puts("Class: #{e.class}")
|
160
|
+
$stderr.puts("Message: #{e.message}")
|
161
|
+
$stderr.puts("Backtrace:")
|
162
|
+
$stderr.puts(e.backtrace.join("\n\t"))
|
163
|
+
end
|
164
|
+
return 1 #Exit code
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
private
|
169
|
+
|
170
|
+
#Queries the user for a set of file names in an uniform mannor.
|
171
|
+
#Pass in the pluralized symbol of the resource you want to query
|
172
|
+
#for, e.g. :levels or :graphics. Return value is an array of all
|
173
|
+
#found files which may be empty if no files were found.
|
174
|
+
def input_files(plural_name)
|
175
|
+
result = []
|
176
|
+
puts
|
177
|
+
puts "Enter the names of the #{plural_name} you want to include:"
|
178
|
+
loop do
|
179
|
+
print "> "
|
180
|
+
str = $stdin.gets.chomp
|
181
|
+
|
182
|
+
#Test if the user entered an empty line, i.e. wants to end the
|
183
|
+
#query for this question
|
184
|
+
if str.empty?
|
185
|
+
if result.empty?
|
186
|
+
print("No #{plural_name} specified. Is this correct?(y/n) ")
|
187
|
+
break if $stdin.gets.chomp.downcase == "y"
|
188
|
+
else
|
189
|
+
break
|
190
|
+
end
|
191
|
+
else #User entered something
|
192
|
+
str.split(",").each do |file|
|
193
|
+
file.strip! #Due to possible whitespace behind the comma
|
194
|
+
ary = get_file_paths(plural_name.to_s, file)
|
195
|
+
$stderr.puts("Warning: File(s) not found: #{file}. Ignoring.") if ary.empty?
|
196
|
+
result.concat(ary)
|
197
|
+
end
|
198
|
+
end
|
199
|
+
end
|
200
|
+
result
|
201
|
+
end
|
202
|
+
|
203
|
+
def get_file_paths(plural_name, path)
|
204
|
+
#Even on Windows we work with forward slash (Windows supports this,
|
205
|
+
#although it’s not well known)
|
206
|
+
path = path.gsub("\\", "/")
|
207
|
+
ary = []
|
208
|
+
#First check if it’s an absolute path
|
209
|
+
if RUBY_PLATFORM =~ /mswin|mingw|cygwin/ and path =~ /^[a-z]:/i
|
210
|
+
ary.replace(Dir.glob(path)) #Works even without an actual escape char like *
|
211
|
+
elsif path.start_with?("/")
|
212
|
+
ary.replace(Dir.glob(path))
|
213
|
+
else #OK, relative path
|
214
|
+
plural_name = "pixmaps" if plural_name == "graphics" #As always...
|
215
|
+
|
216
|
+
#The user level directory only contains levels, but for the
|
217
|
+
#sake of simplicity I treat it as if sounds etc existed there
|
218
|
+
#as well. It doesn’t hurt if not, because that just causes
|
219
|
+
#an empty array.
|
220
|
+
user_level_dir = CUI::USER_SMC_DIR + plural_name
|
221
|
+
smc_install_dir = @cui.local_repository.path + plural_name
|
222
|
+
global_files = Dir.glob(smc_install_dir.join(path).to_s)
|
223
|
+
user_files = Dir.glob(user_level_dir.join(path).to_s)
|
224
|
+
#In case a file with the same name exists in both paths,
|
225
|
+
#the user-level file overrides the SMC installation ones’s.
|
226
|
+
ary.replace(user_files)
|
227
|
+
global_files.each{|path| ary << path unless ary.any?{|p2| File.basename(path) == File.basename(p2)}}
|
228
|
+
end
|
229
|
+
ary
|
230
|
+
end
|
231
|
+
|
232
|
+
#Asks for a newline and/or comma-separated list of things which are
|
233
|
+
#returned as an array.
|
234
|
+
def ask_list(message, blank_allowed = false)
|
235
|
+
puts(message)
|
236
|
+
list = []
|
237
|
+
loop do
|
238
|
+
print "> "
|
239
|
+
str = $stdin.gets.chomp
|
240
|
+
|
241
|
+
if str.empty?
|
242
|
+
if list.empty? and !blank_allowed
|
243
|
+
$stderr.puts("You have to input at least one entry.")
|
244
|
+
else
|
245
|
+
break
|
246
|
+
end
|
247
|
+
else #Something was entered
|
248
|
+
list.concat(str.split(",").map(&:strip))
|
249
|
+
end
|
250
|
+
end
|
251
|
+
puts #Blank line
|
252
|
+
list
|
253
|
+
end
|
254
|
+
|
255
|
+
#Ask for a short string. If +no_whitespace+ is true, the user is
|
256
|
+
#prompted again and again until he finally enters something without
|
257
|
+
#whitespace. The string is returned.
|
258
|
+
def ask_string(message, no_whitespace = false)
|
259
|
+
loop do
|
260
|
+
print(message)
|
261
|
+
str = $stdin.gets.chomp
|
262
|
+
if no_whitespace and str =~ /\s/
|
263
|
+
$stderr.puts("No whitespace allowed.")
|
264
|
+
else
|
265
|
+
puts #Blank line
|
266
|
+
return str
|
267
|
+
end
|
268
|
+
end
|
269
|
+
end
|
270
|
+
|
271
|
+
#Ask for a longer text that will be returned. If +blank_allowed+ is true,
|
272
|
+
#an empty text causes a return value of +nil+.
|
273
|
+
def ask_text(message, blank_allowed = false)
|
274
|
+
puts(message)
|
275
|
+
puts "End input with the word END on a single line."
|
276
|
+
text = ""
|
277
|
+
loop do
|
278
|
+
str = $stdin.gets
|
279
|
+
if str == "END\n"
|
280
|
+
if text.empty? and !blank_allowed
|
281
|
+
$stderr.puts("Nothing entered. Please input some text.")
|
282
|
+
else
|
283
|
+
puts #Blank line
|
284
|
+
return text.empty? ? nil : text.strip
|
285
|
+
end #if empty?
|
286
|
+
else
|
287
|
+
text << str
|
288
|
+
end #if END
|
289
|
+
end #loop
|
290
|
+
end #ask_text
|
291
|
+
|
292
|
+
end
|
293
|
+
|
294
|
+
end
|
295
|
+
|
296
|
+
end
|
297
|
+
# vim:set ts=8 sts=2 sw=2 et: #
|