furoshiki 0.0.2 → 0.1.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.
Files changed (43) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +3 -0
  3. data/.rspec +2 -0
  4. data/Gemfile +9 -0
  5. data/README.rdoc +33 -28
  6. data/Rakefile +3 -1
  7. data/furoshiki.gemspec +2 -1
  8. data/lib/furoshiki/exceptions.rb +3 -0
  9. data/lib/furoshiki/shoes/configuration.rb +146 -0
  10. data/lib/furoshiki/shoes/swt_app.rb +217 -0
  11. data/lib/furoshiki/shoes/swt_jar.rb +62 -0
  12. data/lib/furoshiki/shoes.rb +15 -0
  13. data/lib/furoshiki/version.rb +1 -1
  14. data/lib/furoshiki/zip/directory.rb +19 -0
  15. data/lib/furoshiki/zip/directory_contents.rb +20 -0
  16. data/lib/furoshiki/zip/recursive.rb +58 -0
  17. data/lib/furoshiki/zip.rb +2 -0
  18. data/lib/furoshiki.rb +3 -1
  19. data/lib/warbler/traits/shoes.rb +51 -0
  20. data/spec/shoes/configuration_spec.rb +156 -0
  21. data/spec/shoes/spec_helper.rb +68 -0
  22. data/spec/shoes/support/shared_config.rb +6 -0
  23. data/spec/shoes/swt_app_spec.rb +119 -0
  24. data/spec/shoes/swt_jar_spec.rb +45 -0
  25. data/spec/shoes/test_app/app.yaml +17 -0
  26. data/spec/shoes/test_app/bin/hello_world +3 -0
  27. data/spec/shoes/test_app/dir_to_ignore/file_to_ignore.txt +1 -0
  28. data/spec/shoes/test_app/img/boots.icns +0 -0
  29. data/spec/shoes/test_app/img/boots.ico +0 -0
  30. data/spec/shoes/test_app/img/boots_512x512x32.png +0 -0
  31. data/spec/shoes/test_app/sibling.rb +1 -0
  32. data/spec/spec_helper.rb +32 -0
  33. data/spec/support/shared_zip.rb +21 -0
  34. data/spec/support/zip/a/a.rb +3 -0
  35. data/spec/support/zip/a/b/b.png +0 -0
  36. data/spec/support/zip/a/b/c/c.rb +3 -0
  37. data/spec/zip/directory_contents_spec.rb +25 -0
  38. data/spec/zip/directory_spec.rb +30 -0
  39. data/vendor/appbundler-1.0.jar +0 -0
  40. metadata +103 -47
  41. data/.rvmrc +0 -1
  42. data/Gemfile.lock +0 -7
  43. data/lib/furoshiki/rake_task.rb +0 -19
