ferver 1.1.0 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,59 +1,61 @@
1
+ require 'forwardable'
2
+
1
3
  # A representation of Ferver's file list
2
4
  #
3
5
  module Ferver
4
- class FileList
5
-
6
- # List of files
7
- attr_reader :files
8
-
9
- # create a new instance with a path
10
- #
11
- def initialize(path)
12
- raise ArgumentError, "No path is specified" if path.empty?
13
- raise DirectoryNotFoundError unless Dir.exists?(path)
6
+ class FileList
7
+ extend Forwardable
8
+ def_delegators :@files, :size, :each
9
+ include Enumerable
10
+
11
+ # Create a new instance with a path
12
+ #
13
+ def initialize(path)
14
+ fail ArgumentError, 'No path is specified' if path.empty?
15
+ fail DirectoryNotFoundError unless Dir.exist?(path)
16
+
17
+ @files = []
18
+ @configured_file_path = File.expand_path(path)
19
+ find_files
20
+ end
14
21
 
15
- @file_path = File.expand_path(path)
16
- find_files
17
- end
22
+ # Return an absolute path to a `file_name` in the `directory`
23
+ #
24
+ def self.path_for_file(directory, file_name)
25
+ File.join(directory, file_name)
26
+ end
18
27
 
19
- # Return an absolute path to a `file_name` in the `directory`
20
- #
21
- def self.path_for_file(directory, file_name)
22
- File.join(directory, file_name)
23
- end
28
+ # Is the file id a valid id for Ferver to serve
29
+ #
30
+ def file_id_is_valid?(file_id)
31
+ file_id < files.size
32
+ end
24
33
 
25
- # Is the file id a valid id for Ferver to serve
26
- #
27
- def file_id_is_valid?(file_id)
28
- file_id < @files.size
29
- end
34
+ # Filename by its index
35
+ #
36
+ def file_by_id(id)
37
+ files.fetch(id)
38
+ end
30
39
 
31
- # Filename by its index
32
- #
33
- def file_by_id(id)
34
- @files.fetch(id)
35
- end
40
+ def all
41
+ files
42
+ end
36
43
 
37
- # Number of files in list
38
- #
39
- def file_count
40
- @files.size
41
- end
44
+ private
42
45
 
43
- private
46
+ attr_reader :configured_file_path, :files
44
47
 
45
- # Iterate through files in specified dir for files
46
- #
47
- def find_files
48
- @files = []
48
+ # Iterate through files in specified dir for files
49
+ #
50
+ def find_files
51
+ @files = []
49
52
 
50
- Dir.foreach(@file_path) do |file|
51
- next if file == '.' or file == '..'
53
+ Dir.foreach(configured_file_path) do |file|
54
+ next if file == '.' || file == '..'
52
55
 
53
- file_path = FileList.path_for_file(@file_path, file)
54
- @files << file if File.file?(file_path)
55
- end
56
- end
57
-
56
+ file_path = FileList.path_for_file(configured_file_path, file)
57
+ @files << file if File.file?(file_path)
58
+ end
58
59
  end
59
- end
60
+ end
61
+ end
@@ -1,3 +1,3 @@
1
1
  module Ferver
2
- VERSION = "1.1.0"
2
+ VERSION = '1.2.0'
3
3
  end
@@ -0,0 +1,28 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <title>File List &middot; Ferver</title>
6
+ </head>
7
+ <body>
8
+ <h3>Files served:</h3>
9
+ <ul>
10
+ <% file_list.each_with_index do |file_name, index| %>
11
+
12
+ <li><a href="/files/<%= index %>"><%= file_name %></a></li>
13
+
14
+ <% end %>
15
+
16
+ </ul>
17
+
18
+ <p><%= file_count %> files served from: <%= ferver_path %></p>
19
+
20
+ <hr>
21
+
22
+ <p>Served by <a href="https://github.com/rob-murray/ferver" title="Ferver: A simple Ruby app serving files over HTTP">Ferver</a> gem v<%= Ferver::VERSION %></p>
23
+
24
+ </body>
25
+ </html>
26
+
27
+ <html>
28
+ <body>
@@ -0,0 +1,24 @@
1
+ require 'spec_helper'
2
+
3
+ describe Ferver::Configuration do
4
+ subject { Ferver::Configuration.new }
5
+
6
+ describe 'configured directory path' do
7
+
8
+ context 'with no path set' do
9
+ it 'should return default path' do
10
+ expect(subject.directory_path).to eq(Ferver::DEFAULT_FILE_SERVER_DIR_PATH)
11
+ end
12
+ end
13
+
14
+ context 'when directory is set' do
15
+ let(:path) { '/foo/bar' }
16
+
17
+ it 'should return default path' do
18
+ subject.directory_path = path
19
+
20
+ expect(subject.directory_path).to eq(path)
21
+ end
22
+ end
23
+ end
24
+ end
@@ -1,231 +1,183 @@
1
- require "spec_helper"
1
+ require 'spec_helper'
2
2
 
