fixture_tree 1.0.0

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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 1dcb06bf0cff5a0bf61e4fb25d05747287af2924
4
+ data.tar.gz: 5cde802d2ccc3684465aa871fcb3e374fc559fd5
5
+ SHA512:
6
+ metadata.gz: 558ec567790defbd8ca976d7e7fe94918f51c069aa0c0c89b82bd18335761e68b3af2c7321deeab6cf5ae6ba506e133c6a1a30ae83985708d144eb135adf418a
7
+ data.tar.gz: da234c94add70c0baaf9c08f0ed423265ec2ea146e4154fb843836fc73e4dd536b9446ea307d56fb8ba172d00fbbca9dc594cf8c964bc5c6dce9147983ad3513
@@ -0,0 +1,141 @@
1
+ # Helper for creating directory hierarchies to use with tests.
2
+ #
3
+ # You'll typically create trees with `FixtureTree.create`. If you're using RSpec, put this inside one of your specs:
4
+ #
5
+ # around do |example|
6
+ # FixtureTree.create do |tree|
7
+ # @tree = tree
8
+ # example.run
9
+ # end
10
+ # end
11
+ #
12
+ # Now put some data into your tree:
13
+ #
14
+ # before do
15
+ # @tree.merge({
16
+ # 'one' => 'two', # keys can be either strings...
17
+ # three: 'four', # ...or symbols
18
+ # five: { # create nested directories by using a hash
19
+ # six: 'seven'
20
+ # }
21
+ # })
22
+ # end
23
+ #
24
+ # And test against it:
25
+ #
26
+ # it "has a file named 'one' whose contents are 'two'" do
27
+ # expect(@tree.path.join('one').open.read).to eq('two') # FixtureTree#path returns a Pathname object
28
+ # end
29
+ #
30
+ # it "has a nested directory named 'five' with a file named 'six' whose contents are 'seven'" do
31
+ # expect(@tree.path.join('five/six').open.read).to eq('seven')
32
+ # end
33
+ #
34
+ # You can add additional files if a test calls for them:
35
+ #
36
+ # it 'lets me add additional files and keeps existing ones around' do
37
+ # @tree.merge({
38
+ # 'eight.txt' => 'nine'
39
+ # })
40
+ # expect(@tree.path.join('eight.txt').open.read).to eq('nine')
41
+ # expect(@tree.path.join('one').open.read).to eq('two')
42
+ # end
43
+ #
44
+ # Or you can replace the entire tree:
45
+ #
46
+ # it 'lets me replace the entire tree' do
47
+ # @tree.replace({
48
+ # ten: 'eleven'
49
+ # })
50
+ # expect(@tree.path.join('ten').open.read).to eq('eleven')
51
+ # expect(@tree.path.join('one').exist?).to be(false)
52
+ # end
53
+ #
54
+ # The tree will be automatically deleted when your `FixtureTree#create` block exits.
55
+ class FixtureTree
56
+ attr_reader :path
57
+
58
+ # Wrap the specified `Pathname` instance with a `FixtureTree` that can be used to modify it. No special cleanup will
59
+ # be undertaken after you're done testing if you create a `FixtureTree` this way, so you'll need to make sure to
60
+ # delete it after you're done with it.
61
+ def initialize(path)
62
+ @path = path
63
+ end
64
+
65
+ # Create an ephemeral `FixtureTree`.
66
+ #
67
+ # If a block is given, the tree will be yielded to the block, and the tree's data (including any modifications made
68
+ # to it during the course of testing) will be deleted when the block exits. If not, `[dir, tree]` will be returned,
69
+ # where `dir` is a Pathname object pointing to a temporary directory containing the tree and `tree` is the ephemeral
70
+ # `FixtureTree` object. The tree's contents can be cleaned up by deleting `dir` after testing is complete.
71
+ def self.create
72
+ temp_dir = Pathname.new(Dir.mktmpdir('fixture_tree'))
73
+ tree = FixtureTree.new(temp_dir.join('fixture'))
74
+
75
+ if block_given?
76
+ begin
77
+ yield FixtureTree.new(temp_dir.join('fixture'))
78
+ ensure
79
+ temp_dir.rmtree if temp_dir.exist?
80
+ end
81
+ else
82
+ [temp_dir, tree]
83
+ end
84
+ end
85
+
86
+ # Merge the given directory hierarchy or file into this `FixtureTree`.
87
+ #
88
+ # `data` can be either a string or a hash. If it's a hash, this `FixtureTree` will be created as a directory if it's
89
+ # not already one and a file or directory created for each entry in the hash. Values can themselves be strings or
90
+ # hashes to create nested files or directories, respectively. If it's a string, this `FixtureTree` will be created
91
+ # as a file whose contents are the specified string.
92
+ def merge(data)
93
+ if data.is_a?(Hash)
94
+ delete unless @path.directory?
95
+ @path.mkpath
96
+
97
+ data.each do |name, contents|
98
+ join(name.to_s).merge(contents)
99
+ end
100
+ else
101
+ delete
102
+ @path.write(data)
103
+ end
104
+
105
+ self
106
+ end
107
+
108
+ # Replace this `FixtureTree` with the specified directory hierarchy or file. This is equivalent to calling `delete`
109
+ # followed by `merge(data)`.
110
+ def replace(data)
111
+ delete
112
+ merge(data)
113
+
114
+ self
115
+ end
116
+
117
+ # Deletes this `FixtureTree`, if it exists. If this tree is currently a directory, it will be removed along with its
118
+ # children. If this tree is currently a file, the file will be deleted.
119
+ #
120
+ # `merge` or `replace` can later be called to recreate this `FixtureTree`.
121
+ def delete
122
+ if @path.directory?
123
+ @path.rmtree
124
+ elsif @path.exist?
125
+ @path.delete
126
+ end
127
+
128
+ self
129
+ end
130
+
131
+ # Return a `FixtureTree` offering a view on a nested path of this `FixtureTree`. This can be used like:
132
+ #
133
+ # some_tree.join('foo/bar').merge({'baz' => 'qux'})
134
+ #
135
+ # to get the same effect as:
136
+ #
137
+ # some_tree.merge({'foo' => {'bar' => {'baz' => 'qux'}}})
138
+ def join(path)
139
+ FixtureTree.new(@path.join(path))
140
+ end
141
+ end
@@ -0,0 +1,112 @@
1
+ class FixtureTree
2
+ # RSpec helpers to make testing with FixtureTree even easier.
3
+ #
4
+ # Extend RSpecSupport in a test:
5
+ #
6
+ # RSpec.describe 'something' do
7
+ # extend FixtureTree::RSpecSupport
8
+ #
9
+ # # specs here
10
+ # end
11
+ #
12
+ # Or include it in all your tests:
13
+ #
14
+ # RSpec.configure do |c|
15
+ # c.extend RSpecSupport
16
+ # end
17
+ #
18
+ # You can then declare trees using `fixture_tree`:
19
+ #
20
+ # RSpec.describe 'something' do
21
+ # fixture_tree :example_tree, data: {foo: 'bar'}
22
+ #
23
+ # it "has a file named 'foo' whose contents are 'bar'" do
24
+ # expect(example_tree.path.join('foo').open.read).to eq('bar')
25
+ # end
26
+ # end
27
+ #
28
+ # Trees can be populated in `before` hooks, if you like:
29
+ #
30
+ # fixture_tree :example_tree
31
+ #
32
+ # before(:each) do
33
+ # example_tree.merge({foo: 'bar'})
34
+ # end
35
+ #
36
+ # it "has a file named 'foo' whose contents are 'bar'" do
37
+ # expect(example_tree.path.join('foo').open.read).to eq('bar')
38
+ # end
39
+ #
40
+ # Nested contexts can overwrite trees:
41
+ #
42
+ # fixture_tree :example_tree, data: {foo: 'bar'}
43
+ #
44
+ # it "has a file named 'foo'" do
45
+ # expect(example_tree.path.children.map(&:basename)).to contain_exactly('foo')
46
+ # end
47
+ #
48
+ # context 'with a different set of files' do
49
+ # fixture_tree :example_tree, data: {baz: 'qux'}
50
+ #
51
+ # it "only has a file named 'baz'" do
52
+ # expect(example_tree.path.children.map(&:basename)).to contain_exactly('baz')
53
+ # end
54
+ # end
55
+ #
56
+ # Or you can include `merge: true` to merge with the parent context's tree:
57
+ #
58
+ # fixture_tree :example_tree, data: {foo: 'bar'}
59
+ #
60
+ # it "has a file named 'foo'" do
61
+ # expect(example_tree.path.children.map(&:basename)).to contain_exactly('foo')
62
+ # end
63
+ #
64
+ # context 'with an additional file' do
65
+ # fixture_tree :example_tree, merge: true, data: {baz: 'qux'}
66
+ #
67
+ # it "has files named 'foo' and 'baz'" do
68
+ # expect(example_tree.path.children.map(&:basename)).to contain_exactly('foo', 'baz')
69
+ # end
70
+ # end
71
+ #
72
+ # And that's about it.
73
+ module RSpecSupport
74
+ def fixture_tree(name, data: nil, merge: false, eager: false)
75
+ # eager intentionally left undocumented because it's not actually useful until I implement support for running
76
+ # hooks when a tree is instantiated
77
+ let(name) do
78
+ if merge && defined?(super)
79
+ # asked to merge and super is defined. we'll assume it's a tree from an outer context and merge into it
80
+ # instead of creating a new tree.
81
+ tree = super()
82
+ else
83
+ # either our parent context doesn't define a tree or we weren't asked to merge with it, so create a new one.
84
+ temp_dir, tree = FixtureTree.create
85
+
86
+ # store the temp dir so that we can clean it up after the test completes
87
+ instance_variable_set(:"@_fixture_tree_dir_#{name}", temp_dir)
88
+ end
89
+
90
+ if data
91
+ tree.merge(data)
92
+ end
93
+ end
94
+
95
+ if eager
96
+ before do
97
+ send(name)
98
+ end
99
+ end
100
+
101
+ after do
102
+ # clean up the temp dir if we still know about one
103
+ if instance_variable_defined?(:"@_fixture_tree_dir_#{name}")
104
+ # delete it
105
+ instance_variable_get(:"@_fixture_tree_dir_#{name}").rmtree
106
+ # then unset it so that we won't accidentally try to clean it up in a parent context
107
+ remove_instance_variable(:"@_fixture_tree_dir_#{name}")
108
+ end
109
+ end
110
+ end
111
+ end
112
+ end
metadata ADDED
@@ -0,0 +1,45 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: fixture_tree
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Alex Boyd
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2016-10-18 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description:
14
+ email: aboyd@instructure.com
15
+ executables: []
16
+ extensions: []
17
+ extra_rdoc_files: []
18
+ files:
19
+ - lib/fixture_tree.rb
20
+ - lib/fixture_tree/rspec_support.rb
21
+ homepage: https://github.com/instructure/fixture_tree
22
+ licenses: []
23
+ metadata: {}
24
+ post_install_message:
25
+ rdoc_options: []
26
+ require_paths:
27
+ - lib
28
+ required_ruby_version: !ruby/object:Gem::Requirement
29
+ requirements:
30
+ - - ">="
31
+ - !ruby/object:Gem::Version
32
+ version: '0'
33
+ required_rubygems_version: !ruby/object:Gem::Requirement
34
+ requirements:
35
+ - - ">="
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
38
+ requirements: []
39
+ rubyforge_project:
40
+ rubygems_version: 2.2.2
41
+ signing_key:
42
+ specification_version: 4
43
+ summary: Helper for creating directory hierarchies to use with tests
44
+ test_files: []
45
+ has_rdoc: