fun_with_files 0.0.13 → 0.0.14
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.
- 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,
|