3
- describe "ferver" do
4
- include Webrat::Matchers # allow cool html matching
5
-
6
-
7
- context "given a request to the server root" do
8
-
9
- before(:each) do
10
- get "/"
11
- end
12
-
13
- it "should return redirect" do
14
- expect(last_response).to be_redirect
15
- end
16
-
17
- it "should redirect to file list" do
18
- follow_redirect!
19
-
20
- expect(last_response).to be_ok
21
- expect(last_request.url).to match(/files/)
22
- end
3
+ describe 'ferver' do
4
+ let(:file_list) { double('file-list') }
23
5
 
6
+ context 'given a request to the server root' do
7
+ before do
8
+ get '/'
24
9
  end
25
10
 
26
- describe "choosing directory to serve files from" do
27
-
28
- before {
29
- @file_list = mock()
30
- @file_list.stubs(:files).returns(EMPTY_FILE_LIST)
31
- @file_list.stubs(:file_count).returns(0)
32
- }
33
-
34
- context "when no directory is specified" do
35
-
36
- it "will use default directory" do
37
-
38
- Ferver::FileList.expects(:new).with("./").returns(@file_list)
39
-
40
- get "/files"
41
- end
11
+ it 'should return redirect' do
12
+ expect(last_response).to be_redirect
13
+ end
42
14
 
43
- end
15
+ it 'should redirect to file list' do
16
+ follow_redirect!
44
17
 
45
- context "when the directory passed via configuration" do
18
+ expect(last_response).to be_ok
19
+ expect(last_request.url).to match(/files/)
20
+ end
21
+ end
46
22
 
47
- before { Ferver::App.set :ferver_path, "/foo" }
23
+ describe 'choosing directory to serve files from' do
24
+ before do
25
+ allow(file_list).to receive(:all).and_return(EMPTY_FILE_LIST)
26
+ allow(file_list).to receive(:size).and_return(0)
27
+ end
48
28
 
49
- it "will use directory specified" do
50
- Ferver::FileList.expects(:new).with("/foo").returns(@file_list)
29
+ context 'when no directory is specified' do
30
+ it 'will use default directory' do
31
+ expect(Ferver::FileList).to receive(:new).with('./').and_return(file_list)
51
32
 
52
- get "/files"
53
- end
33
+ get '/files'
34
+ end
35
+ end
54
36
 
37
+ context 'when the directory passed via configuration' do
38
+ before do
39
+ Ferver.configure do |conf|
40
+ conf.directory_path = '/foo'
55
41
  end
42
+ end
56
43
 
57
- context "when directory does not exist" do
44
+ it 'will use directory specified' do
45
+ expect(Ferver::FileList).to receive(:new).with('/foo').and_return(file_list)
58
46
 
59
- before(:each) { Ferver::App.set :ferver_path, "/foo" }
47
+ get '/files'
48
+ end
49
+ end
60
50
 
61
- it "will attempt to create FileList with path" do
62
- Ferver::FileList.expects(:new).with("/foo").raises(Ferver::DirectoryNotFoundError)
51
+ context 'when directory does not exist' do
52
+ before do
53
+ allow(Ferver::FileList).to receive(:new).and_raise(Ferver::DirectoryNotFoundError)
54
+ end
63
55
 
64
- get "/files"
65
- end
56
+ it 'will return server error status' do
57
+ get '/files'
66
58
 
