rack-combobot 0.0.3 → 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.
- 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
|