rack-combobot 0.0.3 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile.lock +2 -2
- data/Guardfile +2 -3
- data/Rakefile +1 -1
- data/config.ru +6 -0
- data/lib/rack/combobot/combination.rb +33 -0
- data/lib/rack/combobot.rb +19 -31
- data/rack-combobot.gemspec +1 -1
- data/spec/lib/rack/combobot/combination_spec.rb +41 -0
- data/spec/lib/rack/combobot_spec.rb +49 -0
- metadata +20 -16
- data/spec/rack_combobot_spec.rb +0 -50
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
rack-combobot (0.0.
|
4
|
+
rack-combobot (0.0.3)
|
5
5
|
rack
|
6
6
|
rake
|
7
7
|
|
@@ -12,7 +12,7 @@ GEM
|
|
12
12
|
guard (0.10.0)
|
13
13
|
ffi (>= 0.5.0)
|
14
14
|
thor (~> 0.14.6)
|
15
|
-
guard-minitest (0.
|
15
|
+
guard-minitest (0.5.0)
|
16
16
|
guard (~> 0.4)
|
17
17
|
minitest (2.10.0)
|
18
18
|
rack (1.4.0)
|
data/Guardfile
CHANGED
@@ -1,6 +1,5 @@
|
|
1
1
|
guard 'minitest' do
|
2
2
|
watch(%r|^spec/(.*)_spec\.rb|)
|
3
|
-
watch(%r|^lib/(.*)\.rb|)
|
4
|
-
watch(%r|^
|
5
|
-
watch(%r|^spec/spec_helper\.rb|) { "spec" }
|
3
|
+
watch(%r|^lib/(.*)\.rb|) { |m| "spec/#{m[1]}_spec.rb" }
|
4
|
+
watch(%r|^spec/spec_helper\.rb|) { "spec" }
|
6
5
|
end
|
data/Rakefile
CHANGED
data/config.ru
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
module Rack
|
4
|
+
class Combobot
|
5
|
+
class Combination
|
6
|
+
def initialize(root, file_names)
|
7
|
+
@root = root
|
8
|
+
|
9
|
+
@file_contents = fetch_file_contents file_names if file_names
|
10
|
+
end
|
11
|
+
|
12
|
+
def fetch_file_contents(file_names = [])
|
13
|
+
file_names.map do |file_name|
|
14
|
+
|
15
|
+
raise PathError if file_name.include?('..') || file_name.include?("~")
|
16
|
+
|
17
|
+
root_prefix = ::File.expand_path(".", @root) + "/"
|
18
|
+
file_path = ::File.expand_path(file_name, @root)
|
19
|
+
|
20
|
+
raise PathError unless file_path.start_with?(root_prefix) && ::File.exist?(file_path)
|
21
|
+
|
22
|
+
file_content = ::File.open(file_path, 'r') { |f| f.read }
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def combine
|
27
|
+
@combo ||= @file_contents.join
|
28
|
+
end
|
29
|
+
|
30
|
+
class PathError < ArgumentError; end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
data/lib/rack/combobot.rb
CHANGED
@@ -1,32 +1,45 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
1
3
|
require "rack/combobot/config"
|
4
|
+
require "rack/combobot/combination"
|
2
5
|
require "pathname"
|
3
6
|
require "uri"
|
4
7
|
|
5
8
|
module Rack
|
6
9
|
class Combobot
|
7
|
-
def self.configure(*args)
|
8
|
-
new(*args)
|
9
|
-
end
|
10
10
|
|
11
11
|
MIME_TYPES = {
|
12
12
|
"js" => "text/javascript",
|
13
13
|
"css" => "text/css"
|
14
14
|
}
|
15
15
|
|
16
|
-
def initialize(options = {})
|
16
|
+
def initialize(app, options = {})
|
17
|
+
@app = app
|
18
|
+
|
17
19
|
root = Pathname.new(options[:root] || Dir.pwd)
|
18
20
|
@config = Rack::Combobot::Config.new(root)
|
19
21
|
end
|
20
22
|
|
21
23
|
# rack request handler
|
22
24
|
def call(env)
|
25
|
+
if Rack::Request.new(env).path == '/combobot'
|
26
|
+
combine(env)
|
27
|
+
else
|
28
|
+
@app.call(env)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def combine(env)
|
23
33
|
params = env["QUERY_STRING"]
|
24
34
|
file_names = params.split("&")
|
25
|
-
|
35
|
+
|
36
|
+
return not_found if file_names.empty?
|
37
|
+
|
38
|
+
extension = file_names[0].split(".").last
|
26
39
|
|
27
40
|
begin
|
28
41
|
combo = Combination.new(@config.root, file_names).combine
|
29
|
-
[200, {"Content-Type" => MIME_TYPES[
|
42
|
+
[200, {"Content-Type" => MIME_TYPES[extension]}, [combo]]
|
30
43
|
rescue Combination::PathError
|
31
44
|
not_found
|
32
45
|
end
|
@@ -36,30 +49,5 @@ module Rack
|
|
36
49
|
[404, {'Content-Type' => 'text/html'}, ['File not found']]
|
37
50
|
end
|
38
51
|
|
39
|
-
class Combination
|
40
|
-
def initialize(root, file_names)
|
41
|
-
@file_contents = combine_files(root, file_names)
|
42
|
-
end
|
43
|
-
|
44
|
-
def combine_files(root, file_names = [])
|
45
|
-
file_names.map do |file_name|
|
46
|
-
|
47
|
-
raise PathError if file_name.include?('..') || file_name.include?("~")
|
48
|
-
|
49
|
-
root_prefix = ::File.expand_path(".", root) + "/"
|
50
|
-
file_path = ::File.expand_path(file_name, root)
|
51
|
-
|
52
|
-
raise PathError unless file_path.start_with?(root_prefix) && ::File.exist?(file_path)
|
53
|
-
|
54
|
-
file_content = ::File.open(file_path, 'r') { |f| f.read }
|
55
|
-
end
|
56
|
-
end
|
57
|
-
|
58
|
-
def combine
|
59
|
-
@combo ||= @file_contents.join
|
60
|
-
end
|
61
|
-
|
62
|
-
class PathError < ArgumentError; end
|
63
|
-
end
|
64
52
|
end
|
65
53
|
end
|
data/rack-combobot.gemspec
CHANGED
@@ -4,7 +4,7 @@ $:.push File.expand_path("../lib", __FILE__)
|
|
4
4
|
|
5
5
|
Gem::Specification.new do |s|
|
6
6
|
s.name = "rack-combobot"
|
7
|
-
s.version = "0.0
|
7
|
+
s.version = "0.1.0"
|
8
8
|
s.authors = ["Simon Højberg", "Christopher Meiklejohn"]
|
9
9
|
s.email = ["r.hackr@gmail.com", "christopher.meiklejohn@gmail.com"]
|
10
10
|
s.homepage = "https://github.com/hojberg/rack-combobot"
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../../../spec_helper'
|
2
|
+
|
3
|
+
describe Rack::Combobot::Combination do
|
4
|
+
|
5
|
+
let(:combination) { Rack::Combobot::Combination.new(File.dirname(__FILE__) + '/../../../public', ['js1.js', 'js2.js']) }
|
6
|
+
|
7
|
+
describe 'fetch' do
|
8
|
+
|
9
|
+
it 'fetches files content' do
|
10
|
+
contents = combination.fetch_file_contents(['js1.js', 'js2.js'])
|
11
|
+
contents.must_equal(["function lorem() { return \"a\"; }\n", "function ipsum() { return \"b\"; }\n"])
|
12
|
+
end
|
13
|
+
|
14
|
+
describe 'error handling' do
|
15
|
+
it 'raises PathError when files are not found' do
|
16
|
+
proc {
|
17
|
+
combination.fetch_file_contents(['js3.js'])
|
18
|
+
}.must_raise Rack::Combobot::Combination::PathError
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'raises PathError when trying to move outside the root' do
|
22
|
+
proc {
|
23
|
+
combination.fetch_file_contents(['js1.js', '../../etc/hosts'])
|
24
|
+
}.must_raise Rack::Combobot::Combination::PathError
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
describe 'combination' do
|
30
|
+
|
31
|
+
before do
|
32
|
+
combination.fetch_file_contents(['js1.js', 'js2.js'])
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'combines file content' do
|
36
|
+
combination.combine.must_equal("function lorem() { return \"a\"; }\nfunction ipsum() { return \"b\"; }\n")
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../../spec_helper'
|
2
|
+
|
3
|
+
describe Rack::Combobot do
|
4
|
+
include Rack::Test::Methods
|
5
|
+
|
6
|
+
# the dummy app represents any other middleware in the rack stack
|
7
|
+
let(:dummy_app_response) { [200, {"Content-Type" => "text/html"}, ["Dummy App"]] }
|
8
|
+
let(:dummy_app) { Proc.new {|env| dummy_app_response } }
|
9
|
+
|
10
|
+
before do
|
11
|
+
@app = Rack::Combobot.new(dummy_app, :root => File.dirname(__FILE__) + '/../../public')
|
12
|
+
end
|
13
|
+
|
14
|
+
describe 'routing' do
|
15
|
+
|
16
|
+
# request helpers
|
17
|
+
let(:combobot_request) { { 'PATH_INFO' => '/combobot' } }
|
18
|
+
let(:combobot_js_request) { combobot_request.merge({ "QUERY_STRING" => "js1.js&js2.js" }) }
|
19
|
+
let(:combobot_css_request) { combobot_request.merge({ "QUERY_STRING" => "css1.css&css2.css" }) }
|
20
|
+
let(:combobot_404_request) { combobot_request.merge({ "QUERY_STRING" => "js3.js&js4.js" }) }
|
21
|
+
let(:combobot_hack_request) { combobot_request.merge({ "QUERY_STRING" => "js3.js&../../js4.js" }) }
|
22
|
+
|
23
|
+
# response helpers
|
24
|
+
let(:combobot_js_response) { [200, {"Content-Type" => "text/javascript"}, ["function lorem() { return \"a\"; }\nfunction ipsum() { return \"b\"; }\n"]] }
|
25
|
+
let(:combobot_css_response) { [200, {"Content-Type" => "text/css"}, [".lorem { background: blue; }\n#lipsum { border: 1px solid red }\n"]] }
|
26
|
+
let(:combobot_404_response) { [404, {'Content-Type' => 'text/html'}, ['File not found']] }
|
27
|
+
|
28
|
+
it 'should not respond to anything other than "/combobot"' do
|
29
|
+
@app.call({}).must_equal(dummy_app_response)
|
30
|
+
end
|
31
|
+
|
32
|
+
it "combines javascript" do
|
33
|
+
@app.call(combobot_js_request).must_equal(combobot_js_response)
|
34
|
+
end
|
35
|
+
|
36
|
+
it "combines css" do
|
37
|
+
@app.call(combobot_css_request).must_equal(combobot_css_response)
|
38
|
+
end
|
39
|
+
|
40
|
+
it "returns 404 when it can't find files" do
|
41
|
+
@app.call(combobot_404_request).must_equal(combobot_404_response)
|
42
|
+
end
|
43
|
+
|
44
|
+
it 'returns 404 when trying to move up from the root dir' do
|
45
|
+
@app.call(combobot_hack_request).must_equal(combobot_404_response)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rack-combobot
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 0.1.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -10,11 +10,11 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date: 2012-03-
|
13
|
+
date: 2012-03-14 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: rake
|
17
|
-
requirement: &
|
17
|
+
requirement: &2153707180 !ruby/object:Gem::Requirement
|
18
18
|
none: false
|
19
19
|
requirements:
|
20
20
|
- - ! '>='
|
@@ -22,10 +22,10 @@ dependencies:
|
|
22
22
|
version: '0'
|
23
23
|
type: :runtime
|
24
24
|
prerelease: false
|
25
|
-
version_requirements: *
|
25
|
+
version_requirements: *2153707180
|
26
26
|
- !ruby/object:Gem::Dependency
|
27
27
|
name: rack
|
28
|
-
requirement: &
|
28
|
+
requirement: &2153706740 !ruby/object:Gem::Requirement
|
29
29
|
none: false
|
30
30
|
requirements:
|
31
31
|
- - ! '>='
|
@@ -33,10 +33,10 @@ dependencies:
|
|
33
33
|
version: '0'
|
34
34
|
type: :runtime
|
35
35
|
prerelease: false
|
36
|
-
version_requirements: *
|
36
|
+
version_requirements: *2153706740
|
37
37
|
- !ruby/object:Gem::Dependency
|
38
38
|
name: minitest
|
39
|
-
requirement: &
|
39
|
+
requirement: &2153706320 !ruby/object:Gem::Requirement
|
40
40
|
none: false
|
41
41
|
requirements:
|
42
42
|
- - ! '>='
|
@@ -44,10 +44,10 @@ dependencies:
|
|
44
44
|
version: '0'
|
45
45
|
type: :development
|
46
46
|
prerelease: false
|
47
|
-
version_requirements: *
|
47
|
+
version_requirements: *2153706320
|
48
48
|
- !ruby/object:Gem::Dependency
|
49
49
|
name: rack-test
|
50
|
-
requirement: &
|
50
|
+
requirement: &2153705900 !ruby/object:Gem::Requirement
|
51
51
|
none: false
|
52
52
|
requirements:
|
53
53
|
- - ! '>='
|
@@ -55,10 +55,10 @@ dependencies:
|
|
55
55
|
version: '0'
|
56
56
|
type: :development
|
57
57
|
prerelease: false
|
58
|
-
version_requirements: *
|
58
|
+
version_requirements: *2153705900
|
59
59
|
- !ruby/object:Gem::Dependency
|
60
60
|
name: guard
|
61
|
-
requirement: &
|
61
|
+
requirement: &2153705480 !ruby/object:Gem::Requirement
|
62
62
|
none: false
|
63
63
|
requirements:
|
64
64
|
- - ! '>='
|
@@ -66,10 +66,10 @@ dependencies:
|
|
66
66
|
version: '0'
|
67
67
|
type: :development
|
68
68
|
prerelease: false
|
69
|
-
version_requirements: *
|
69
|
+
version_requirements: *2153705480
|
70
70
|
- !ruby/object:Gem::Dependency
|
71
71
|
name: guard-minitest
|
72
|
-
requirement: &
|
72
|
+
requirement: &2153705060 !ruby/object:Gem::Requirement
|
73
73
|
none: false
|
74
74
|
requirements:
|
75
75
|
- - ! '>='
|
@@ -77,7 +77,7 @@ dependencies:
|
|
77
77
|
version: '0'
|
78
78
|
type: :development
|
79
79
|
prerelease: false
|
80
|
-
version_requirements: *
|
80
|
+
version_requirements: *2153705060
|
81
81
|
description: combines assets to server 1 file
|
82
82
|
email:
|
83
83
|
- r.hackr@gmail.com
|
@@ -94,15 +94,18 @@ files:
|
|
94
94
|
- Guardfile
|
95
95
|
- README.md
|
96
96
|
- Rakefile
|
97
|
+
- config.ru
|
97
98
|
- lib/rack-combobot.rb
|
98
99
|
- lib/rack/combobot.rb
|
100
|
+
- lib/rack/combobot/combination.rb
|
99
101
|
- lib/rack/combobot/config.rb
|
100
102
|
- rack-combobot.gemspec
|
103
|
+
- spec/lib/rack/combobot/combination_spec.rb
|
104
|
+
- spec/lib/rack/combobot_spec.rb
|
101
105
|
- spec/public/css1.css
|
102
106
|
- spec/public/css2.css
|
103
107
|
- spec/public/js1.js
|
104
108
|
- spec/public/js2.js
|
105
|
-
- spec/rack_combobot_spec.rb
|
106
109
|
- spec/spec_helper.rb
|
107
110
|
homepage: https://github.com/hojberg/rack-combobot
|
108
111
|
licenses: []
|
@@ -129,9 +132,10 @@ signing_key:
|
|
129
132
|
specification_version: 3
|
130
133
|
summary: asset combinator
|
131
134
|
test_files:
|
135
|
+
- spec/lib/rack/combobot/combination_spec.rb
|
136
|
+
- spec/lib/rack/combobot_spec.rb
|
132
137
|
- spec/public/css1.css
|
133
138
|
- spec/public/css2.css
|
134
139
|
- spec/public/js1.js
|
135
140
|
- spec/public/js2.js
|
136
|
-
- spec/rack_combobot_spec.rb
|
137
141
|
- spec/spec_helper.rb
|
data/spec/rack_combobot_spec.rb
DELETED
@@ -1,50 +0,0 @@
|
|
1
|
-
require File.dirname(__FILE__) + '/spec_helper'
|
2
|
-
|
3
|
-
describe "combing assets from query string" do
|
4
|
-
include Rack::Test::Methods
|
5
|
-
|
6
|
-
before(:each) do
|
7
|
-
@app = Rack::Combobot.configure(:root => File.dirname(__FILE__) + '/public')
|
8
|
-
end
|
9
|
-
|
10
|
-
it "combines javascript" do
|
11
|
-
@app.call({
|
12
|
-
"QUERY_STRING" => "js1.js&js2.js"
|
13
|
-
}).must_equal([
|
14
|
-
200,
|
15
|
-
{"Content-Type" => "text/javascript"},
|
16
|
-
["function lorem() { return \"a\"; }\nfunction ipsum() { return \"b\"; }\n"]
|
17
|
-
])
|
18
|
-
end
|
19
|
-
|
20
|
-
it "combines css" do
|
21
|
-
@app.call({
|
22
|
-
"QUERY_STRING" => "css1.css&css2.css"
|
23
|
-
}).must_equal([
|
24
|
-
200,
|
25
|
-
{"Content-Type" => "text/css"},
|
26
|
-
[".lorem { background: blue; }\n#lipsum { border: 1px solid red }\n"]
|
27
|
-
])
|
28
|
-
end
|
29
|
-
|
30
|
-
it "returns 404 when it can't find files" do
|
31
|
-
@app.call({
|
32
|
-
"QUERY_STRING" => "js3.js&js4.js"
|
33
|
-
}).must_equal([
|
34
|
-
404,
|
35
|
-
{'Content-Type' => 'text/html'},
|
36
|
-
['File not found']
|
37
|
-
])
|
38
|
-
end
|
39
|
-
|
40
|
-
it 'returns 404 when trying to move up from the root dir' do
|
41
|
-
@app.call({
|
42
|
-
"QUERY_STRING" => "js3.js&../../js4.js"
|
43
|
-
}).must_equal([
|
44
|
-
404,
|
45
|
-
{'Content-Type' => 'text/html'},
|
46
|
-
['File not found']
|
47
|
-
])
|
48
|
-
end
|
49
|
-
|
50
|
-
end
|