furoshiki 0.0.2 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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