fun_with_files 0.0.13 → 0.0.14
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -13
- data/CHANGELOG.markdown +50 -0
- data/README.rdoc +10 -2
- data/VERSION +1 -1
- data/lib/fun_with/files/core_extensions/file.rb +5 -0
- data/lib/fun_with/files/directory_builder.rb +9 -3
- data/lib/fun_with/files/file_manipulation_methods.rb +45 -21
- data/lib/fun_with/files/file_path.rb +138 -100
- data/test/test_directory_builder.rb +7 -3
- data/test/test_file_manipulation.rb +39 -2
- data/test/test_file_path.rb +32 -1
- data/test/test_fun_with_files.rb +1 -1
- data/test/test_symlinking.rb +3 -0
- metadata +75 -67
checksums.yaml
CHANGED
@@ -1,15 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
|
5
|
-
data.tar.gz: !binary |-
|
6
|
-
OTE2Y2IxNTI0Y2U0Y2VhNjFlODlmOWE0NmM2ZTAxZjNlMzlkYzZjYg==
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: cf6595c5de6273e8d7fb668ddc70d161a1354c4c
|
4
|
+
data.tar.gz: 4938516e5ad413f8ffa722985d963fcb6eb1f039
|
7
5
|
SHA512:
|
8
|
-
metadata.gz:
|
9
|
-
|
10
|
-
Yjk4ZTBiYThhMTc0ZDVlZTQ2MDQzZjQ1ZmQ0NmE3MDQxZmQzNDJiMzJhZjAx
|
11
|
-
YjRmNGRkNGRhZTUyMWI2ZWU4NTkzMjk3ZTQzOTdlZDhlMjYxZDg=
|
12
|
-
data.tar.gz: !binary |-
|
13
|
-
M2Q0Zjc1NjAxZDdlZGQ1Y2YzNzc1ZTAzYjAwZjRlYTdmM2MxMDM1ZDVjMDAy
|
14
|
-
MGExZDRhMTFjYTQ4NTI1NzdiNGIzNDRkZTY4ZGRhMjYyNDM2ZjQ0YmI1Zjdl
|
15
|
-
NTZlNTc3MmM1NTYwZTNhNjgxODEyNTUxYzhhMDljNzUzYTUzMTY=
|
6
|
+
metadata.gz: 09db56d93b3cde0407d1f0e7d8691ab0373158301828ee5af974c1cb259369c2f8a5c43c79eb37352760bede2d5d4d4f310887b9129aba917100109643138787
|
7
|
+
data.tar.gz: 06690ccc56d90230e7d8c55a9f9372cc74dc9f6ff1104fe7f8ea26c1efdb601b5ff221a0c4250630d40ab7e2a065cc71ff124545de1ed1a66405fc591ffbc49a
|
data/CHANGELOG.markdown
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
CHANGELOG
|
2
|
+
=========
|
3
|
+
|
4
|
+
v0.0.14
|
5
|
+
=======
|
6
|
+
|
7
|
+
Make symlinking actually work in a sensible way.
|
8
|
+
|
9
|
+
v0.0.12
|
10
|
+
=======
|
11
|
+
|
12
|
+
FilePath.touch() takes same options as FileUtils.touch()
|
13
|
+
FilePath.glob() now takes a block (yields files one at a time)
|
14
|
+
|
15
|
+
|
16
|
+
|
17
|
+
v0.0.9
|
18
|
+
------
|
19
|
+
|
20
|
+
Changed the initialization procedure, which wasn't working on some systems.
|
21
|
+
|
22
|
+
v0.0.8
|
23
|
+
------
|
24
|
+
|
25
|
+
A few new, useful functions. .ext() overloaded to take an argument, spit out the path with .arg added to the end. timestamp()
|
26
|
+
|
27
|
+
v0.0.7
|
28
|
+
------
|
29
|
+
|
30
|
+
Added dependency on `fun_with_version_strings`. Then removed it, cuz fwvs needs fwf more. Bleh.
|
31
|
+
Added filepath.md5() => hexdigest of file contents.
|
32
|
+
Added shaXXXX functions, so the poor li'l crypto won't feel left out.
|
33
|
+
|
34
|
+
|
35
|
+
0.0.4 - 0.0.6
|
36
|
+
-------------
|
37
|
+
|
38
|
+
I've not been so good about updating this doc.
|
39
|
+
|
40
|
+
|
41
|
+
0.0.3
|
42
|
+
-----
|
43
|
+
|
44
|
+
Added .succession() to get all existing files within a succession group. The differentiating piece of the filename can be either a timestamp or a numeric ID.
|
45
|
+
|
46
|
+
|
47
|
+
TODO
|
48
|
+
----
|
49
|
+
|
50
|
+
* It really makes more sense for path.basename to return a string instead of a filepath. Or is it? Why does Pathname.basename return a path? Imma cargo cult this and leave it as-is.
|
data/README.rdoc
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
= fun_with_files
|
1
|
+
= fun_with_files =
|
2
2
|
|
3
3
|
FunWith::Files adds a bit of whimsy to your file manipulations, if that's what you're looking for.
|
4
4
|
|
@@ -34,7 +34,15 @@ To the code!
|
|
34
34
|
|
35
35
|
# whole buchcha other goodies, yet to be documented.
|
36
36
|
|
37
|
-
|
37
|
+
|
38
|
+
|
39
|
+
=== Linking files ===
|
40
|
+
|
41
|
+
While fwf.symlink and fwf.link are both backed by FileUtils.ln / FileUtils.ln_s, the defaults are somewhat different
|
42
|
+
|
43
|
+
|
44
|
+
|
45
|
+
== DirectoryBuilder ==
|
38
46
|
|
39
47
|
DirectoryBuilder is a class for defining and populating a file hierarchy with relative ease. DirectoryBuilder is probably most easily demonstrated by example. Sample code:
|
40
48
|
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.0.
|
1
|
+
0.0.14
|
@@ -4,7 +4,7 @@ module FunWith
|
|
4
4
|
# Describes a domain-specific language for creating and populating a
|
5
5
|
# directory of files.
|
6
6
|
class DirectoryBuilder
|
7
|
-
attr_accessor :current_path
|
7
|
+
attr_accessor :current_path
|
8
8
|
|
9
9
|
def initialize( path )
|
10
10
|
@paths = []
|
@@ -68,10 +68,16 @@ module FunWith
|
|
68
68
|
end
|
69
69
|
end
|
70
70
|
|
71
|
-
|
72
|
-
|
71
|
+
attr_reader :current_file
|
72
|
+
|
73
|
+
def current_file=( file )
|
74
|
+
@current_file = file.fwf_filepath
|
73
75
|
end
|
74
76
|
|
77
|
+
# def current_file
|
78
|
+
# @current_file ? FunWith::Files::FilePath.new( @current_file.path ) : nil
|
79
|
+
# end
|
80
|
+
|
75
81
|
# if file not given, the result is appended to the current file.
|
76
82
|
def download( url, file = nil )
|
77
83
|
if file
|
@@ -21,45 +21,68 @@ module FunWith
|
|
21
21
|
#
|
22
22
|
#
|
23
23
|
def cp( *args )
|
24
|
-
|
25
|
-
|
26
|
-
|
24
|
+
destination_and_options( args ) do |dest, opts|
|
25
|
+
FileUtils.cp_r( self, dest, narrow_options( opts, FileUtils::OPT_TABLE["cp_r"] ) )
|
26
|
+
dest.fwf_filepath
|
27
|
+
end
|
27
28
|
end
|
28
29
|
|
29
30
|
alias :copy :cp
|
30
31
|
|
32
|
+
# Treat as a copy then a delete? Nah, that's a lot slower in some cases. Should be much more in tune with what the command line program does
|
31
33
|
def mv( *args )
|
32
34
|
|
33
35
|
end
|
34
36
|
|
37
|
+
alias :move :mv
|
38
|
+
|
35
39
|
|
36
|
-
#
|
40
|
+
# Logic of link()
|
41
|
+
#
|
42
|
+
# self is the target, link is the filepath entry linking to the file represented by self
|
37
43
|
# returns filepath of the new link. Will fall back to symbolic
|
38
|
-
# link if self is a directory
|
39
|
-
def
|
40
|
-
self.destination_and_options( args ) do |
|
41
|
-
|
44
|
+
# link if self is a directory. Necessary directories will be created.
|
45
|
+
def link *args
|
46
|
+
self.destination_and_options( args ) do |lnk, opts|
|
47
|
+
symlink_requested = self.directory? || opts[:symbolic] || opts[:sym] || opts[:soft]
|
42
48
|
|
43
|
-
if
|
44
|
-
|
49
|
+
if symlink_requested
|
50
|
+
self.symlink lnk, opts
|
45
51
|
else
|
46
|
-
|
52
|
+
opts = narrow_options opts, FileUtils::OPT_TABLE["ln"]
|
53
|
+
|
54
|
+
FileUtils.ln self, lnk, opts
|
47
55
|
end
|
48
56
|
|
49
|
-
|
57
|
+
lnk.fwf_filepath
|
50
58
|
end
|
51
59
|
end
|
52
60
|
|
53
|
-
alias :
|
61
|
+
alias :ln :link
|
54
62
|
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
63
|
+
# * Where does the symlink live in the filesys.
|
64
|
+
# * What does it point to?
|
65
|
+
# * How does it point to the thing?
|
66
|
+
# * absolutely
|
67
|
+
# * relatively
|
68
|
+
# * custom string (programmer error hilarity ensues?)
|
69
|
+
# It can't
|
70
|
+
# What to return? The path of the symlink, or the path of the target?
|
71
|
+
#
|
72
|
+
def symlink( *args )
|
73
|
+
lnk, opts = self.destination_and_options( args )
|
74
|
+
|
75
|
+
if opts[:absolute]
|
76
|
+
lnk = lnk.fwf_filepath.expand
|
77
|
+
else
|
78
|
+
lnk = lnk.fwf_filepath
|
79
|
+
end
|
80
|
+
|
81
|
+
FileUtils.ln_s( self, lnk, narrow_options( opts, FileUtils::OPT_TABLE["ln_s"] ) )
|
82
|
+
lnk.fwf_filepath
|
60
83
|
end
|
61
84
|
|
62
|
-
alias :
|
85
|
+
alias :ln_s :symlink
|
63
86
|
|
64
87
|
|
65
88
|
def file_gsub( *args, &block )
|
@@ -118,10 +141,11 @@ module FunWith
|
|
118
141
|
end
|
119
142
|
end
|
120
143
|
|
144
|
+
|
121
145
|
protected
|
122
146
|
def destination_and_options( args, &block )
|
123
147
|
options = args.last.is_a?(Hash) ? args.pop : {}
|
124
|
-
destination = self.
|
148
|
+
destination = self._find_destination_from_args( args )
|
125
149
|
|
126
150
|
if block_given?
|
127
151
|
yield [destination, options]
|
@@ -140,7 +164,7 @@ module FunWith
|
|
140
164
|
# If dest doesn't exist, and src (self) is a file, dest is taken to be the complete path.
|
141
165
|
# If dest doesn't exist, and src (self) is a directory, then dest is taken to be
|
142
166
|
# If dest is a directory and the source is a file, then the file will be copied into dest with the src's basename
|
143
|
-
def
|
167
|
+
def _find_destination_from_args( args )
|
144
168
|
raise ArgumentError.new("File #{self} must exist.") unless self.exist?
|
145
169
|
|
146
170
|
if args.first.is_a?(Pathname)
|
@@ -1,6 +1,7 @@
|
|
1
1
|
module FunWith
|
2
2
|
module Files
|
3
3
|
class FilePath < Pathname
|
4
|
+
|
4
5
|
SUCC_DIGIT_COUNT = 6
|
5
6
|
DEFAULT_TIMESTAMP_FORMAT = "%Y%m%d%H%M%S%L"
|
6
7
|
|
@@ -44,50 +45,57 @@ module FunWith
|
|
44
45
|
self.join(*args)
|
45
46
|
end
|
46
47
|
|
47
|
-
alias :exists? :exist?
|
48
48
|
|
49
49
|
def doesnt_exist?
|
50
50
|
self.exist? == false
|
51
51
|
end
|
52
52
|
|
53
|
+
def not_a_file?
|
54
|
+
! self.file?
|
55
|
+
end
|
56
|
+
|
57
|
+
alias :absent? :doesnt_exist?
|
58
|
+
alias :exists? :exist?
|
59
|
+
alias :folder? :directory?
|
60
|
+
|
53
61
|
# If called on a file instead of a directory,
|
54
62
|
# has the same effect as path.dirname
|
55
63
|
def up
|
56
64
|
self.class.new( self.join("..") ).expand
|
57
65
|
end
|
58
|
-
|
66
|
+
|
59
67
|
alias :down :join
|
60
|
-
|
68
|
+
|
61
69
|
# opts:
|
62
|
-
# :flags => File::FNM_CASEFOLD
|
63
|
-
# File::FNM_DOTMATCH
|
64
|
-
# File::FNM_NOESCAPE
|
65
|
-
# File::FNM_PATHNAME
|
66
|
-
# File::FNM_SYSCASE
|
67
|
-
# See Dir documentation for details.
|
68
|
-
# Can be given as an integer: (File::FNM_DOTMATCH | File::FNM_NOESCAPE)
|
70
|
+
# :flags => File::FNM_CASEFOLD
|
71
|
+
# File::FNM_DOTMATCH
|
72
|
+
# File::FNM_NOESCAPE
|
73
|
+
# File::FNM_PATHNAME
|
74
|
+
# File::FNM_SYSCASE
|
75
|
+
# See Dir documentation for details.
|
76
|
+
# Can be given as an integer: (File::FNM_DOTMATCH | File::FNM_NOESCAPE)
|
69
77
|
# or as an array: [File::FNM_CASEFOLD, File::FNM_DOTMATCH]
|
70
|
-
#
|
78
|
+
#
|
71
79
|
# :class => [self.class] The class of objects you want returned (String, FilePath, etc.)
|
72
80
|
# Should probably be a subclass of FilePath or String. Class.initialize() must accept a string
|
73
81
|
# [representing a file path] as the sole argument.
|
74
82
|
#
|
75
83
|
# :recurse => [defaults true]
|
76
84
|
# :recursive (synonym for :recurse)
|
77
|
-
#
|
85
|
+
#
|
78
86
|
# :ext => [] A single symbol, or a list containing strings/symbols representing file name extensions.
|
79
87
|
# No leading periods kthxbai.
|
80
88
|
# :sensitive => true : do a case sensitive search. I guess the default is an insensitive search, so
|
81
89
|
# the default behaves similarly on Windows and Unix. Not gonna fight it.
|
82
90
|
#
|
83
|
-
# :dots => true : include dotfiles. Does not include . and ..s unless you also
|
84
|
-
# specify the option :parent_and_current => true.
|
85
|
-
#
|
91
|
+
# :dots => true : include dotfiles. Does not include . and ..s unless you also
|
92
|
+
# specify the option :parent_and_current => true.
|
93
|
+
#
|
86
94
|
# If opts[:recurse] / opts[:ext] not given, the user can get the same
|
87
95
|
# results explicitly with arguments like .glob("**", "*.rb")
|
88
|
-
#
|
96
|
+
#
|
89
97
|
# :all : if :all is the only argument, this is the same as .glob("**", "*")
|
90
|
-
#
|
98
|
+
#
|
91
99
|
# Examples:
|
92
100
|
# @path.glob( "css", "*.css" ) # Picks up all css files in the css folder
|
93
101
|
# @path.glob( "css", :ext => :css ) # same
|
@@ -95,20 +103,20 @@ module FunWith
|
|
95
103
|
# @path.glob(:all) # same. Note: :all cannot be used in conjunction with :ext or any other arguments. Which may be a mistake on my part.
|
96
104
|
# @path.glob("**", "*") # same
|
97
105
|
# @path.entries # synonym for :all, :recursive => false
|
98
|
-
#
|
106
|
+
#
|
99
107
|
# TODO: depth argument? depth should override recurse. When extention given, recursion should default to true?
|
100
108
|
# the find -depth argument says depth(0) is the root of the searched directory, any files beneath would be depth(1)
|
101
109
|
def glob( *args, &block )
|
102
110
|
args.push( :all ) if args.fwf_blank?
|
103
111
|
opts = args.last.is_a?(Hash) ? args.pop : {}
|
104
|
-
|
112
|
+
|
105
113
|
if args.last == :all
|
106
114
|
all_arg_given = true
|
107
115
|
args.pop
|
108
116
|
else
|
109
117
|
all_arg_given = false
|
110
118
|
end
|
111
|
-
|
119
|
+
|
112
120
|
flags = case (flags_given = opts.delete(:flags))
|
113
121
|
when NilClass
|
114
122
|
0
|
@@ -119,10 +127,10 @@ module FunWith
|
|
119
127
|
when Integer
|
120
128
|
flags_given
|
121
129
|
end
|
122
|
-
|
130
|
+
|
123
131
|
flags |= File::FNM_DOTMATCH if opts[:dots]
|
124
132
|
flags |= File::FNM_CASEFOLD if opts[:sensitive] # case sensitive. Only applies to Windows.
|
125
|
-
|
133
|
+
|
126
134
|
recurse = if all_arg_given
|
127
135
|
if opts[:recursive] == false || opts[:recurse] == false
|
128
136
|
false
|
@@ -132,7 +140,7 @@ module FunWith
|
|
132
140
|
else
|
133
141
|
opts[:recursive] == true || opts[:recurse] == true || false
|
134
142
|
end
|
135
|
-
|
143
|
+
|
136
144
|
if all_arg_given
|
137
145
|
if recurse
|
138
146
|
args = ["**", "*"]
|
@@ -155,15 +163,15 @@ module FunWith
|
|
155
163
|
nil
|
156
164
|
end
|
157
165
|
end
|
158
|
-
|
166
|
+
|
159
167
|
args.push( extensions ) if extensions
|
160
168
|
end
|
161
|
-
|
169
|
+
|
162
170
|
class_to_return = opts[:class] || self.class
|
163
|
-
|
171
|
+
|
164
172
|
files = Dir.glob( self.join(*args), flags ).map{ |f| class_to_return.new( f ) }
|
165
173
|
files.reject!{ |f| f.basename.to_s.match( /^\.\.?$/ ) } unless opts[:parent_and_current]
|
166
|
-
|
174
|
+
|
167
175
|
if block_given?
|
168
176
|
for file in files
|
169
177
|
yield file
|
@@ -172,11 +180,11 @@ module FunWith
|
|
172
180
|
files
|
173
181
|
end
|
174
182
|
end
|
175
|
-
|
183
|
+
|
176
184
|
def entries
|
177
185
|
self.glob( :recurse => false )
|
178
186
|
end
|
179
|
-
|
187
|
+
|
180
188
|
def expand
|
181
189
|
self.class.new( File.expand_path( self ) )
|
182
190
|
end
|
@@ -184,14 +192,14 @@ module FunWith
|
|
184
192
|
# Raises error if self is a file and args present.
|
185
193
|
# Raises error if the file is not accessible for writing, or cannot be created.
|
186
194
|
# attempts to create a directory
|
187
|
-
#
|
195
|
+
#
|
188
196
|
# Takes an options hash as the last argument, allowing same options as FileUtils.touch
|
189
197
|
def touch( *args, &block )
|
190
198
|
args, opts = extract_opts_from_args( args )
|
191
|
-
|
199
|
+
|
192
200
|
raise "Cannot create subdirectory to a file" if self.file? && args.length > 0
|
193
201
|
touched = self.join(*args)
|
194
|
-
|
202
|
+
|
195
203
|
dir_for_touched_file = case args.length
|
196
204
|
when 0
|
197
205
|
self.up
|
@@ -200,39 +208,63 @@ module FunWith
|
|
200
208
|
when 2..Float::INFINITY
|
201
209
|
self.join( *(args[0..-2] ) )
|
202
210
|
end
|
203
|
-
|
211
|
+
|
204
212
|
self.touch_dir( dir_for_touched_file, opts ) unless dir_for_touched_file.directory?
|
205
213
|
FileUtils.touch( touched, narrow_options( opts, FileUtils::OPT_TABLE["touch"] ) )
|
206
|
-
|
214
|
+
|
207
215
|
yield touched if block_given?
|
208
216
|
return touched
|
209
217
|
end
|
210
|
-
|
218
|
+
|
211
219
|
# Takes the options of both FileUtils.touch and FileUtils.mkdir_p
|
212
220
|
# mkdir_p options will only matter if the directory is being created.
|
213
221
|
def touch_dir( *args, &block )
|
214
222
|
args, opts = extract_opts_from_args( args )
|
215
|
-
|
223
|
+
|
216
224
|
touched = self.join(*args)
|
217
225
|
if touched.directory?
|
218
226
|
FileUtils.touch( touched, narrow_options( opts, FileUtils::OPT_TABLE["touch"] ) ) # update access time
|
219
227
|
else
|
220
228
|
FileUtils.mkdir_p( touched, narrow_options( opts, FileUtils::OPT_TABLE["mkdir_p"] ) ) # create directory (and any needed parents)
|
221
229
|
end
|
222
|
-
|
230
|
+
|
223
231
|
yield touched if block_given?
|
224
232
|
return touched
|
225
233
|
end
|
226
|
-
|
227
|
-
def write(
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
234
|
+
|
235
|
+
def write( *args, &block )
|
236
|
+
args, opts = extract_opts_from_args( args )
|
237
|
+
|
238
|
+
content = args.first
|
239
|
+
|
240
|
+
if content == :random
|
241
|
+
self.write_random_data( opts )
|
242
|
+
else
|
243
|
+
File.open( self, "w" ) do |f|
|
244
|
+
f << content if content
|
245
|
+
if block_given?
|
246
|
+
yield f
|
247
|
+
end
|
232
248
|
end
|
233
249
|
end
|
234
250
|
end
|
235
|
-
|
251
|
+
|
252
|
+
# sz: number of bytes to write to the file
|
253
|
+
# opts[:mode] => :overwrite or :append
|
254
|
+
# seed: What number to seed the random number generator with
|
255
|
+
#
|
256
|
+
# FUTURE: May perform slowly on large sz inputs?
|
257
|
+
def write_random_data( sz, opts = {} )
|
258
|
+
rng = Random.new( opts[:seed] || Random::new_seed )
|
259
|
+
mode = opts[:mode] || :overwrite
|
260
|
+
|
261
|
+
if mode == :overwrite
|
262
|
+
self.write( rng.bytes( sz ) )
|
263
|
+
elsif mode == :append
|
264
|
+
self.append( rng.bytes( sz ) )
|
265
|
+
end
|
266
|
+
end
|
267
|
+
|
236
268
|
def append( content = nil, &block )
|
237
269
|
File.open( self, "a" ) do |f|
|
238
270
|
f << content if content
|
@@ -241,9 +273,9 @@ module FunWith
|
|
241
273
|
end
|
242
274
|
end
|
243
275
|
end
|
244
|
-
|
276
|
+
|
245
277
|
# Returns a [list] of the lines in the file matching the given file. Contrast with
|
246
|
-
|
278
|
+
|
247
279
|
def grep( regex, &block )
|
248
280
|
return [] unless self.file?
|
249
281
|
matching = []
|
@@ -251,8 +283,8 @@ module FunWith
|
|
251
283
|
matching.push( line ) if line.match( regex )
|
252
284
|
yield line if block_given?
|
253
285
|
end
|
254
|
-
|
255
|
-
|
286
|
+
|
287
|
+
|
256
288
|
matching
|
257
289
|
end
|
258
290
|
|
@@ -261,23 +293,23 @@ module FunWith
|
|
261
293
|
# must not have any data in it.
|
262
294
|
def empty?
|
263
295
|
raise Exceptions::FileDoesNotExist unless self.exist?
|
264
|
-
|
296
|
+
|
265
297
|
if self.file?
|
266
298
|
File.size( self ) == 0
|
267
299
|
elsif self.directory?
|
268
300
|
self.glob( :all ).fwf_blank?
|
269
301
|
end
|
270
302
|
end
|
271
|
-
|
303
|
+
|
272
304
|
# Does not return a filepath
|
273
305
|
def basename_no_ext
|
274
306
|
self.basename.to_s.split(".")[0..-2].join(".")
|
275
307
|
end
|
276
|
-
|
308
|
+
|
277
309
|
def without_ext
|
278
310
|
self.gsub(/\.#{self.ext}$/, '')
|
279
311
|
end
|
280
|
-
|
312
|
+
|
281
313
|
# Two separate modes. With no arguments given, returns the current extension as a string (not a filepath)
|
282
314
|
# With an argument, returns the path with a .(arg) tacked onto the end. The leading period is wholly optional.
|
283
315
|
# Does not return a filepath.
|
@@ -286,52 +318,58 @@ module FunWith
|
|
286
318
|
if args.length == 0
|
287
319
|
split_basename = self.basename.to_s.split(".")
|
288
320
|
split_basename.length > 1 ? split_basename.last : ""
|
289
|
-
|
290
|
-
|
291
|
-
|
321
|
+
else
|
322
|
+
|
323
|
+
append_to_path = args.compact.map{ |ex|
|
324
|
+
ex.to_s.gsub( /^\./, '' )
|
325
|
+
}.compact.join( "." )
|
326
|
+
|
327
|
+
appended_to_path = "." + "#{append_to_path}" unless append_to_path.fwf_blank?
|
328
|
+
|
329
|
+
self.class.new( "#{@path}#{appended_to_path}" )
|
292
330
|
end
|
293
331
|
end
|
294
|
-
|
332
|
+
|
295
333
|
# base, ext = @path.basename_and_ext
|
296
334
|
def basename_and_ext
|
297
335
|
[self.basename_no_ext, self.ext]
|
298
336
|
end
|
299
|
-
|
300
|
-
|
301
|
-
|
337
|
+
|
338
|
+
|
339
|
+
|
302
340
|
def dirname_and_basename
|
303
341
|
warn("FilePath#dirname_and_basename() is deprecated. Pathname#split() already existed, and should be used instead.")
|
304
342
|
[self.dirname, self.basename]
|
305
343
|
end
|
306
|
-
|
344
|
+
|
307
345
|
def dirname_and_basename_and_ext
|
308
346
|
[self.dirname, self.basename_no_ext, self.ext]
|
309
347
|
end
|
310
|
-
|
348
|
+
|
311
349
|
# if it's a file, returns the immediate parent directory.
|
312
350
|
# if it's not a file, returns itself
|
313
351
|
def directory
|
314
352
|
self.directory? ? self : self.dirname
|
315
353
|
end
|
316
|
-
|
354
|
+
|
317
355
|
def original?
|
318
356
|
!self.symlink?
|
319
357
|
end
|
320
|
-
|
358
|
+
|
321
359
|
def original
|
322
360
|
self.symlink? ? self.readlink.original : self
|
323
361
|
end
|
324
|
-
|
362
|
+
|
325
363
|
# Basically Pathname.relative_path_from, but you can pass in strings
|
326
364
|
def relative_path_from( dir )
|
327
365
|
dir = super( Pathname.new( dir ) )
|
328
366
|
self.class.new( dir )
|
329
367
|
end
|
330
|
-
|
368
|
+
|
331
369
|
def fwf_filepath
|
332
370
|
self
|
333
371
|
end
|
334
|
-
|
372
|
+
|
335
373
|
# Gives a sequence of files. Examples:
|
336
374
|
# file.dat --> file.000000.dat
|
337
375
|
# file_without_ext --> file_without_ext.000000
|
@@ -341,7 +379,7 @@ module FunWith
|
|
341
379
|
# You can change the length of the sequence string by passing
|
342
380
|
# in an argument, but it should always be the same value for
|
343
381
|
# a given set of files.
|
344
|
-
#
|
382
|
+
#
|
345
383
|
# TODO: Need to get this relying on the specifier() method.
|
346
384
|
def succ( opts = { digit_count: SUCC_DIGIT_COUNT, timestamp: false } )
|
347
385
|
if timestamp = opts[:timestamp]
|
@@ -352,7 +390,7 @@ module FunWith
|
|
352
390
|
timestamp = false
|
353
391
|
digit_count = opts[:digit_count]
|
354
392
|
end
|
355
|
-
|
393
|
+
|
356
394
|
chunks = self.basename.to_s.split(".")
|
357
395
|
# not yet sequence stamped, no file extension.
|
358
396
|
if chunks.length == 1
|
@@ -384,17 +422,17 @@ module FunWith
|
|
384
422
|
|
385
423
|
self.up.join( chunks.join(".") )
|
386
424
|
end
|
387
|
-
|
388
|
-
|
425
|
+
|
426
|
+
|
389
427
|
def timestamp( format = true, &block )
|
390
428
|
nxt = self.succ( :timestamp => format )
|
391
429
|
yield nxt if block_given?
|
392
430
|
nxt
|
393
431
|
end
|
394
|
-
|
432
|
+
|
395
433
|
# puts a string between the main part of the basename and the extension
|
396
434
|
# or after the basename if there is no extension. Used to describe some
|
397
|
-
# file variant.
|
435
|
+
# file variant.
|
398
436
|
# Example "/home/docs/my_awesome_screenplay.txt".fwf_filepath.specifier("final_draft")
|
399
437
|
# => FunWith::Files::FilePath:/home/docs/my_awesome_screenplay.final_draft.txt
|
400
438
|
#
|
@@ -402,16 +440,16 @@ module FunWith
|
|
402
440
|
def specifier( str )
|
403
441
|
str = str.to_s
|
404
442
|
chunks = self.to_s.split(".")
|
405
|
-
|
443
|
+
|
406
444
|
if chunks.length == 1
|
407
445
|
chunks << str
|
408
446
|
else
|
409
447
|
chunks = chunks[0..-2] + [str] + [chunks[-1]]
|
410
448
|
end
|
411
|
-
|
449
|
+
|
412
450
|
chunks.join(".").fwf_filepath
|
413
451
|
end
|
414
|
-
|
452
|
+
|
415
453
|
# TODO: succession : enumerates a sequence of files that get passed
|
416
454
|
# to a block in order.
|
417
455
|
def succession( opts = { digit_count: SUCC_DIGIT_COUNT, timestamp: false } )
|
@@ -423,10 +461,10 @@ module FunWith
|
|
423
461
|
timestamp = false
|
424
462
|
digit_count = opts[:digit_count]
|
425
463
|
end
|
426
|
-
|
464
|
+
|
427
465
|
chunks = self.basename.to_s.split(".")
|
428
466
|
glob_stamp_matcher = '[0-9]' * digit_count
|
429
|
-
|
467
|
+
|
430
468
|
# unstamped filename, no extension
|
431
469
|
if chunks.length == 1
|
432
470
|
original = chunks.first
|
@@ -444,15 +482,15 @@ module FunWith
|
|
444
482
|
original = chunks.join(".")
|
445
483
|
stamped = [ chunks[0..-2], glob_stamp_matcher, chunks[-1] ].flatten.join(".")
|
446
484
|
end
|
447
|
-
|
485
|
+
|
448
486
|
[self.dirname.join(original), self.dirname.glob(stamped)].flatten
|
449
487
|
end
|
450
488
|
|
451
489
|
|
452
|
-
|
490
|
+
|
453
491
|
# TODO: succ_last : find the last existing file of the given sequence.
|
454
492
|
# TODO: succ_next : find the first free file of the given sequence
|
455
|
-
|
493
|
+
|
456
494
|
def load
|
457
495
|
if self.directory?
|
458
496
|
self.glob( :recursive => true, :ext => "rb" ).map(&:load)
|
@@ -460,12 +498,12 @@ module FunWith
|
|
460
498
|
Kernel.load( self.expand )
|
461
499
|
end
|
462
500
|
end
|
463
|
-
|
501
|
+
|
464
502
|
# Require ALL THE RUBY!
|
465
503
|
# This may be a bad idea...
|
466
|
-
#
|
504
|
+
#
|
467
505
|
# Sometimes it fails to require a file because one of the necessary prerequisites
|
468
|
-
# hasn't been required yet (NameError). requir catches this failure and stores
|
506
|
+
# hasn't been required yet (NameError). requir catches this failure and stores
|
469
507
|
# the failed requirement in order to try it later. Doesn't fail until it goes through
|
470
508
|
# a full loop where none of the required files were successful.
|
471
509
|
def requir
|
@@ -474,12 +512,12 @@ module FunWith
|
|
474
512
|
successfully_required = 1337 # need to break into initial loop
|
475
513
|
failed_requirements = []
|
476
514
|
error_messages = []
|
477
|
-
|
515
|
+
|
478
516
|
while requirements.length > 0 && successfully_required > 0
|
479
517
|
successfully_required = 0
|
480
518
|
failed_requirements = []
|
481
519
|
error_messages = []
|
482
|
-
|
520
|
+
|
483
521
|
for requirement in requirements
|
484
522
|
begin
|
485
523
|
requirement.requir
|
@@ -489,30 +527,30 @@ module FunWith
|
|
489
527
|
error_messages << "Error while requiring #{requirement} : #{e.message} (#{e.class})"
|
490
528
|
end
|
491
529
|
end
|
492
|
-
|
530
|
+
|
493
531
|
requirements = failed_requirements
|
494
532
|
end
|
495
|
-
|
533
|
+
|
496
534
|
if failed_requirements.length > 0
|
497
535
|
msg = "requiring directory #{self} failed:\n"
|
498
536
|
for message in error_messages
|
499
537
|
msg << "\n\terror message: #{message}"
|
500
538
|
end
|
501
|
-
|
539
|
+
|
502
540
|
raise NameError.new(msg)
|
503
541
|
end
|
504
542
|
else
|
505
543
|
require self.expand.gsub( /\.rb$/, '' )
|
506
544
|
end
|
507
545
|
end
|
508
|
-
|
546
|
+
|
509
547
|
def root?
|
510
548
|
self == self.up
|
511
549
|
end
|
512
|
-
|
550
|
+
|
513
551
|
def descend( &block )
|
514
552
|
path = self.clone
|
515
|
-
|
553
|
+
|
516
554
|
if path.root?
|
517
555
|
yield path
|
518
556
|
else
|
@@ -520,10 +558,10 @@ module FunWith
|
|
520
558
|
yield self
|
521
559
|
end
|
522
560
|
end
|
523
|
-
|
561
|
+
|
524
562
|
def ascend( &block )
|
525
563
|
path = self.clone
|
526
|
-
|
564
|
+
|
527
565
|
if path.root?
|
528
566
|
yield path
|
529
567
|
else
|
@@ -531,7 +569,7 @@ module FunWith
|
|
531
569
|
self.up.ascend( &block )
|
532
570
|
end
|
533
571
|
end
|
534
|
-
|
572
|
+
|
535
573
|
def to_pathname
|
536
574
|
Pathname.new( @path )
|
537
575
|
end
|
@@ -546,7 +584,7 @@ module FunWith
|
|
546
584
|
# end
|
547
585
|
# # otherwise we're installing a separator
|
548
586
|
# end
|
549
|
-
|
587
|
+
|
550
588
|
protected
|
551
589
|
# TODO: Need a separate API for user to call
|
552
590
|
def _must_be_a_file
|
@@ -555,25 +593,25 @@ module FunWith
|
|
555
593
|
raise Errno::EACCESS.new( "Can only call FunWith::Files::FilePath##{calling_method}() on an existing file.")
|
556
594
|
end
|
557
595
|
end
|
558
|
-
|
596
|
+
|
559
597
|
def _must_be_a_directory
|
560
598
|
unless self.directory?
|
561
599
|
calling_method = caller[0][/`.*'/][1..-2]
|
562
600
|
raise Errno::EACCESS.new( "Can only call FunWith::Files::FilePath##{calling_method}() on an existing directory.")
|
563
601
|
end
|
564
602
|
end
|
565
|
-
|
603
|
+
|
566
604
|
def _must_be_writable
|
567
605
|
unless self.writable?
|
568
606
|
calling_method = caller[0][/`.*'/][1..-2]
|
569
607
|
raise Errno::EACCESS.new( "Error in FunWith::Files::FilePath##{calling_method}(): #{@path} not writable.")
|
570
608
|
end
|
571
609
|
end
|
572
|
-
|
610
|
+
|
573
611
|
def narrow_options( opts, keys )
|
574
612
|
opts.keep_if{ |k,v| keys.include?( k ) }
|
575
613
|
end
|
576
|
-
|
614
|
+
|
577
615
|
def extract_opts_from_args( args )
|
578
616
|
if args.last.is_a?( Hash )
|
579
617
|
[args[0..-2], args.last ]
|
@@ -581,7 +619,7 @@ module FunWith
|
|
581
619
|
[args, {}]
|
582
620
|
end
|
583
621
|
end
|
584
|
-
|
622
|
+
|
585
623
|
def yield_and_return( obj, &block )
|
586
624
|
yield obj if block_given?
|
587
625
|
obj
|
@@ -29,12 +29,16 @@ class TestDirectoryBuilder < FunWith::Files::TestCase
|
|
29
29
|
assert_equal DirectoryBuilder, b.class
|
30
30
|
assert b.current_path
|
31
31
|
assert b.current_path.exist?
|
32
|
+
|
32
33
|
b.file("widdershins.txt") do |f|
|
34
|
+
assert_empty_file( f.fwf_filepath )
|
35
|
+
|
33
36
|
f << "Hello World"
|
34
37
|
f.flush
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
+
|
39
|
+
fil = b.current_file.fwf_filepath
|
40
|
+
assert_file_not_empty fil
|
41
|
+
assert_equal 11, fil.size
|
38
42
|
end
|
39
43
|
end
|
40
44
|
end
|
@@ -85,7 +85,7 @@ class TestFileManipulation < FunWith::Files::TestCase
|
|
85
85
|
|
86
86
|
should "symlink masterfully" do
|
87
87
|
file = @dir.join( "original.txt" )
|
88
|
-
file.write( "
|
88
|
+
file.write( "I AM SPARTACUS" )
|
89
89
|
|
90
90
|
clone = file.symlink( "clone.txt" )
|
91
91
|
clone_of_clone = clone.symlink( "clone_of_clone.txt" )
|
@@ -93,7 +93,14 @@ class TestFileManipulation < FunWith::Files::TestCase
|
|
93
93
|
assert( clone_of_clone.symlink? )
|
94
94
|
assert_equal( file, clone_of_clone.original )
|
95
95
|
|
96
|
-
assert_file_contents( clone_of_clone, /
|
96
|
+
assert_file_contents( clone_of_clone, /I AM SPARTACUS/ )
|
97
|
+
|
98
|
+
subdir = @dir.join( "subdir" ).touch_dir
|
99
|
+
|
100
|
+
subdir_clone = clone_of_clone.symlink( subdir.join( "clone.txt" ) )
|
101
|
+
subdir_clone_of_clone = subdir_clone.symlink( "clone_of_clone.txt" )
|
102
|
+
|
103
|
+
assert_file_contents( subdir_clone_of_clone, /I AM SPARTACUS/ )
|
97
104
|
end
|
98
105
|
|
99
106
|
should "do nothing when opts[:noop]" do
|
@@ -101,5 +108,35 @@ class TestFileManipulation < FunWith::Files::TestCase
|
|
101
108
|
file.touch( :noop => true, :this_invalid_option_is_ignored => true, :also_this_one => "also ignored" )
|
102
109
|
assert_no_file file
|
103
110
|
end
|
111
|
+
|
112
|
+
should "pass exhaustive copypalooza" do
|
113
|
+
dir_abc = @dir.join( "A", "B", "C" ).touch_dir
|
114
|
+
dir_def = @dir.join( "D", "E", "F" ).touch_dir
|
115
|
+
|
116
|
+
file_abc = dir_abc.join( "abc.txt" )
|
117
|
+
file_abc.write( "this space for rent" )
|
118
|
+
|
119
|
+
assert_file_contents file_abc, /rent/
|
120
|
+
|
121
|
+
file_def = file_abc.cp( dir_def )
|
122
|
+
|
123
|
+
assert_match /abc\.txt/, file_def.path
|
124
|
+
assert_file_contents file_def, /rent/
|
125
|
+
|
126
|
+
|
127
|
+
# Examples: @dir.cp( "~/tmp/dir" ) would use _find_destination_from_args() to select /Users/me/tmp/dir filepath
|
128
|
+
# If it's already a file, raise an error. If the directory exists already, hmmm.... I want it to not matter, but
|
129
|
+
# it matters. And the issues raised by each operation are different. I want them to behave as similarly as possible,
|
130
|
+
# but maybe it's okay to copy a directory's contents to an existing directory, but not okay to turn that existing directory
|
131
|
+
# into a symlink.
|
132
|
+
# Assume file = "~/testdir/file.txt"
|
133
|
+
#
|
134
|
+
# file.cp( "copy.txt" ) => Copies into the same directory.
|
135
|
+
# file.cp( "../pouncer_of_destiny.epubforge") (an existing directory, despite the .ext) ==> copies into ../pouncer_of_destiny.epubforge/file.txt
|
136
|
+
# file.cp( "~/tmp/32fb768cd" ) (dest doesn't exist)
|
137
|
+
#
|
138
|
+
# Assume dir = "~/testdir/" (existing directory with file.txt in it)
|
139
|
+
# dir.cp( "")
|
140
|
+
end
|
104
141
|
end
|
105
142
|
end
|
data/test/test_file_path.rb
CHANGED
@@ -207,7 +207,7 @@ class TestFilePath < FunWith::Files::TestCase
|
|
207
207
|
@read_only_file = "/bin/bash".fwf_filepath # This usually exists. I don't know enough Windows to think of a similarly ubiquitous file.
|
208
208
|
|
209
209
|
if @read_only_file.file? && ! @read_only_file.writable?
|
210
|
-
assert_raises( Errno::
|
210
|
+
assert_raises( Errno::EPERM ) do
|
211
211
|
@read_only_file.touch
|
212
212
|
end
|
213
213
|
else
|
@@ -215,4 +215,35 @@ class TestFilePath < FunWith::Files::TestCase
|
|
215
215
|
end
|
216
216
|
end
|
217
217
|
end
|
218
|
+
|
219
|
+
context "test ext()" do
|
220
|
+
setup do
|
221
|
+
@path = "hello.txt".fwf_filepath
|
222
|
+
end
|
223
|
+
|
224
|
+
should "not change path when sent nil as an argument" do
|
225
|
+
assert_equal @path.path, @path.ext( nil ).path
|
226
|
+
end
|
227
|
+
|
228
|
+
should "append when given symbol" do
|
229
|
+
assert_equal @path.path + ".tgz", @path.ext( :tgz ).path
|
230
|
+
end
|
231
|
+
|
232
|
+
should "append when given string" do
|
233
|
+
assert_equal @path.path + ".tgz", @path.ext( 'tgz' ).path
|
234
|
+
end
|
235
|
+
|
236
|
+
should "append correctly when given leading ." do
|
237
|
+
assert_equal @path.path + ".tgz", @path.ext( '.tgz' ).path
|
238
|
+
end
|
239
|
+
|
240
|
+
should "append multiple extensions as separate args" do
|
241
|
+
assert_equal @path.path + ".backup.tar.gz", @path.ext( :backup, "tar", nil, ".gz" ).path
|
242
|
+
end
|
243
|
+
|
244
|
+
should "append multiple extensions as a single string" do
|
245
|
+
assert_equal @path.path + ".backup.tar.gz", @path.ext( ".backup.tar.gz" ).path
|
246
|
+
end
|
247
|
+
|
248
|
+
end
|
218
249
|
end
|
data/test/test_fun_with_files.rb
CHANGED
@@ -26,7 +26,7 @@ class TestFunWithFiles < FunWith::Files::TestCase
|
|
26
26
|
assert_respond_to( FunWith::Files, :root )
|
27
27
|
assert_respond_to( FunWith::Files, :version )
|
28
28
|
|
29
|
-
assert_equal "0.0.
|
29
|
+
assert_equal "0.0.13", FunWith::Files.version # Gotta change with every point release. Ick.
|
30
30
|
end
|
31
31
|
end
|
32
32
|
end
|
data/test/test_symlinking.rb
CHANGED
metadata
CHANGED
@@ -1,108 +1,116 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: fun_with_files
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.14
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Bryce Anderson
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2016-06-26 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: xdg
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- - ~>
|
17
|
+
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
19
|
version: '2'
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
|
-
- - ~>
|
24
|
+
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '2'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: fun_with_testing
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
|
-
- - ~>
|
31
|
+
- - "~>"
|
32
32
|
- !ruby/object:Gem::Version
|
33
33
|
version: '0.0'
|
34
34
|
type: :development
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
|
-
- - ~>
|
38
|
+
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '0.0'
|
41
|
-
description:
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
41
|
+
description: |2
|
42
|
+
A more intuitive syntax for performing a variety of file actions. Examples:
|
43
|
+
"/".fwf_filepath.join('usr', 'bin', 'bash').touch
|
44
|
+
FunWith::Files::FilePath.home("Music").glob(:ext => "mp3", :recurse => true)
|
45
|
+
home = FunWith::Files::FilePath.home
|
46
|
+
home.touch( "Music", "CDs", "BubbleBoyTechnoRemixxxx2011", "01-jiggypalooza.mp3" )
|
47
|
+
home.touch_dir( "Music", "CDs", "ReggaeSmackdown2008" ) do |dir|
|
48
|
+
dir.touch( "liner_notes.txt" )
|
49
|
+
dir.touch( "cover.jpg" )
|
50
|
+
dir.touch( "01-tokin_by_the_sea.mp3" )
|
51
|
+
dir.touch( "02-tourists_be_crazy_mon.mp3" )
|
52
|
+
end
|
48
53
|
email: keeputahweird@gmail.com
|
49
54
|
executables: []
|
50
55
|
extensions: []
|
51
56
|
extra_rdoc_files:
|
57
|
+
- CHANGELOG.markdown
|
52
58
|
- LICENSE.txt
|
53
59
|
- README.rdoc
|
54
60
|
files:
|
55
|
-
- ./lib/fun_with/files/core_extensions/array.rb
|
56
|
-
- ./lib/fun_with/files/core_extensions/false.rb
|
57
|
-
- ./lib/fun_with/files/core_extensions/
|
58
|
-
- ./lib/fun_with/files/core_extensions/
|
59
|
-
- ./lib/fun_with/files/core_extensions/
|
60
|
-
- ./lib/fun_with/files/core_extensions/
|
61
|
-
- ./lib/fun_with/files/
|
62
|
-
- ./lib/fun_with/files/
|
63
|
-
- ./lib/fun_with/files/
|
64
|
-
- ./lib/fun_with/files/
|
65
|
-
- ./lib/fun_with/files/
|
66
|
-
- ./lib/fun_with/files/
|
67
|
-
- ./lib/fun_with/files/
|
68
|
-
- ./lib/fun_with/files/
|
69
|
-
- ./lib/fun_with/files/
|
70
|
-
- ./lib/fun_with/files/
|
71
|
-
- ./lib/fun_with/files/
|
72
|
-
- ./lib/fun_with/files/
|
73
|
-
- ./lib/fun_with/files/
|
74
|
-
- ./lib/fun_with/files/
|
75
|
-
- ./lib/fun_with/files/
|
76
|
-
- ./lib/fun_with/files/
|
77
|
-
- ./lib/fun_with/files/
|
78
|
-
- ./lib/
|
79
|
-
- ./
|
80
|
-
- ./test/data/
|
81
|
-
- ./test/data/
|
82
|
-
- ./test/data/
|
83
|
-
- ./test/data/
|
84
|
-
- ./test/
|
85
|
-
- ./test/
|
86
|
-
- ./test/loadable_dir/
|
87
|
-
- ./test/loadable_dir/
|
88
|
-
- ./test/loadable_dir/
|
89
|
-
- ./test/loadable_dir/
|
90
|
-
- ./test/loadable_dir/dir5/
|
91
|
-
- ./test/loadable_dir/dir5/
|
92
|
-
- ./test/loadable_dir/dir5/
|
93
|
-
- ./test/
|
94
|
-
- ./test/
|
95
|
-
- ./test/
|
96
|
-
- ./test/
|
97
|
-
- ./test/
|
98
|
-
- ./test/
|
99
|
-
- ./test/
|
100
|
-
- ./test/
|
101
|
-
- ./test/
|
102
|
-
- ./test/
|
103
|
-
- ./test/
|
104
|
-
- ./test/
|
105
|
-
- ./test/
|
61
|
+
- "./lib/fun_with/files/core_extensions/array.rb"
|
62
|
+
- "./lib/fun_with/files/core_extensions/false.rb"
|
63
|
+
- "./lib/fun_with/files/core_extensions/file.rb"
|
64
|
+
- "./lib/fun_with/files/core_extensions/hash.rb"
|
65
|
+
- "./lib/fun_with/files/core_extensions/nil.rb"
|
66
|
+
- "./lib/fun_with/files/core_extensions/object.rb"
|
67
|
+
- "./lib/fun_with/files/core_extensions/string.rb"
|
68
|
+
- "./lib/fun_with/files/digest_methods.rb"
|
69
|
+
- "./lib/fun_with/files/directory_builder.rb"
|
70
|
+
- "./lib/fun_with/files/downloader.rb"
|
71
|
+
- "./lib/fun_with/files/errors.rb"
|
72
|
+
- "./lib/fun_with/files/file_manipulation_methods.rb"
|
73
|
+
- "./lib/fun_with/files/file_orderer.rb"
|
74
|
+
- "./lib/fun_with/files/file_path.rb"
|
75
|
+
- "./lib/fun_with/files/file_path_class_methods.rb"
|
76
|
+
- "./lib/fun_with/files/file_permission_methods.rb"
|
77
|
+
- "./lib/fun_with/files/file_requirements.rb"
|
78
|
+
- "./lib/fun_with/files/gem_api.rb"
|
79
|
+
- "./lib/fun_with/files/pathname_extensions.rb"
|
80
|
+
- "./lib/fun_with/files/remote_path.rb"
|
81
|
+
- "./lib/fun_with/files/root_path.rb"
|
82
|
+
- "./lib/fun_with/files/string_behavior.rb"
|
83
|
+
- "./lib/fun_with/files/string_extensions.rb"
|
84
|
+
- "./lib/fun_with/files/xdg_extensions.rb"
|
85
|
+
- "./lib/fun_with_files.rb"
|
86
|
+
- "./test/data/empty.txt"
|
87
|
+
- "./test/data/grep1.txt"
|
88
|
+
- "./test/data/grep2.txt"
|
89
|
+
- "./test/data/gsub1.txt"
|
90
|
+
- "./test/data/gsub2.txt"
|
91
|
+
- "./test/helper.rb"
|
92
|
+
- "./test/loadable_dir/dir1/file1.rb"
|
93
|
+
- "./test/loadable_dir/dir2/file2.rb"
|
94
|
+
- "./test/loadable_dir/dir3/file3.rb"
|
95
|
+
- "./test/loadable_dir/dir4/file4.rb"
|
96
|
+
- "./test/loadable_dir/dir5/a.rb"
|
97
|
+
- "./test/loadable_dir/dir5/b.rb"
|
98
|
+
- "./test/loadable_dir/dir5/c.rb"
|
99
|
+
- "./test/loadable_dir/dir5/d.rb"
|
100
|
+
- "./test/test_copying.rb"
|
101
|
+
- "./test/test_core_extensions.rb"
|
102
|
+
- "./test/test_descent.rb"
|
103
|
+
- "./test/test_digest.rb"
|
104
|
+
- "./test/test_directory_builder.rb"
|
105
|
+
- "./test/test_file_manipulation.rb"
|
106
|
+
- "./test/test_file_path.rb"
|
107
|
+
- "./test/test_fun_with_files.rb"
|
108
|
+
- "./test/test_globbing.rb"
|
109
|
+
- "./test/test_loading.rb"
|
110
|
+
- "./test/test_root_path.rb"
|
111
|
+
- "./test/test_symlinking.rb"
|
112
|
+
- "./test/test_touching.rb"
|
113
|
+
- CHANGELOG.markdown
|
106
114
|
- Gemfile
|
107
115
|
- LICENSE.txt
|
108
116
|
- README.rdoc
|
@@ -118,17 +126,17 @@ require_paths:
|
|
118
126
|
- lib
|
119
127
|
required_ruby_version: !ruby/object:Gem::Requirement
|
120
128
|
requirements:
|
121
|
-
- -
|
129
|
+
- - ">="
|
122
130
|
- !ruby/object:Gem::Version
|
123
131
|
version: '0'
|
124
132
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
125
133
|
requirements:
|
126
|
-
- -
|
134
|
+
- - ">="
|
127
135
|
- !ruby/object:Gem::Version
|
128
136
|
version: '0'
|
129
137
|
requirements: []
|
130
138
|
rubyforge_project:
|
131
|
-
rubygems_version: 2.
|
139
|
+
rubygems_version: 2.4.6
|
132
140
|
signing_key:
|
133
141
|
specification_version: 4
|
134
142
|
summary: A mashup of several File, FileUtils, and Dir class functions, with a peppy,
|