facets 1.8.0 → 1.8.8
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/PROJECT +4 -4
- data/Rakefile +19 -14
- data/VERSION +1 -1
- data/lib/facet/enumerable/cart.rb +1 -0
- data/lib/facet/enumerable/cartesian_product.rb +1 -0
- data/lib/facet/enumerable/self/cart.rb +1 -0
- data/lib/facet/enumerable/self/cartesian_product.rb +1 -0
- data/lib/facets.rb +2 -1
- data/lib/facets/core/dir/self/multiglob_sum.rb +2 -0
- data/lib/facets/core/enumerable/cart.rb +119 -0
- data/lib/facets/core/enumerable/cartesian_product.rb +8 -0
- data/lib/facets/core/enumerable/self/cart.rb +120 -0
- data/lib/facets/core/enumerable/self/cartesian_product.rb +8 -0
- data/lib/facets/core/string/singular.rb +7 -7
- data/lib/facets/more/ann.rb +6 -5
- data/lib/facets/more/ann_attr.rb +11 -14
- data/lib/facets/more/autovivify.rb +2 -2
- data/lib/facets/more/dictionary.rb +63 -69
- data/lib/facets/more/opencascade.rb +3 -3
- data/lib/facets/more/openobject.rb +318 -9
- data/lib/facets/more/times.rb +129 -43
- data/lib/facets/more/uploadutils.rb +248 -43
- data/work/hash_open.rb +23 -0
- data/work/openobject-temp.rb +45 -0
- metadata +13 -9
- data/lib/facet/enumerable/cross.rb +0 -1
- data/lib/facet/enumerable/self/cross.rb +0 -1
- data/lib/facet/openhash.rb +0 -1
- data/lib/facets/core/enumerable/cross.rb +0 -47
- data/lib/facets/core/enumerable/self/cross.rb +0 -85
- data/lib/facets/more/openhash.rb +0 -350
data/lib/facets/more/times.rb
CHANGED
@@ -13,13 +13,22 @@
|
|
13
13
|
#
|
14
14
|
# == SPECIAL THANKS
|
15
15
|
#
|
16
|
-
# Thanks to Richard Kilmer for the orignal work and
|
17
|
-
#
|
16
|
+
# Thanks to Richard Kilmer for the orignal work and Alexander Kellett
|
17
|
+
# for suggesting it for Facets.
|
18
|
+
#
|
19
|
+
# Thanks to Dave Hoover and Ryan Platte for the Weekdays implementation.
|
18
20
|
#
|
19
21
|
# == Author(s)
|
20
22
|
#
|
21
23
|
# * Rich Kilmer
|
22
24
|
# * Thomas Sawyer
|
25
|
+
# * Dave Hoover
|
26
|
+
# * Ryan Platte
|
27
|
+
#
|
28
|
+
# CREDIT Rich Kilmer
|
29
|
+
# CREDIT Thomas Sawyer
|
30
|
+
# CREDIT Dave Hoover
|
31
|
+
# CREDIT Ryan Platte
|
23
32
|
#
|
24
33
|
# == Developer Notes
|
25
34
|
#
|
@@ -98,8 +107,55 @@ class Numeric
|
|
98
107
|
alias_method :from_now, :after # Reads best without arguments: 10.minutes.from_now
|
99
108
|
alias_method :later, :after # Reads best without arguments: 10.minutes.later
|
100
109
|
|
110
|
+
# Works with day in terms of weekdays.
|
111
|
+
def weekdays
|
112
|
+
Weekdays.new(self)
|
113
|
+
end
|
114
|
+
alias :weekday :weekdays
|
115
|
+
|
116
|
+
end
|
117
|
+
|
118
|
+
|
119
|
+
# The Weekdays class provides useful weekday terminology to Numeric.
|
120
|
+
|
121
|
+
class Weekdays
|
122
|
+
WEEKDAYS = 1..5 # Monday is wday 1
|
123
|
+
ONE_DAY = 60 * 60 * 24
|
124
|
+
|
125
|
+
def initialize(n)
|
126
|
+
@n = n
|
127
|
+
end
|
128
|
+
|
129
|
+
def ago(time = ::Time.now)
|
130
|
+
step :down, time
|
131
|
+
end
|
132
|
+
alias :until :ago
|
133
|
+
alias :before :ago
|
134
|
+
|
135
|
+
def since(time = ::Time.now)
|
136
|
+
step :up, time
|
137
|
+
end
|
138
|
+
alias :from_now :since
|
139
|
+
alias :after :since
|
140
|
+
|
141
|
+
private
|
142
|
+
|
143
|
+
def step(direction, original_time)
|
144
|
+
result = original_time
|
145
|
+
time = ONE_DAY
|
146
|
+
|
147
|
+
compare = direction == :up ? ">" : "<"
|
148
|
+
time *= -1 if direction == :down
|
149
|
+
|
150
|
+
@n.times do
|
151
|
+
result += time until result.send(compare, original_time) && WEEKDAYS.member?(result.wday)
|
152
|
+
original_time = result
|
153
|
+
end
|
154
|
+
result
|
155
|
+
end
|
101
156
|
end
|
102
157
|
|
158
|
+
|
103
159
|
class Time
|
104
160
|
|
105
161
|
NEVER = Time.mktime(2038)
|
@@ -267,61 +323,91 @@ end
|
|
267
323
|
|
268
324
|
=begin testing
|
269
325
|
|
270
|
-
require 'test/unit'
|
271
|
-
#require 'mega/multiplier'
|
326
|
+
require 'test/unit'
|
327
|
+
#require 'mega/multiplier'
|
272
328
|
|
273
|
-
class
|
329
|
+
class NumericTest < Test::Unit::TestCase
|
274
330
|
|
275
|
-
|
276
|
-
|
277
|
-
|
331
|
+
#def test_micro_seconds
|
332
|
+
# assert_equal( 0.000001, 1.microsecond )
|
333
|
+
#end
|
278
334
|
|
279
|
-
|
280
|
-
|
281
|
-
|
335
|
+
#def test_milli_seconds
|
336
|
+
# assert_equal( 0.001, 1.millisecond )
|
337
|
+
#end
|
282
338
|
|
283
|
-
|
284
|
-
|
285
|
-
|
339
|
+
def test_seconds
|
340
|
+
assert_equal( 60**0, 1.seconds )
|
341
|
+
end
|
286
342
|
|
287
|
-
|
288
|
-
|
289
|
-
|
343
|
+
def test_minutes
|
344
|
+
assert_equal( 60**1, 1.minutes )
|
345
|
+
end
|
290
346
|
|
291
|
-
|
292
|
-
|
293
|
-
|
347
|
+
def test_hours
|
348
|
+
assert_equal( 60**2, 1.hours )
|
349
|
+
end
|
294
350
|
|
295
|
-
|
296
|
-
|
297
|
-
|
351
|
+
def test_days
|
352
|
+
assert_equal( 24*(60**2), 1.days )
|
353
|
+
end
|
298
354
|
|
299
|
-
|
300
|
-
|
301
|
-
|
355
|
+
def test_weeks
|
356
|
+
assert_equal( 7*24*(60**2), 1.weeks )
|
357
|
+
end
|
302
358
|
|
303
|
-
|
304
|
-
|
305
|
-
|
359
|
+
def test_fortnights
|
360
|
+
assert_equal( 14*24*(60**2), 1.fortnights )
|
361
|
+
end
|
306
362
|
|
307
|
-
|
308
|
-
|
309
|
-
|
363
|
+
def test_months
|
364
|
+
assert_equal( 30*24*(60**2), 1.months )
|
365
|
+
end
|
310
366
|
|
311
|
-
|
312
|
-
|
313
|
-
|
367
|
+
def test_years
|
368
|
+
assert_equal( 365*24*(60**2), 1.years )
|
369
|
+
end
|
314
370
|
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
371
|
+
def test_before
|
372
|
+
t = Time.now
|
373
|
+
assert_equal( t - 1.day, 1.day.before(t) )
|
374
|
+
end
|
375
|
+
|
376
|
+
def test_after
|
377
|
+
t = Time.now
|
378
|
+
assert_equal( t + 1.day, 1.day.after(t) )
|
379
|
+
end
|
319
380
|
|
320
|
-
def test_after
|
321
|
-
t = Time.now
|
322
|
-
assert_equal( t + 1.day, 1.day.after(t) )
|
323
381
|
end
|
324
382
|
|
325
|
-
|
383
|
+
class WeekdaysTest < Test::Unit::TestCase
|
384
|
+
|
385
|
+
MONDAY = Time.at(1165250000)
|
386
|
+
THURSDAY = Time.at(1165500000)
|
387
|
+
FRIDAY = Time.at(1165606025)
|
388
|
+
|
389
|
+
def test_weekday_after_monday
|
390
|
+
assert_equal 2, 1.weekday.since(MONDAY).wday
|
391
|
+
end
|
392
|
+
|
393
|
+
def test_weekday_after_friday
|
394
|
+
assert_equal 1, 1.weekday.after(FRIDAY).wday
|
395
|
+
end
|
396
|
+
|
397
|
+
def test_weekdays_before_friday
|
398
|
+
assert_equal 2, 3.weekdays.before(FRIDAY).wday
|
399
|
+
end
|
400
|
+
|
401
|
+
#def test_weekday_before_today
|
402
|
+
# Time.expects(:now).returns(THURSDAY)
|
403
|
+
# assert_equal 3, 1.weekday.ago.wday
|
404
|
+
#end
|
405
|
+
|
406
|
+
#def test_weekdays_after_today
|
407
|
+
# Time.expects(:now).returns(MONDAY)
|
408
|
+
# assert_equal 3, 2.weekday.from_now.wday
|
409
|
+
#end
|
410
|
+
|
411
|
+
end
|
326
412
|
|
327
413
|
=end
|
@@ -1,6 +1,9 @@
|
|
1
1
|
# = uploadutils.rb
|
2
2
|
#
|
3
|
-
# TODO Incorporate password into scp and ftp
|
3
|
+
# TODO Incorporate password into scp and ftp ?
|
4
|
+
#
|
5
|
+
# TODO rsync needs --delete option
|
6
|
+
#++
|
4
7
|
|
5
8
|
require 'openssl'
|
6
9
|
require 'shellwords'
|
@@ -44,6 +47,248 @@ require 'tmpdir'
|
|
44
47
|
module UploadUtils
|
45
48
|
|
46
49
|
module_function
|
50
|
+
|
51
|
+
#
|
52
|
+
# Upload via given protocol.
|
53
|
+
#
|
54
|
+
|
55
|
+
def upload( protocol, opts )
|
56
|
+
send(protocol.to_s.downcase,opts)
|
57
|
+
end
|
58
|
+
|
59
|
+
#
|
60
|
+
# Use ftp to upload files.
|
61
|
+
#
|
62
|
+
|
63
|
+
def ftp( keys )
|
64
|
+
keys = keys.to_openhash
|
65
|
+
|
66
|
+
# set transfer rules
|
67
|
+
if keys.stage
|
68
|
+
trans = stage_transfer(keys.stage)
|
69
|
+
else
|
70
|
+
files(keys.dir, keys.copy).each do |from|
|
71
|
+
trans << [from,from]
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
# append location of publication dir to from
|
76
|
+
dir = keys.dir
|
77
|
+
trans.collect!{ |from,to| [File.join(dir,from), to] }
|
78
|
+
|
79
|
+
if keys.dryrun
|
80
|
+
puts "ftp open #{keys.user}@#{keys.host}:#{keys.root}/"
|
81
|
+
keys.trans.each do |f, t|
|
82
|
+
puts "ftp put #{f} #{t}"
|
83
|
+
end
|
84
|
+
else
|
85
|
+
require 'net/ftp'
|
86
|
+
Net::FTP.open(keys.host) do |ftp|
|
87
|
+
ftp.login(keys.user) #password?
|
88
|
+
ftp.chdir(keys.root)
|
89
|
+
keys.trans.each do |f, t|
|
90
|
+
puts "ftp #{f} #{t}" unless keys.quiet
|
91
|
+
ftp.putbinaryfile( f, t, 1024 )
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
#
|
98
|
+
# Use sftp to upload files.
|
99
|
+
#
|
100
|
+
|
101
|
+
def sftp( keys )
|
102
|
+
keys = keys.to_openobject
|
103
|
+
|
104
|
+
# set transfer rules
|
105
|
+
if keys.stage
|
106
|
+
trans = stage_transfer(keys.stage)
|
107
|
+
else
|
108
|
+
files(keys.dir, keys.copy).each do |from|
|
109
|
+
trans << [from,from]
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
# append location of publication dir to from
|
114
|
+
dir = keys.dir
|
115
|
+
trans.collect!{ |from,to| [File.join(dir,from), to] }
|
116
|
+
|
117
|
+
if keys.dryrun
|
118
|
+
puts "sftp open #{keys.user}@#{keys.host}:#{keys.root}/"
|
119
|
+
keys.trans.each do |f,t|
|
120
|
+
puts "sftp put #{f} #{t}"
|
121
|
+
end
|
122
|
+
else
|
123
|
+
require 'net/sftp'
|
124
|
+
Net::SFTP.start(keys.host, keys.user, keys.pass) do |sftp|
|
125
|
+
#sftp.login( user )
|
126
|
+
sftp.chdir(keys.root)
|
127
|
+
keys.trans.each do |f,t|
|
128
|
+
puts "sftp #{f} #{t}" unless keys.quiet
|
129
|
+
sftp.put_file(f,t) #, 1024 )
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
#
|
136
|
+
# Use rsync to upload files.
|
137
|
+
#
|
138
|
+
|
139
|
+
def rsync( keys )
|
140
|
+
keys = keys.to_openobject
|
141
|
+
|
142
|
+
flags = []
|
143
|
+
flags << "-n" if keys.dryrun
|
144
|
+
flags << "-q" if keys.quiet
|
145
|
+
flags << "-v" if keys.verbose
|
146
|
+
flags << "--progress" unless keys.quiet
|
147
|
+
flags = flags.join(' ').strip
|
148
|
+
flags = ' ' + flags unless flags.empty?
|
149
|
+
|
150
|
+
manfile = '.publish.mainfest'
|
151
|
+
|
152
|
+
if keys.stage
|
153
|
+
dir = stage_linkdir(keys.dir, keys.stage)
|
154
|
+
Dir.chdir(dir) do
|
155
|
+
cpy = files(keys.copy)
|
156
|
+
end
|
157
|
+
manifest = File.join(dir,manfile)
|
158
|
+
cmd = %{rsync#{flags} -L -arz --files-from='#{manifest}' #{dir} #{keys.user}@#{keys.host}:/#{keys.root}}
|
159
|
+
else
|
160
|
+
dir = keys.dir
|
161
|
+
cpy = files(dir, keys.copy)
|
162
|
+
manifest = File.join(dir,manfile)
|
163
|
+
cmd = %{rsync#{flags} -arz --files-from='#{manifest}' #{dir} #{keys.user}@#{keys.host}:/#{keys.root}}
|
164
|
+
end
|
165
|
+
|
166
|
+
#Dir.chdir(keys.dir) do
|
167
|
+
begin
|
168
|
+
File.open(manifest, 'w'){ |f| f << cpy.join("\n") }
|
169
|
+
ENV['RSYNC_PASSWORD'] = keys.pass if keys.pass
|
170
|
+
puts cmd unless keys.quiet
|
171
|
+
system cmd
|
172
|
+
ensure
|
173
|
+
ENV.delete('RSYNC_PASSWORD') if keys.pass
|
174
|
+
end
|
175
|
+
#end
|
176
|
+
|
177
|
+
end
|
178
|
+
|
179
|
+
# private (can't do b/c of module_function)
|
180
|
+
|
181
|
+
# parse publishing options.
|
182
|
+
|
183
|
+
def upload_parameters( keys )
|
184
|
+
keys = OpenObject.new(keys)
|
185
|
+
|
186
|
+
keys.copy = keys.copy || '**/*'
|
187
|
+
keys.host = keys.host || keys.domain
|
188
|
+
keys.user = keys.user || keys.username
|
189
|
+
keys.root = keys.root || '/'
|
190
|
+
#keys.pass = keys.pass || keys.password
|
191
|
+
|
192
|
+
# validate
|
193
|
+
raise ArgumentError, "missing publish parameter -- host" unless keys.host
|
194
|
+
raise ArgumentError, "missing publish parameter -- user" unless keys.user
|
195
|
+
raise ArgumentError, "missing publish parameter -- copy" unless keys.copy
|
196
|
+
#raise ArgumentError, "missing publish parameter -- root" unless keys.root
|
197
|
+
|
198
|
+
#keys.root = '' if keys.root.nil?
|
199
|
+
#keys.root = keys.root[1..-1] if keys.root[0,1] == '/'
|
200
|
+
keys.root = '' if opts.root.nil?
|
201
|
+
keys.root.sub!(/^\//,'')
|
202
|
+
|
203
|
+
if String===keys.copy and File.directory?(keys.copy)
|
204
|
+
copy = File.join(keys.copy, '*')
|
205
|
+
end
|
206
|
+
keys.copy = [keys.copy].flatten.compact
|
207
|
+
|
208
|
+
# trans = []
|
209
|
+
# keys.copy.each do |from|
|
210
|
+
# #from, to = *Shellwords.shellwords(c)
|
211
|
+
# #to = from if to.nil?
|
212
|
+
# #to = to[1..-1] if to[0,1] == '/'
|
213
|
+
# from.sub('*','**/*') unless from =~ /\*\*/
|
214
|
+
# files = Dir.glob(from)
|
215
|
+
# files.each do |f|
|
216
|
+
# #t = File.join(to,File.basename(f))
|
217
|
+
# #t = t[1..-1] if t[0,1] == '/'
|
218
|
+
# trans << [f,f]
|
219
|
+
# end
|
220
|
+
# end
|
221
|
+
# keys.trans = trans
|
222
|
+
|
223
|
+
return keys
|
224
|
+
end
|
225
|
+
|
226
|
+
# Put together the list of files to copy.
|
227
|
+
|
228
|
+
def files( dir, copy )
|
229
|
+
Dir.chdir(dir) do
|
230
|
+
del, add = copy.partition{ |f| /^[-]/ =~ f }
|
231
|
+
|
232
|
+
# remove - and + prefixes
|
233
|
+
del.collect!{ |f| f.sub(/^[-]/,'') }
|
234
|
+
add.collect!{ |f| f.sub(/^[+]/,'') }
|
235
|
+
|
236
|
+
del.concat(must_exclude)
|
237
|
+
|
238
|
+
files = []
|
239
|
+
add.each{ |g| files += Dir.multiglob_recurse(g) }
|
240
|
+
del.each{ |g| files -= Dir.multiglob_recurse(g) }
|
241
|
+
|
242
|
+
files.collect!{ |f| f.sub(/^\//,'') }
|
243
|
+
|
244
|
+
return files
|
245
|
+
end
|
246
|
+
end
|
247
|
+
|
248
|
+
# Combine three part stage list into a two part from->to list.
|
249
|
+
#
|
250
|
+
# Using the stage list of three space separated fields.
|
251
|
+
#
|
252
|
+
# fromdir file todir
|
253
|
+
#
|
254
|
+
# This is used to generate a from -> to list of the form:
|
255
|
+
#
|
256
|
+
# fromdir/file todir/file
|
257
|
+
#
|
258
|
+
|
259
|
+
def stage_transfer( list )
|
260
|
+
trans = []
|
261
|
+
list.each do |line|
|
262
|
+
trans << Shellwords.shellwords(line)
|
263
|
+
end
|
264
|
+
|
265
|
+
trans.collect! do |from, base, to|
|
266
|
+
file = File.join(from,base)
|
267
|
+
to = File.join(to,base)
|
268
|
+
[from, to]
|
269
|
+
end
|
270
|
+
end
|
271
|
+
|
272
|
+
# When using stage options this will create temporary linked location.
|
273
|
+
|
274
|
+
def stage_linkdir( dir, list )
|
275
|
+
folder = File.join(Dir.tmpdir, 'ratchets', 'project', object_id.abs.to_s)
|
276
|
+
FileUtils.mkdir_p(folder)
|
277
|
+
|
278
|
+
Dir.chdir(dir) do
|
279
|
+
stage_transfer(list).each do |file, to|
|
280
|
+
link = File.join(folder,to)
|
281
|
+
FileUtils.ln_s(link,file)
|
282
|
+
end
|
283
|
+
end
|
284
|
+
|
285
|
+
return folder
|
286
|
+
end
|
287
|
+
|
288
|
+
|
289
|
+
=begin
|
290
|
+
|
291
|
+
|
47
292
|
#--
|
48
293
|
# SHELLS OUT! Need net/scp library to fix.
|
49
294
|
#++
|
@@ -134,49 +379,7 @@ module UploadUtils
|
|
134
379
|
end
|
135
380
|
end
|
136
381
|
|
137
|
-
# private (can't do b/c of module_function)
|
138
|
-
|
139
|
-
# parse publishing options.
|
140
|
-
|
141
|
-
def upload_parameters( keys )
|
142
|
-
keys = OpenHash.new(keys)
|
143
|
-
|
144
|
-
keys.copy = keys.copy || '**/*'
|
145
|
-
keys.host = keys.host || keys.domain
|
146
|
-
keys.user = keys.user || keys.username
|
147
|
-
keys.pass = keys.pass || keys.password
|
148
|
-
|
149
|
-
# validate
|
150
|
-
raise ArgumentError, "missing publish parameter -- host" unless keys.host
|
151
|
-
raise ArgumentError, "missing publish parameter -- user" unless keys.user
|
152
|
-
raise ArgumentError, "missing publish parameter -- copy" unless keys.copy
|
153
|
-
raise ArgumentError, "missing publish parameter -- root" unless keys.root
|
154
|
-
|
155
|
-
keys.root = '' if keys.root.nil?
|
156
|
-
keys.root = keys.root[1..-1] if keys.root[0,1] == '/'
|
157
|
-
|
158
|
-
if String===keys.copy and File.directory?(keys.copy)
|
159
|
-
copy = File.join(keys.copy, '*')
|
160
|
-
end
|
161
|
-
keys.copy = [keys.copy].flatten.compact
|
162
|
-
|
163
|
-
trans = []
|
164
|
-
keys.copy.each do |from|
|
165
|
-
#from, to = *Shellwords.shellwords(c)
|
166
|
-
#to = from if to.nil?
|
167
|
-
#to = to[1..-1] if to[0,1] == '/'
|
168
|
-
from.sub('*','**/*') unless from =~ /\*\*/
|
169
|
-
files = Dir.glob(from)
|
170
|
-
files.each do |f|
|
171
|
-
#t = File.join(to,File.basename(f))
|
172
|
-
#t = t[1..-1] if t[0,1] == '/'
|
173
|
-
trans << [f,f]
|
174
|
-
end
|
175
|
-
end
|
176
|
-
keys.trans = trans
|
177
382
|
|
178
|
-
return keys
|
179
|
-
end
|
180
383
|
|
181
384
|
# Creates a stage from which the whole directory can be uploaded.
|
182
385
|
# This is needed for scp and rsync which have to shelled out,
|
@@ -204,4 +407,6 @@ module UploadUtils
|
|
204
407
|
FileUtils.rm_r(tmpdir) # now remove the temp dir
|
205
408
|
end
|
206
409
|
|
410
|
+
=end
|
411
|
+
|
207
412
|
end
|