@@ -0,0 +1,58 @@
1
+ require 'pathname'
2
+ require 'zip/zip'
3
+
4
+ module Furoshiki
5
+ module Zip
6
+ # Adapted from rubyzip's sample, ZipFileGenerator
7
+ #
8
+ # This is a utility class that uses rubyzip to recursively
9
+ # generate a zip file containing the given entries and all of
10
+ # their children.
11
+ #
12
+ # Best used through frontend classes Furoshiki::Zip::Directory or
13
+ # Furoshiki::Zip::DirectoryContents
14
+ #
15
+ # @example
16
+ # To zip the directory "/tmp/input" so that unarchiving
17
+ # gives you a single directory "input":
18
+ #
19
+ # zip = Furoshiki::Zip::Recursive
20
+ # entries = Pathname.new("/tmp/input").entries
21
+ # zip_prefix = ''
22
+ # disk_prefix = '/tmp'
23
+ # output_file = '/tmp/out.zip'
24
+ # zf.write(entries, disk_prefix, zip_prefix, output_file)
25
+ class Recursive
26
+ def initialize(output_file)
27
+ @output_file = output_file.to_s
28
+ end
29
+
30
+ # @param [Array<Pathname>] entries the initial set of files to include
31
+ # @param [Pathname] disk_prefix a path prefix for existing entries
32
+ # @param [Pathname] zip_prefix a path prefix to add within archive
33
+ # @param [Pathname] output_file the location of the output archive
34
+ def write(entries, disk_prefix, zip_prefix)
35
+ io = ::Zip::ZipFile.open(@output_file, ::Zip::ZipFile::CREATE);
36
+ write_entries(entries, disk_prefix, zip_prefix, io)
37
+ io.close();
38
+ end
39
+
40
+ # A helper method to make the recursion work.
41
+ private
42
+ def write_entries(entries, disk_prefix, path, io)
43
+ entries.each do |e|
44
+ zip_path = path.to_s == "" ? e.basename : path.join(e.basename)
45
+ disk_path = disk_prefix.join(zip_path)
46
+ puts "Deflating #{disk_path}"
47
+ if disk_path.directory?
48
+ io.mkdir(zip_path)
49
+ subdir = disk_path.children(false)
50
+ write_entries(subdir, disk_prefix, zip_path, io)
51
+ else
52
+ io.get_output_stream(zip_path) { |f| f.puts(File.open(disk_path, "rb").read())}
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,2 @@
1
+ require 'furoshiki/zip/directory'
2
+ require 'furoshiki/zip/directory_contents'
data/lib/furoshiki.rb CHANGED
@@ -1 +1,3 @@
1
- require_relative 'furoshiki/rake_task'
1
+ puts "OMG, nothing here!"
2
+ puts ""
3
+ puts "You probably want to `require 'furoshiki/shoes'`.
@@ -0,0 +1,51 @@
1
+ require 'furoshiki/shoes/configuration'
2
+
3
+ module Warbler
4
+ module Traits
5
+ # Hack to control the executable
6
+ class NoGemspec
7
+ def update_archive(jar); end
8
+ end
9
+
10
+ class Shoes
11
+ include Trait
12
+ include PathmapHelper
13
+
14
+ def self.detect?
15
+ #File.exist? "app.yaml"
16
+ true
17
+ end
18
+
19
+ def self.requires?(trait)
20
+ # Actually, it would be better to dump the NoGemspec trait, but since
21
+ # we can't do that, we can at least make sure that this trait gets
22
+ # processed later by declaring that it requires NoGemspec.
23
+ [Traits::Jar, Traits::NoGemspec].include? trait
24
+ end
25
+
26
+ def after_configure
27
+ config.init_contents << StringIO.new("require 'shoes'\nShoes.configuration.backend = :swt\n")
28
+ end
29
+
30
+ def update_archive(jar)
31
+ # Not sure why Warbler doesn't do this automatically
32
+ jar.files.delete_if { |k, v| @config.excludes.include? k }
33
+ add_main_rb(jar, apply_pathmaps(config, default_executable, :application))
34
+ end
35
+
36
+ # Uses the `@config.run` if it exists. Otherwise, looks in the
37
+ # application's `bin` directory for an executable with the same name as
38
+ # the jar. If this also fails, defaults to the first executable (alphabetically) in the
39
+ # applications `bin` directory.
40
+ #
41
+ # @return [String] filename of the executable to run
42
+ def default_executable
43
+ return @config.run if @config.run
44
+ exes = Dir['bin/*'].sort
45
+ exe = exes.grep(/#{config.jar_name}/).first || exes.first
46
+ raise "No executable script found" unless exe
47
+ exe
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,156 @@
1
+ require_relative 'spec_helper'
2
+ require 'furoshiki/shoes/configuration'
3
+
4
+ describe Furoshiki::Shoes::Configuration do
5
+ context "defaults" do
6
+ subject { Furoshiki::Shoes::Configuration.new }
7
+
8
+ its(:name) { should eq('Shoes App') }
9
+ its(:shortname) { should eq('shoesapp') }
10
+ its(:ignore) { should eq(['pkg']) }
11
+ its(:gems) { should include('shoes') }
12
+ its(:version) { should eq('0.0.0') }
13
+ its(:release) { should eq('Rookie') }
14
+ its(:icons) { should be_an_instance_of(Hash) }
15
+ its(:dmg) { should be_an_instance_of(Hash) }
16
+ its(:run) { should be_nil }
17
+
18
+ describe "#icon" do
19
+ it 'osx is nil' do
20
+ subject.icons[:osx].should be_nil
21
+ end
22
+
23
+ it 'gtk is nil' do
24
+ subject.icons[:gtk].should be_nil
25
+ end
26
+
27
+ it 'win32 is nil' do
28
+ subject.icons[:win32].should be_nil
29
+ end
30
+ end
31
+
32
+ describe "#dmg" do
33
+ it "has ds_store" do
34
+ subject.dmg[:ds_store].should eq('path/to/default/.DS_Store')
35
+ end
36
+
37
+ it "has background" do
38
+ subject.dmg[:background].should eq('path/to/default/background.png')
39
+ end
40
+ end
41
+
42
+ describe "#to_hash" do
43
+ it "round-trips" do
44
+ Furoshiki::Shoes::Configuration.new(subject.to_hash).should eq(subject)
45
+ end
46
+ end
47
+ end
48
+
49
+ context "with options" do
50
+ include_context 'config'
51
+ subject { Furoshiki::Shoes::Configuration.load(config_filename) }
52
+
53
+ its(:name) { should eq('Sugar Clouds') }
54
+ its(:shortname) { should eq('sweet-nebulae') }
55
+ its(:ignore) { should include('pkg') }
56
+ its(:gems) { should include('rspec') }
57
+ its(:gems) { should include('shoes') }
58
+ its(:version) { should eq('0.0.1') }
59
+ its(:release) { should eq('Mindfully') }
60
+ its(:icons) { should be_an_instance_of(Hash) }
61
+ its(:dmg) { should be_an_instance_of(Hash) }
62
+
63
+ describe "#icon" do
64
+ it 'has osx' do
65
+ subject.icons[:osx].should eq('img/boots.icns')
66
+ end
67
+
68
+ it 'has gtk' do
69
+ subject.icons[:gtk].should eq('img/boots_512x512x32.png')
70
+ end
71
+
72
+ it 'has win32' do
73
+ subject.icons[:win32].should eq('img/boots.ico')
74
+ end
75
+ end
76
+
77
+ describe "#dmg" do
78
+ it "has ds_store" do
79
+ subject.dmg[:ds_store].should eq('path/to/custom/.DS_Store')
80
+ end
81
+
82
+ it "has background" do
83
+ subject.dmg[:background].should eq('path/to/custom/background.png')
84
+ end
85
+ end
86
+
87
+ it "incorporates custom features" do
88
+ subject.custom.should eq('my custom feature')
89
+ end
90
+ end
91
+
92
+ context "with name, but without explicit shortname" do
93
+ let(:options) { {:name => "Sugar Clouds"} }
94
+ subject { Furoshiki::Shoes::Configuration.new options }
95
+
96
+ its(:name) { should eq("Sugar Clouds") }
97
+ its(:shortname) { should eq("sugarclouds") }
98
+ end
99
+
100
+ context "auto-loading" do
101
+ include_context 'config'
102
+
103
+ context "without a path" do
104
+ it "looks for 'app.yaml' in current directory" do
105
+ Dir.chdir config_filename.parent do
106
+ config = Furoshiki::Shoes::Configuration.load
107
+ config.shortname.should eq('sweet-nebulae')
108
+ end
109
+ end
110
+
111
+ it "blows up if it can't find the file" do
112
+ Dir.chdir File.dirname(__FILE__) do
113
+ lambda { config = Furoshiki::Shoes::Configuration.load }.should raise_error
114
+ end
115
+ end
116
+ end
117
+
118
+ shared_examples "config with path" do
119
+ it "finds the config" do
120
+ Dir.chdir File.dirname(__FILE__) do
121
+ config = Furoshiki::Shoes::Configuration.load(path)
122
+ config.shortname.should eq('sweet-nebulae')
123
+ end
124
+ end
125
+ end
126
+
127
+ context "with an 'app.yaml'" do
128
+ let(:path) { config_filename }
129
+ it_behaves_like "config with path"
130
+ end
131
+
132
+ context "with a path to a directory containing an 'app.yaml'" do
133
+ let(:path) { config_filename.parent }
134
+ it_behaves_like "config with path"
135
+ end
136
+
137
+ context "with a path to a file that is siblings with an 'app.yaml'" do
138
+ let(:path) { config_filename.parent.join('sibling.rb') }
139
+ it_behaves_like "config with path"
140
+ end
141
+
142
+ context "with a path that exists, but no 'app.yaml'" do
143
+ let(:path) { config_filename.parent.join('bin/hello_world') }
144
+ subject { Furoshiki::Shoes::Configuration.load(path) }
145
+
146
+ its(:name) { should eq('hello_world') }
147
+ its(:shortname) { should eq('hello_world') }
148
+ end
149
+
150
+ context "when the file doesn't exist" do
151
+ it "blows up" do
152
+ lambda { Furoshiki::Shoes::Configuration.load('some/bogus/path') }.should raise_error
153
+ end
154
+ end
155
+ end
156
+ end
@@ -0,0 +1,68 @@
1
+ SHOESSPEC_ROOT = File.expand_path('..', __FILE__)
2
+
3
+ # Packaging caches files in $HOME/.furoshiki/cache by default.
4
+ # For testing, we override $HOME using $FUROSHIKI_HOME
5
+ ENV['FUROSHIKI_HOME'] = SHOESSPEC_ROOT
6
+
7
+ require 'rspec'
8
+ require 'pathname'
9
+ require 'furoshiki/shoes'
10
+
11
+ # Guards for running or not running specs. Specs in the guarded block only
12
+ # run if the guard conditions are met.
13
+ #
14
+ # @see Guard#backend_is
15
+ module Guard
16
+ # Runs specs only if backend matches given name
17
+ #
18
+ # @example
19
+ # backend_is :swt do
20
+ # specify "backend_name is :swt" do
21
+ # # body of spec
22
+ # end
23
+ # end
24
+ def backend_is(backend)
25
+ yield if Shoes.configuration.backend_name == backend && block_given?
26
+ end
27
+
28
+ # Runs specs only if platform matches
29
+ #
30
+ # @example
31
+ # platform_is :windows do
32
+ # it "does something only on windows" do
33
+ # # specification
34
+ # end
35
+ # end
36
+ def platform_is(platform)
37
+ yield if self.send "platform_is_#{platform.to_s}"
38
+ end
39
+
40
+ # Runs specs only if platform does not match
41
+ #
42
+ # @example
43
+ # platform_is_not :windows do
44
+ # it "does something only on posix systems" do
45
+ # # specification
46
+ # end
47
+ # end
48
+ def platform_is_not(platform)
49
+ yield unless self.send "platform_is_#{platform.to_s}"
50
+ end
51
+
52
+ def platform_is_windows
53
+ return RbConfig::CONFIG['host_os'] =~ /windows|mswin/i
54
+ end
55
+
56
+ def platform_is_linux
57
+ return RbConfig::CONFIG['host_os'] =~ /linux/i
58
+ end
59
+
60
+ def platform_is_osx
61
+ return RbConfig::CONFIG['host_os'] =~ /darwin/i
62
+ end
63
+ end
64
+
65
+ include Guard
66
+
67
+ Dir["#{SHOESSPEC_ROOT}/support/**/*.rb"].each {|f| require f}
68
+
@@ -0,0 +1,6 @@
1
+ require 'yaml'
2
+ require 'pathname'
3
+
4
+ shared_context 'config' do
5
+ let(:config_filename) { Pathname.new(__FILE__).join('../../test_app/app.yaml').cleanpath }
6
+ end
@@ -0,0 +1,119 @@
1
+ require 'spec_helper'
2
+ require_relative 'spec_helper'
3
+ require 'pathname'
4
+ require 'furoshiki/shoes/swt_app'
5
+
6
+ include PackageHelpers
7
+
8
+ describe Furoshiki::Shoes::SwtApp do
9
+ include_context 'config'
10
+ include_context 'package'
11
+
12
+ let(:app_name) { 'Sugar Clouds.app' }
13
+ let(:output_file) { output_dir.join app_name }
14
+ let(:config) { Furoshiki::Shoes::Configuration.load config_filename}
15
+ let(:launcher) { output_file.join('Contents/MacOS/JavaAppLauncher') }
16
+ let(:icon) { output_file.join('Contents/Resources/boots.icns') }
17
+ let(:jar) { output_file.join('Contents/Java/sweet-nebulae.jar') }
18
+ subject { Furoshiki::Shoes::SwtApp.new config }
19
+
20
+ # $FUROSHIKI_HOME is set in spec_helper.rb for testing purposes,
21
+ # but should default to $HOME
22
+ context "when not setting $FUROSHIKI_HOME" do
23
+ before do
24
+ @old_furoshiki_home = ENV['FUROSHIKI_HOME']
25
+ ENV['FUROSHIKI_HOME'] = nil
26
+ end
27
+
28
+ its(:cache_dir) { should eq(Pathname.new(Dir.home).join('.furoshiki', 'cache')) }
29
+
30
+ after do
31
+ ENV['FUROSHIKI_HOME'] = @old_furoshiki_home
32
+ end
33
+ end
34
+
35
+ context "default" do
36
+ let(:cache_dir) { Pathname.new(SHOESSPEC_ROOT).join('.furoshiki', 'cache') }
37
+ its(:cache_dir) { should eq(cache_dir) }
38
+
39
+ it "sets package dir to {pwd}/pkg" do
40
+ Dir.chdir app_dir do
41
+ subject.default_package_dir.should eq(app_dir.join 'pkg')
42
+ end
43
+ end
44
+
45
+ its(:template_path) { should eq(cache_dir.join('shoes-app-template.zip')) }
46
+ its(:remote_template_url) { should eq('http://shoesrb.com/downloads/shoes-app-template-0.0.1.zip') }
47
+ end
48
+
49
+ context "when creating a .app" do
50
+ before :all do
51
+ output_dir.rmtree if output_dir.exist?
52
+ output_dir.mkpath
53
+ Dir.chdir app_dir do
54
+ subject.package
55
+ end
56
+ end
57
+
58
+ its(:template_path) { should exist }
59
+
60
+ it "creates a .app" do
61
+ output_file.should exist
62
+ end
63
+
64
+ it "includes launcher" do
65
+ launcher.should exist
66
+ end
67
+
68
+ # Windows can't test this
69
+ platform_is_not :windows do
70
+ it "makes launcher executable" do
71
+ launcher.should be_executable
72
+ end
73
+ end
74
+
75
+ it "deletes generic icon" do
76
+ icon.parent.join('GenericApp.icns').should_not exist
77
+ end
78
+
79
+ it "injects icon" do
80
+ icon.should exist
81
+ end
82
+
83
+ it "injects jar" do
84
+ jar.should exist
85
+ end
86
+
87
+ it "removes any extraneous jars" do
88
+ jar_dir_contents = output_file.join("Contents/Java").children
89
+ jar_dir_contents.reject {|f| f == jar }.should be_empty
90
+ end
91
+
92
+ describe "Info.plist" do
93
+ require 'plist'
94
+ before :all do
95
+ @plist = Plist.parse_xml(output_file.join 'Contents/Info.plist')
96
+ end
97
+
98
+ it "sets identifier" do
99
+ @plist['CFBundleIdentifier'].should eq('com.hackety.shoes.sweet-nebulae')
100
+ end
101
+
102
+ it "sets display name" do
103
+ @plist['CFBundleDisplayName'].should eq('Sugar Clouds')
104
+ end
105
+
106
+ it "sets bundle name" do
107
+ @plist['CFBundleName'].should eq('Sugar Clouds')
108
+ end
109
+
110
+ it "sets icon" do
111
+ @plist['CFBundleIconFile'].should eq('boots.icns')
112
+ end
113
+
114
+ it "sets version" do
115
+ @plist['CFBundleVersion'].should eq('0.0.1')
116
+ end
117
+ end
118
+ end
119
+ end
@@ -0,0 +1,45 @@
1
+ require_relative 'spec_helper'
2
+ require 'pathname'
3
+ require 'furoshiki/shoes/swt_jar'
4
+
5
+ include PackageHelpers
6
+
7
+ describe Furoshiki::Shoes::SwtJar do
8
+ include_context 'config'
9
+ include_context 'package'
10
+
11
+ context "when creating a .jar" do
12
+ before :all do
13
+ output_dir.rmtree if output_dir.exist?
14
+ output_dir.mkpath
15
+ Dir.chdir app_dir do
16
+ @jar_path = subject.package(output_dir)
17
+ end
18
+ end
19
+
20
+ let(:jar_name) { 'sweet-nebulae.jar' }
21
+ let(:output_file) { Pathname.new(output_dir.join jar_name) }
22
+ let(:config) { Furoshiki::Shoes::Configuration.load(config_filename) }
23
+ subject { Furoshiki::Shoes::SwtJar.new(config) }
24
+
25
+ it "creates a .jar" do
26
+ output_file.should exist
27
+ end
28
+
29
+ it "returns path to .jar" do
30
+ @jar_path.should eq(output_file.to_s)
31
+ end
32
+
33
+ it "creates .jar smaller than 50MB" do
34
+ File.size(output_file).should be < 50 * 1024 * 1024
35
+ end
36
+
37
+ it "excludes directories recursively" do
38
+ jar = Zip::ZipFile.new(output_file)
39
+ jar.entries.should_not include("dir_to_ignore/file_to_ignore")
40
+ end
41
+
42
+ its(:default_dir) { should eq(output_dir) }
43
+ its(:filename) { should eq(jar_name) }
44
+ end
45
+ end
@@ -0,0 +1,17 @@
1
+ name: Sugar Clouds
2
+ shortname: sweet-nebulae
3
+ ignore:
4
+ - pkg
5
+ - dir_to_ignore
6
+ run: bin/hello_world
7
+ gems: rspec
8
+ version: 0.0.1
9
+ release: Mindfully
10
+ icons:
11
+ osx: img/boots.icns
12
+ gtk: img/boots_512x512x32.png
13
+ win32: img/boots.ico
14
+ dmg:
15
+ ds_store: path/to/custom/.DS_Store
16
+ background: path/to/custom/background.png
17
+ custom: my custom feature
@@ -0,0 +1,3 @@
1
+ Shoes.app do
2
+ banner "Hello world"
3
+ end
@@ -0,0 +1 @@
1
+ should be ignored
Binary file
Binary file
@@ -0,0 +1 @@
1
+ # Just a sibling of 'app.yaml'
@@ -0,0 +1,32 @@
1
+ module PackageHelpers
2
+ # need these values from a context block, so let doesn't work
3
+ def spec_dir
4
+ Pathname.new(__FILE__).join('..').cleanpath
5
+ end
6
+
7
+ def input_dir
8
+ spec_dir.join 'support', 'zip'
9
+ end
10
+ end
11
+
12
+ module ZipHelpers
13
+ include PackageHelpers
14
+ # dir = Pathname.new('spec/support/zip')
15
+ # add_trailing_slash(dir) #=> '/path/to/spec/support/zip/'
16
+ def add_trailing_slash(dir)
17
+ dir.to_s + "/"
18
+ end
19
+
20
+ def relative_input_paths(from_dir)
21
+ Pathname.glob(input_dir + "**/*").map do |p|
22
+ directory = true if p.directory?
23
+ relative_path = p.relative_path_from(from_dir).to_s
24
+ relative_path = add_trailing_slash(relative_path) if directory
25
+ relative_path
26
+ end
27
+ end
28
+ end
29
+
30
+ spec_root = File.dirname(__FILE__)
31
+ Dir["#{spec_root}/support/**/*.rb"].each { |f| require f }
32
+
@@ -0,0 +1,21 @@
1
+ include ZipHelpers
2
+
3
+ shared_context 'package' do
4
+ let(:app_dir) { spec_dir.join 'shoes/test_app' }
5
+ let(:output_dir) { app_dir.join 'pkg' }
6
+ end
7
+
8
+ shared_context 'zip' do
9
+ include_context 'package'
10
+ let(:output_file) { output_dir.join 'zip_directory_spec.zip' }
11
+ let(:zip) { Zip::ZipFile.open output_file }
12
+
13
+ before :all do
14
+ output_dir.mkpath
15
+ subject.write
16
+ end
17
+
18
+ after :all do
19
+ FileUtils.rm_rf output_dir
20
+ end
21
+ end
@@ -0,0 +1,3 @@
1
+ def a
2
+ puts 'a'
3
+ end
Binary file
@@ -0,0 +1,3 @@
1
+ def c
2
+ puts 'c'
3
+ end
@@ -0,0 +1,25 @@
1
+ require 'spec_helper'
2
+ require 'fileutils'
3
+ require 'furoshiki/zip'
4
+
5
+ describe Furoshiki::Zip::DirectoryContents do
6
+ subject { Furoshiki::Zip::DirectoryContents.new input_dir, output_file }
7
+
8
+ context "output file" do
9
+ include_context 'zip'
10
+
11
+ it "exists" do
12
+ output_file.should exist
13
+ end
14
+
15
+ it "does not include input directory without parents" do
16
+ zip.entries.map(&:name).should_not include(add_trailing_slash input_dir.basename)
17
+ end
18
+
19
+ relative_input_paths(input_dir).each do |path|
20
+ it "includes all children of input directory" do
21
+ zip.entries.map(&:name).should include(path)
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,30 @@
1
+ require 'spec_helper'
2
+ require 'fileutils'
3
+ require 'furoshiki/zip'
4
+
5
+ describe Furoshiki::Zip::Directory do
6
+ subject { Furoshiki::Zip::Directory.new input_dir, output_file }
7
+
8
+ context "output file" do
9
+ include_context 'zip'
10
+
11
+ it "exists" do
12
+ output_file.should exist
13
+ end
14
+
15
+ it "includes input directory without parents" do
16
+ zip.entries.map(&:name).should include(add_trailing_slash input_dir.basename)
17
+ end
18
+
19
+ relative_input_paths(input_dir.parent).each do |path|
20
+ it "includes all children of input directory" do
21
+ zip.entries.map(&:name).should include(path)
22
+ end
23
+ end
24
+
25
+ it "doesn't include extra files" do
26
+ number_of_files = Dir.glob("#{input_dir}/**/*").push(input_dir).length
27
+ zip.entries.length.should eq(number_of_files)
28
+ end
29
+ end
30
+ end
Binary file