67
- it "will return server error status" do
68
- Ferver::FileList.stubs(:new).with("/foo").raises(Ferver::DirectoryNotFoundError)
59
+ expect(last_response.status).to eql 500
60
+ end
61
+ end
62
+ end
69
63
 
70
- get "/files"
64
+ context 'given an empty list of files' do
65
+ before do
66
+ allow(file_list).to receive(:all).and_return(EMPTY_FILE_LIST)
67
+ allow(file_list).to receive(:size).and_return(0)
68
+ allow(Ferver::FileList).to receive(:new).and_return(file_list)
69
+ end
71
70
 
72
- last_response.status.should eql 500
73
- end
71
+ context 'when no content-type is requested' do
72
+ before { get '/files' }
74
73
 
75
- end
74
+ it 'should return valid response' do
75
+ expect(last_response).to be_ok
76
+ end
76
77
 
78
+ it 'should contain no file list in response content' do
79
+ expect(last_response.body).not_to have_tag('li')
80
+ expect(last_response.body).to have_tag('p', text: /0 files/)
81
+ end
77
82
  end
78
83
 
79
- context "given an empty list of files" do
84
+ context 'when json content-type is requested' do
85
+ before do
86
+ get '/files', {}, 'HTTP_ACCEPT' => 'application/json'
87
+ end
80
88
 
81
- before {
82
- file_list = mock()
83
- file_list.stubs(:files).returns(EMPTY_FILE_LIST)
84
- file_list.stubs(:file_count).returns(0)
85
- Ferver::FileList.stubs(:new).returns(file_list)
86
- }
89
+ it 'should return valid response' do
90
+ expect(last_response).to be_ok
91
+ expect(last_response.content_type).to include('application/json')
92
+ end
87
93
 
88
- context "when no content-type is requested" do
94
+ it 'should contain no file list in response content' do
95
+ list = JSON.parse last_response.body
96
+ expect(list).to eq(EMPTY_FILE_LIST)
97
+ end
98
+ end
99
+ end
89
100
 
90
- before { get "/files" }
101
+ context 'given a list of files' do
102
+ before do
103
+ allow(file_list).to receive(:all).and_return(%w(file1 file2))
104
+ allow(file_list).to receive(:size).and_return(2)
105
+ allow(Ferver::FileList).to receive(:new).and_return(file_list)
106
+ end
91
107
 
92
- it "should return valid response" do
93
- expect(last_response).to be_ok
94
- #todo test html
95
- end
108
+ describe 'file list request' do
96
109
 
97
- it "should contain no file list in response content" do
98
- expect(last_response.body).to have_selector("li", :count => 0)
99
- expect(last_response.body).to contain(/0 files/)
100
- end
110
+ context 'when no content-type is requested' do
111
+ before { get '/files' }
101
112
 
113
+ it 'should return valid response' do
114
+ expect(last_response).to be_ok
102
115
  end
103
116
 
104
- context "when json content-type is requested" do
105
-
106
- before {
107
- get "/files", {}, {"HTTP_ACCEPT" => "application/json" }
108
- }
109
-
110
- it "should return valid response" do
111
- expect(last_response).to be_ok
112
- expect(last_response.content_type).to include("application/json")
113
- end
114
-
115
- it "should contain no file list in response content" do
116
- list = JSON.parse last_response.body
117
- expect(list).to eq(EMPTY_FILE_LIST)
118
- end
119
-
117
+ it 'should contain no file list in response content' do
118
+ expect(last_response.body).to have_tag('li', count: 2)
119
+ expect(last_response.body).to have_tag('p', text: /2 files/)
120
120
  end
121
121
 
