files 0.1.0 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +64 -10
- data/files.gemspec +1 -1
- data/lib/files.rb +25 -6
- data/lib/files/version.rb +1 -1
- data/test/files_test.rb +68 -15
- metadata +9 -9
data/README.md
CHANGED
@@ -2,11 +2,35 @@
|
|
2
2
|
|
3
3
|
*a simple DSL for creating temporary files and directories*
|
4
4
|
|
5
|
-
|
5
|
+
Ever want to create a whole bunch of files at once? Like when you're writing tests for a tool that processes files? The Files gem lets you cleanly specify those files and their contents inside your test code, instead of forcing you to create a fixture directory and check it in to your repo. It puts them in a temporary directory and cleans up when your test is done.
|
6
|
+
|
7
|
+
## Usage (mixin mode)
|
8
|
+
|
9
|
+
The mixin mode is a fairly clean API, suitable for use in unit tests. After `include Files` you can call `file` or `dir` to make a temporary file or directory; it'll put them into a new temp dir that is removed on process exit. It also saves a reference to this directory inside an instance variable named `@files` so you can't use that name for your own instance variables.
|
10
|
+
|
11
|
+
require "files"
|
12
|
+
include Files
|
13
|
+
|
14
|
+
file "hello.txt" # creates file "hello.txt" containing "contents of hello.txt"
|
15
|
+
|
16
|
+
dir "web" do # creates directory "web"
|
17
|
+
file "snippet.html", # creates file "web/snippet.html"...
|
18
|
+
"<h1>Fix this!</h1>" # ...containing "<h1>Fix this!</h1>"
|
19
|
+
dir "img" do # creates directory "web/img"
|
20
|
+
file File.new("data/hello.png") # containing a copy of hello.png
|
21
|
+
file "hi.png", File.new("data/hello.png") # and a copy of hello.png named hi.png
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
files.root # creates (or returns) the temporary directory
|
26
|
+
|
27
|
+
## Usage (bare function mode)
|
28
|
+
|
29
|
+
In bare function mode, you call the `Files` method, which doesn't pollute the current object with a `@files` instance variable. It returns a string with the path to the root temp dir that you can use later.
|
6
30
|
|
7
31
|
require "files"
|
8
32
|
|
9
|
-
|
33
|
+
temp_dir = Files do # creates a temporary directory inside Dir.tmpdir
|
10
34
|
file "hello.txt" # creates file "hello.txt" containing "contents of hello.txt"
|
11
35
|
dir "web" do # creates directory "web"
|
12
36
|
file "snippet.html", # creates file "web/snippet.html"...
|
@@ -16,24 +40,54 @@
|
|
16
40
|
file "hi.png", File.new("data/hello.png") # and a copy of hello.png named hi.png
|
17
41
|
end
|
18
42
|
end
|
19
|
-
end # returns a string with the path to the directory
|
43
|
+
end # "Files" returns a string with the path to the directory
|
20
44
|
|
21
|
-
|
45
|
+
|
46
|
+
see `test/files_test.rb` for more usage examples
|
22
47
|
|
23
48
|
## Details
|
24
49
|
|
25
50
|
* the directory will be removed at exit
|
26
51
|
* unless you pass `:remove => false`
|
27
52
|
* the directory name is based on the name of the source file you called Files from
|
53
|
+
* if the first argument to `file` is a String, then a new file is made
|
54
|
+
* the content of the new file is either a short, descriptive message, or whatever you passed as the second argument
|
55
|
+
* if the argument to `file` is a Ruby `File` object, then it copies the contents of the named file into the temporary location
|
28
56
|
|
29
57
|
## TODO
|
30
58
|
|
59
|
+
* test under Windows
|
31
60
|
* :path option -- specifying the parent of the temporary dir (default: Dir.tmpdir)
|
32
|
-
* take a hash
|
33
|
-
*
|
34
|
-
* emit a hash
|
35
|
-
* emit a YAML file or string
|
36
|
-
* support symlinks (?)
|
37
|
-
* specify file mode
|
61
|
+
* take a hash or a YAML file or YAML string to specify the directory layout and contents
|
62
|
+
* emit a hash or a YAML file or string to serialize the directory layout and contents for later
|
38
63
|
* copy an entire data dir
|
64
|
+
* support symlinks (?)
|
65
|
+
* specify file write mode (?)
|
39
66
|
* play nice with FakeFS (possibly with a :fake option)
|
67
|
+
* global/default :remove option
|
68
|
+
|
69
|
+
## Credits
|
70
|
+
|
71
|
+
Written by Alex Chaffee <http://alexchaffee.com> <mailto:alex@stinky.com> <http://github.com/alexch> [@alexch](http://twitter.com/alexch)
|
72
|
+
|
73
|
+
## License
|
74
|
+
|
75
|
+
Copyright (C) 2012 Alex Chaffee
|
76
|
+
|
77
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
78
|
+
this software and associated documentation files (the "Software"), to deal in
|
79
|
+
the Software without restriction, including without limitation the rights to
|
80
|
+
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
81
|
+
of the Software, and to permit persons to whom the Software is furnished to do
|
82
|
+
so, subject to the following conditions:
|
83
|
+
|
84
|
+
The above copyright notice and this permission notice shall be included in all
|
85
|
+
copies or substantial portions of the Software.
|
86
|
+
|
87
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
88
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
89
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
90
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
91
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
92
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
93
|
+
SOFTWARE.
|
data/files.gemspec
CHANGED
@@ -9,7 +9,7 @@ Gem::Specification.new do |s|
|
|
9
9
|
s.email = ["alex@stinky.com"]
|
10
10
|
s.homepage = ""
|
11
11
|
s.summary = %q{a simple DSL for creating temporary files and directories}
|
12
|
-
s.description = %q{
|
12
|
+
s.description = %q{Ever want to create a whole bunch of files at once? Like when you're writing tests for a tool that processes files? The Files gem lets you cleanly specify those files and their contents inside your test code, instead of forcing you to create a fixture directory and check it in to your repo. It puts them in a temporary directory and cleans up when your test is done.}
|
13
13
|
|
14
14
|
s.rubyforge_project = "files"
|
15
15
|
|
data/lib/files.rb
CHANGED
@@ -1,7 +1,8 @@
|
|
1
1
|
require "files/version"
|
2
2
|
|
3
|
-
|
4
3
|
module Files
|
4
|
+
|
5
|
+
# class methods
|
5
6
|
|
6
7
|
def self.default_options level = 2
|
7
8
|
{:remove => true, :name => called_from(level)}
|
@@ -18,11 +19,23 @@ module Files
|
|
18
19
|
name = options[:name]
|
19
20
|
path = File.join(Dir::tmpdir, "#{name}_#{Time.now.to_i}_#{rand(1000)}")
|
20
21
|
|
21
|
-
|
22
|
-
|
23
|
-
files.root
|
22
|
+
Files.new path, block, options
|
24
23
|
end
|
25
24
|
|
25
|
+
# mixin methods
|
26
|
+
def files options = ::Files.default_options # todo: block
|
27
|
+
@files ||= ::Files.create(options)
|
28
|
+
end
|
29
|
+
|
30
|
+
def file *args, &block
|
31
|
+
files.file *args, &block
|
32
|
+
end
|
33
|
+
|
34
|
+
def dir *args, &block
|
35
|
+
files.dir *args, &block
|
36
|
+
end
|
37
|
+
|
38
|
+
# concrete class for creating files and dirs under a temporary directory
|
26
39
|
class Files
|
27
40
|
|
28
41
|
attr_reader :root
|
@@ -31,7 +44,8 @@ module Files
|
|
31
44
|
@root = path
|
32
45
|
@dirs = []
|
33
46
|
dir path, &block
|
34
|
-
|
47
|
+
@dirs = [path]
|
48
|
+
at_exit {remove} if options[:remove]
|
35
49
|
end
|
36
50
|
|
37
51
|
def dir name, &block
|
@@ -62,6 +76,10 @@ module Files
|
|
62
76
|
end
|
63
77
|
end
|
64
78
|
|
79
|
+
def remove
|
80
|
+
FileUtils.rm_rf(@root) if File.exists?(@root)
|
81
|
+
end
|
82
|
+
|
65
83
|
private
|
66
84
|
def current
|
67
85
|
@dirs.join('/')
|
@@ -71,5 +89,6 @@ module Files
|
|
71
89
|
end
|
72
90
|
|
73
91
|
def Files options = Files.default_options, &block
|
74
|
-
Files.create options, &block
|
92
|
+
files = Files.create options, &block
|
93
|
+
files.root
|
75
94
|
end
|
data/lib/files/version.rb
CHANGED
data/test/files_test.rb
CHANGED
@@ -5,21 +5,28 @@ here = File.dirname __FILE__
|
|
5
5
|
$LOAD_PATH.unshift File.join(here, '..', 'lib')
|
6
6
|
require "files"
|
7
7
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
8
|
+
## Testing the Files object
|
9
|
+
|
10
|
+
files = Files.create # creates a temporary directory inside Dir.tmpdir
|
11
|
+
|
12
|
+
assert { files.root }
|
13
|
+
|
14
|
+
files.file "hello.txt" # creates file "hello.txt" containing "contents of hello.txt"
|
15
|
+
files.dir "web" do # creates directory "web"
|
16
|
+
file "snippet.html", # creates file "web/snippet.html", with content
|
17
|
+
"<h1>File under F for fantastic!</h1>"
|
18
|
+
dir "img" do # creates directory "web/img"
|
19
|
+
file File.new("#{here}/data/cheez_doing_it_wrong.jpg") # containing a copy of cheez_doing_it_wrong.jpg
|
20
|
+
file "other.jpg", # and a different named file...
|
21
|
+
File.new("#{here}/data/cheez_doing_it_wrong.jpg") # containing the content of cheez_doing_it_wrong.jpg
|
18
22
|
end
|
19
23
|
end
|
20
24
|
|
25
|
+
dir = files.root
|
21
26
|
assert { dir.split('/').last =~ /^files_test/ }
|
22
27
|
|
28
|
+
assert { dir =~ /^#{Dir::tmpdir}/}
|
29
|
+
|
23
30
|
assert { File.read("#{dir}/hello.txt") == "contents of hello.txt" }
|
24
31
|
assert { File.read("#{dir}/web/snippet.html") == "<h1>File under F for fantastic!</h1>" }
|
25
32
|
assert {
|
@@ -31,10 +38,19 @@ assert {
|
|
31
38
|
File.read("#{here}/data/cheez_doing_it_wrong.jpg")
|
32
39
|
}
|
33
40
|
|
41
|
+
files.remove
|
42
|
+
assert("remove removes the root dir and all contents") { !File.exist?(dir) }
|
43
|
+
assert("after remove, the object is bogus") do
|
44
|
+
rescuing { (files.file "uhoh.txt") }.is_a? Errno::ENOENT
|
45
|
+
end
|
46
|
+
|
47
|
+
## Testing the Files method (which is the recommended public API)
|
48
|
+
|
34
49
|
dir = Files do
|
35
50
|
file "hello.txt"
|
36
51
|
dir("web") { file "hello.html" }
|
37
52
|
end
|
53
|
+
assert { dir }
|
38
54
|
assert { File.read("#{dir}/hello.txt") == "contents of hello.txt" }
|
39
55
|
assert { File.read("#{dir}/web/hello.html") == "contents of hello.html" }
|
40
56
|
assert { dir.split('/').last =~ /^files_test/ }
|
@@ -72,18 +88,17 @@ dir = Files do
|
|
72
88
|
end
|
73
89
|
assert { File.exist? "#{dir}/a" and File.directory? "#{dir}/a"}
|
74
90
|
|
75
|
-
|
76
|
-
# the file and dir methods return the path, suitable for saving into a predeclared local var
|
91
|
+
# the file and dir methods return the path, suitable for storing in a predeclared local var
|
77
92
|
stuff = nil
|
78
93
|
hello = nil
|
79
|
-
|
94
|
+
files_dir = Files do
|
80
95
|
stuff = dir "stuff" do
|
81
96
|
hello = file "hello.txt"
|
82
97
|
end
|
83
98
|
end
|
84
99
|
|
85
|
-
assert { stuff == "#{
|
86
|
-
assert { hello == "#{
|
100
|
+
assert { stuff == "#{files_dir}/stuff" }
|
101
|
+
assert { hello == "#{files_dir}/stuff/hello.txt" }
|
87
102
|
|
88
103
|
dir_inside_do_block = nil
|
89
104
|
dir = Files do
|
@@ -95,3 +110,41 @@ end
|
|
95
110
|
assert("sets the current directory inside the Files block") { File.basename(dir_inside_do_block) == File.basename(dir) }
|
96
111
|
# note that we can't just compare the full paths because some OS's hard link their temp dir to different base paths
|
97
112
|
|
113
|
+
## Testing the Mixin interface (which is the alternate public API)
|
114
|
+
class FilesMixinTest
|
115
|
+
include Files
|
116
|
+
def go
|
117
|
+
assert {@files.nil?}
|
118
|
+
file "foo.txt"
|
119
|
+
assert("calling file creates an instance var") { @files and @files.root }
|
120
|
+
assert("the method 'files' returns the instance var") { @files.object_id == files.object_id }
|
121
|
+
|
122
|
+
assert("calling file creates a file") { File.exist?("#{@files.root}/foo.txt") }
|
123
|
+
assert("the created file contains a nice message") { File.read("#{@files.root}/foo.txt") == "contents of foo.txt" }
|
124
|
+
|
125
|
+
dir "bar" do
|
126
|
+
file "bar.txt"
|
127
|
+
assert("the current directory is set inside a dir block") { File.read("bar.txt") == "contents of bar.txt" }
|
128
|
+
dir "sub" do
|
129
|
+
file "sub.txt"
|
130
|
+
assert("the current directory is set inside a nested dir block") { File.read("sub.txt") == "contents of sub.txt" }
|
131
|
+
end
|
132
|
+
end
|
133
|
+
assert("a file created inside the dir block exists under the root dir") {
|
134
|
+
File.read("#{@files.root}/bar/bar.txt") == "contents of bar.txt"
|
135
|
+
}
|
136
|
+
|
137
|
+
subdir = dir "baz"
|
138
|
+
assert("the dir method creates the dir") { File.exist?("#{@files.root}/baz")}
|
139
|
+
assert("the dir method returns the created dir") { subdir == "#{@files.root}/baz"}
|
140
|
+
assert { File.directory?("#{@files.root}/baz")}
|
141
|
+
|
142
|
+
end
|
143
|
+
end
|
144
|
+
FilesMixinTest.new.go
|
145
|
+
|
146
|
+
# TODO: allow options to be set in mixin mode
|
147
|
+
# TODO: test options from function mode and mixin mode
|
148
|
+
# files = Files.create :dummy => true
|
149
|
+
# assert { files.options[:dummy] == true }
|
150
|
+
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: files
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,13 +9,13 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-01-
|
12
|
+
date: 2012-01-24 00:00:00.000000000Z
|
13
13
|
dependencies: []
|
14
|
-
description:
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
14
|
+
description: Ever want to create a whole bunch of files at once? Like when you're
|
15
|
+
writing tests for a tool that processes files? The Files gem lets you cleanly specify
|
16
|
+
those files and their contents inside your test code, instead of forcing you to
|
17
|
+
create a fixture directory and check it in to your repo. It puts them in a temporary
|
18
|
+
directory and cleans up when your test is done.
|
19
19
|
email:
|
20
20
|
- alex@stinky.com
|
21
21
|
executables: []
|
@@ -45,7 +45,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
45
45
|
version: '0'
|
46
46
|
segments:
|
47
47
|
- 0
|
48
|
-
hash: -
|
48
|
+
hash: -1401824793539482884
|
49
49
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
50
50
|
none: false
|
51
51
|
requirements:
|
@@ -54,7 +54,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
54
54
|
version: '0'
|
55
55
|
segments:
|
56
56
|
- 0
|
57
|
-
hash: -
|
57
|
+
hash: -1401824793539482884
|
58
58
|
requirements: []
|
59
59
|
rubyforge_project: files
|
60
60
|
rubygems_version: 1.8.6
|