122
- end
123
-
124
- context "given a list of files" do
125
-
126
- before {
127
- file_list = mock()
128
- file_list.stubs(:files).returns(["file1", "file2"])
129
- file_list.stubs(:file_count).returns(2)
130
- Ferver::FileList.stubs(:new).returns(file_list)
131
- }
132
-
133
- context "when no content-type is requested" do
134
-
135
- before { get "/files" }
136
-
137
- it "should return valid response" do
138
- expect(last_response).to be_ok
139
- #todo test html
140
- end
141
-
142
- it "should contain no file list in response content" do
143
- expect(last_response.body).to have_selector("li", :count => 2)
144
- expect(last_response.body).to contain(/2 files/)
145
- end
146
-
147
- it "should list filenames" do
148
- expect(last_response.body).to have_selector("li") do |node|
149
-
150
- expect(node.first).to have_selector("a", :content => "file1")
151
- expect(node.last).to have_selector("a", :content => "file2")
152
-
153
- end
154
- end
155
-
122
+ it 'should list filenames' do
123
+ expect(last_response.body).to have_tag('li') do
124
+ with_tag('a', text: 'file1')
125
+ with_tag('a', text: 'file2')
126
+ end
156
127
  end
128
+ end
157
129
 
158
- context "when json content-type is requested" do
159
-
160
- before {
161
- get "/files", {}, {"HTTP_ACCEPT" => "application/json" }
162
- }
163
-
164
- it "should return valid response" do
165
- expect(last_response).to be_ok
166
- expect(last_response.content_type).to include("application/json")
167
- end
168
-
169
- it "should contain no file list in response content" do
170
- list = JSON.parse last_response.body
171
- expect(list.count).to eq(2)
172
- expect(list).to match_array(["file1", "file2"])
173
- end
130
+ context 'when json content-type is requested' do
131
+ before do
132
+ get '/files', {}, 'HTTP_ACCEPT' => 'application/json'
133
+ end
174
134
 
135
+ it 'should return valid response' do
136
+ expect(last_response).to be_ok
137
+ expect(last_response.content_type).to include('application/json')
175
138
  end
176
139
 
140
+ it 'should contain no file list in response content' do
141
+ list = JSON.parse last_response.body
142
+ expect(list.count).to eq(2)
143
+ expect(list).to match_array(%w(file1 file2))
144
+ end
145
+ end
177
146
  end
178
147
 
148
+ describe 'downloading a file' do
179
149
 
180
- describe "downloading a file" do
181
-
182
- before {
183
- @file_list = mock()
184
- @file_list.stubs(:files).returns(["file1", "file2"])
185
- @file_list.stubs(:file_count).returns(2)
186
- Ferver::FileList.stubs(:new).returns(@file_list)
187
- }
188
-
189
- context "when requesting a file out of range" do
190
-
191
- before {
192
- @file_list.expects(:file_id_is_valid?).with(3).returns(false)
193
- get "/files/3"
194
- }
195
-
196
- it "should return not_found" do
197
- expect(last_response).to be_not_found
198
- end
199
-
150
+ context 'when requesting a file out of range' do
151
+ before do
152
+ allow(file_list).to receive(:file_id_is_valid?).with(3).and_return(false)
153
+ get '/files/3'
200
154
  end
201
155
 
202
- context "when requesting invalid file id" do
203
-
204
- before {
205
- @file_list.expects(:file_id_is_valid?).never
206
- get "/files/foo"
207
- }
208
-
209
- it "should return not_found" do
210
- expect(last_response).to be_bad_request
211
- end
212
-
156
+ it 'should return not_found' do
157
+ expect(last_response).to be_not_found
213
158
  end
159
+ end
214
160
 
215
- context "when requesting a valid file id" do
161
+ context 'when requesting invalid file id' do
162
+ before { get '/files/foo' }
216
163
 
217
- before { get "/files/0" }
164
+ it 'should return not_found' do
165
+ expect(last_response).to be_bad_request
166
+ end
167
+ end
218
168
 
219
- xit "should return ok response" do
220
- expect(last_response).to be_ok
221
- end
169
+ context 'when requesting a valid file id' do
170
+ before { get '/files/0' }
222
171
 
223
- xit "should return octet-stream content-type" do
224
- expect(last_response.headers['Content-Type']).to eq("application/octet-stream")
225
- end
172
+ xit 'should return ok response' do
173
+ expect(last_response).to be_ok
174
+ end
226
175
 
176
+ xit 'should return octet-stream content-type' do
177
+ expect(last_response.headers['Content-Type']).to eq('application/octet-stream')
227
178
  end
228
179
 
180
+ end
229
181
  end
230
-
231
- end
182
+ end
183
+ end