hyperloop 0.0.3 → 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 2dfb955d1503bb9133c9c4f83c7813a1a65a1f41
4
- data.tar.gz: 9321f9d51755fbeef6ef2bd694c3a129d273cbe4
3
+ metadata.gz: 29a3801566158ad7b51ebbdaf45cb6ca6e67ae84
4
+ data.tar.gz: 38ec4004a3ed61d574f1e66e6183c6079e0e9272
5
5
  SHA512:
6
- metadata.gz: 9c03dd0d3a042535c644e6db73be972d79783f92ed9a1231889050f3e086693aadb59d0b25716289646ba982737c2d0684c9dd1549993ca27edf4c42c10e9e94
7
- data.tar.gz: f97317e18c1b3aa65243650b00d18fd235252799d6b740c5af0f409168e7f12e0bc98683f7424f9cd73bf76f2d0abb02dcb0081bc0b3cea2af64a26cf1e53d5c
6
+ metadata.gz: 3e1539c80d4e01aedd6b6a41cd0feb1def272cff39d8635225b0230b03b5f93373986d4063ec2390c2746e9c884541a7cd968cb7671e054189f794aa315f9885
7
+ data.tar.gz: 283808d56433d7a843af9de630a15752ca8c14613e957306aa346cb0d8aa550755b1c45ee678857b7413fbea7f4c3aaedb2b781addb7b9b3934321299728ed38
@@ -7,8 +7,7 @@ module Hyperloop
7
7
  include Rack::Utils
8
8
 
9
9
  def initialize(root=nil)
10
- @root = root
11
- @view_registry = View::Registry.new(@root)
10
+ @root = root
12
11
  end
13
12
 
14
13
  # Rack call interface.
@@ -21,7 +20,7 @@ module Hyperloop
21
20
  # as the response body.
22
21
  response["Content-Type"] = asset.content_type
23
22
  response.write(asset.source)
24
- elsif view = @view_registry.find_template_view(normalized_request_path(request.path))
23
+ elsif view = view_registry.find_template_view(normalized_request_path(request.path))
25
24
  # If there's a view at the path, use its data as the response body.
26
25
  data = view.render(request)
27
26
  response.write(data)
@@ -48,12 +47,16 @@ module Hyperloop
48
47
  #
49
48
  # Returns a Sprockets::Environment.
50
49
  def assets
51
- @assets ||= Sprockets::Environment.new do |env|
52
- env.append_path(File.join(@root, "app", "assets"))
53
- env.append_path(File.join(@root, "vendor", "assets"))
50
+ @assets = nil unless production?
51
+
52
+ @assets ||= Sprockets::Environment.new(@root) do |env|
53
+ env.version = ENV["RACK_ENV"]
54
+
55
+ env.append_path(File.join("app", "assets"))
56
+ env.append_path(File.join("vendor", "assets"))
54
57
 
55
58
  # compress everything in production
56
- if ENV["RACK_ENV"] == "production"
59
+ if production?
57
60
  env.js_compressor = YUI::JavaScriptCompressor.new(:munge => true)
58
61
  env.css_compressor = YUI::CssCompressor.new
59
62
  end
@@ -81,5 +84,20 @@ module Hyperloop
81
84
  path.chomp("/")
82
85
  end
83
86
  end
87
+
88
+ # Internal: Are we running in production mode?
89
+ #
90
+ # Returns a boolean.
91
+ def production?
92
+ ENV["RACK_ENV"] == "production"
93
+ end
94
+
95
+ # Internal: The view registry to use for the app.
96
+ #
97
+ # Returns a Hyperloop::View::Registry
98
+ def view_registry
99
+ @view_registry = nil unless production?
100
+ @view_registry ||= View::Registry.new(@root)
101
+ end
84
102
  end
85
103
  end
@@ -1,3 +1,3 @@
1
1
  module Hyperloop
2
- VERSION = "0.0.3"
2
+ VERSION = "0.0.4"
3
3
  end
@@ -3,12 +3,11 @@ require File.expand_path("../spec_helper", __FILE__)
3
3
  describe Hyperloop::Application do
4
4
  describe "with a flat views directory" do
5
5
  before :each do
6
- @app = Hyperloop::Application.new("spec/fixtures/simple/")
7
- @request = Rack::MockRequest.new(@app)
6
+ @app = Hyperloop::Application.new(prepare_fixture(:simple))
8
7
  end
9
8
 
10
9
  it "responds successfully to a request for root" do
11
- response = @request.get("/")
10
+ response = mock_request(@app).get("/")
12
11
 
13
12
  expect(response).to be_ok
14
13
  expect(response.content_type).to eql("text/html")
@@ -16,21 +15,21 @@ describe Hyperloop::Application do
16
15
  end
17
16
 
18
17
  it "responds successfully to a request for a different page" do
19
- response = @request.get("/about")
18
+ response = mock_request(@app).get("/about")
20
19
 
21
20
  expect(response).to be_ok
22
21
  expect(text_in(response.body, "h1")).to eql("About")
23
22
  end
24
23
 
25
24
  it "responds successfully to a request with a trailing slash" do
26
- response = @request.get("/about/")
25
+ response = mock_request(@app).get("/about/")
27
26
 
28
27
  expect(response).to be_ok
29
28
  expect(text_in(response.body, "h1")).to eql("About")
30
29
  end
31
30
 
32
31
  it "404s on a request for a nonexistent page" do
33
- response = @request.get("/nonexistent")
32
+ response = mock_request(@app).get("/nonexistent")
34
33
 
35
34
  expect(response).to be_not_found
36
35
  end
@@ -38,19 +37,18 @@ describe Hyperloop::Application do
38
37
 
39
38
  describe "with subdirectories" do
40
39
  before :each do
41
- @app = Hyperloop::Application.new("spec/fixtures/subdirectories/")
42
- @request = Rack::MockRequest.new(@app)
40
+ @app = Hyperloop::Application.new(prepare_fixture(:subdirectories))
43
41
  end
44
42
 
45
43
  it "responds successfully to a request for the subdirectory root" do
46
- response = @request.get("/subdir1")
44
+ response = mock_request(@app).get("/subdir1")
47
45
 
48
46
  expect(response).to be_ok
49
47
  expect(text_in(response.body, "h1")).to eql("Subdirectory Index")
50
48
  end
51
49
 
52
50
  it "responds successfully to a request for a different page in the subdirectory" do
53
- response = @request.get("/subdir1/kanye")
51
+ response = mock_request(@app).get("/subdir1/kanye")
54
52
 
55
53
  expect(response).to be_ok
56
54
  expect(text_in(response.body, "h1")).to eql("Hurry up with my damn croissant")
@@ -59,12 +57,11 @@ describe Hyperloop::Application do
59
57
 
60
58
  describe "with ERB" do
61
59
  before :each do
62
- @app = Hyperloop::Application.new("spec/fixtures/erb/")
63
- @request = Rack::MockRequest.new(@app)
60
+ @app = Hyperloop::Application.new(prepare_fixture(:erb))
64
61
  end
65
62
 
66
63
  it "renders embedded Ruby in the root page" do
67
- response = @request.get("/")
64
+ response = mock_request(@app).get("/")
68
65
 
69
66
  expect(response).to be_ok
70
67
  expect(text_in(response.body, "h1")).to eql("WE ARE USING ERB")
@@ -73,12 +70,11 @@ describe Hyperloop::Application do
73
70
 
74
71
  describe "with a layout" do
75
72
  before :each do
76
- @app = Hyperloop::Application.new("spec/fixtures/layouts/")
77
- @request = Rack::MockRequest.new(@app)
73
+ @app = Hyperloop::Application.new(prepare_fixture(:layouts))
78
74
  end
79
75
 
80
76
  it "renders the root view within the layout" do
81
- response = @request.get("/")
77
+ response = mock_request(@app).get("/")
82
78
 
83
79
  expect(response).to be_ok
84
80
  expect(text_in(response.body, "h1")).to eql("Layout Header")
@@ -86,7 +82,7 @@ describe Hyperloop::Application do
86
82
  end
87
83
 
88
84
  it "renders subdirectory views within the layout" do
89
- response = @request.get("/subdir")
85
+ response = mock_request(@app).get("/subdir")
90
86
 
91
87
  expect(response).to be_ok
92
88
  expect(text_in(response.body, "h1")).to eql("Layout Header")
@@ -96,19 +92,18 @@ describe Hyperloop::Application do
96
92
 
97
93
  describe "with assets" do
98
94
  before :each do
99
- @app = Hyperloop::Application.new("spec/fixtures/assets/")
100
- @request = Rack::MockRequest.new(@app)
95
+ @app = Hyperloop::Application.new(prepare_fixture(:assets))
101
96
  end
102
97
 
103
98
  it "responds successfully to a request for root" do
104
- response = @request.get("/")
99
+ response = mock_request(@app).get("/")
105
100
 
106
101
  expect(response).to be_ok
107
102
  expect(text_in(response.body, "h1")).to eql("This app has so many assets")
108
103
  end
109
104
 
110
105
  it "responds successfully to a request for the css app bundle" do
111
- response = @request.get("/assets/stylesheets/app.css")
106
+ response = mock_request(@app).get("/assets/stylesheets/app.css")
112
107
 
113
108
  expect(response).to be_ok
114
109
  expect(response.content_type).to eql("text/css")
@@ -116,7 +111,7 @@ describe Hyperloop::Application do
116
111
  end
117
112
 
118
113
  it "responds successfully to a request for the javascript app bundle" do
119
- response = @request.get("/assets/javascripts/app.js")
114
+ response = mock_request(@app).get("/assets/javascripts/app.js")
120
115
 
121
116
  expect(response).to be_ok
122
117
  expect(response.content_type).to eql("application/javascript")
@@ -124,7 +119,7 @@ describe Hyperloop::Application do
124
119
  end
125
120
 
126
121
  it "responds successfully to a request for a vendored css file" do
127
- response = @request.get("/assets/stylesheets/vendored.css")
122
+ response = mock_request(@app).get("/assets/stylesheets/vendored.css")
128
123
 
129
124
  expect(response).to be_ok
130
125
  expect(response.content_type).to eql("text/css")
@@ -132,7 +127,7 @@ describe Hyperloop::Application do
132
127
  end
133
128
 
134
129
  it "responds successfully to a request for a vendored javascript bundle" do
135
- response = @request.get("/assets/javascripts/vendored.js")
130
+ response = mock_request(@app).get("/assets/javascripts/vendored.js")
136
131
 
137
132
  expect(response).to be_ok
138
133
  expect(response.content_type).to eql("application/javascript")
@@ -140,7 +135,7 @@ describe Hyperloop::Application do
140
135
  end
141
136
 
142
137
  it "responds successfully to a request for a gif" do
143
- response = @request.get("/assets/images/my-gif.gif")
138
+ response = mock_request(@app).get("/assets/images/my-gif.gif")
144
139
 
145
140
  expect(response).to be_ok
146
141
  expect(response.content_type).to eql("image/gif")
@@ -148,7 +143,7 @@ describe Hyperloop::Application do
148
143
  end
149
144
 
150
145
  it "responds successfully to a request for a jpg" do
151
- response = @request.get("/assets/images/my-jpg.jpg")
146
+ response = mock_request(@app).get("/assets/images/my-jpg.jpg")
152
147
 
153
148
  expect(response).to be_ok
154
149
  expect(response.content_type).to eql("image/jpeg")
@@ -156,7 +151,7 @@ describe Hyperloop::Application do
156
151
  end
157
152
 
158
153
  it "responds successfully to a request for a png" do
159
- response = @request.get("/assets/images/my-png.png")
154
+ response = mock_request(@app).get("/assets/images/my-png.png")
160
155
 
161
156
  expect(response).to be_ok
162
157
  expect(response.content_type).to eql("image/png")
@@ -164,24 +159,142 @@ describe Hyperloop::Application do
164
159
  end
165
160
 
166
161
  it "404s on a request for an asset without namespacing by type" do
167
- response = @request.get("/assets/app.js")
162
+ response = mock_request(@app).get("/assets/app.js")
168
163
  expect(response).to be_not_found
169
164
  end
170
165
 
171
166
  it "404s on a request for an asset namespaced by the wrong type" do
172
- response = @request.get("/assets/stylesheets/app.js")
167
+ response = mock_request(@app).get("/assets/stylesheets/app.js")
173
168
  expect(response).to be_not_found
174
169
  end
175
170
 
176
171
  it "404s on a request for an asset namespaced by an unknown type" do
177
- response = @request.get("/assets/shouldfail/shouldfail.css")
172
+ response = mock_request(@app).get("/assets/shouldfail/shouldfail.css")
178
173
  expect(response).to be_not_found
179
174
  end
180
175
 
181
176
  it "404s on a request for a nonexistent asset" do
182
- response = @request.get("/assets/javascripts/nonexistent.js")
177
+ response = mock_request(@app).get("/assets/javascripts/nonexistent.js")
183
178
 
184
179
  expect(response).to be_not_found
185
180
  end
186
181
  end
182
+
183
+ describe "live reloading" do
184
+ context "with assets" do
185
+ before :each do
186
+ @root = prepare_fixture(:assets)
187
+ @app = Hyperloop::Application.new(@root)
188
+ end
189
+
190
+ it "reloads changed assets" do
191
+ # On the first request, stylesheet should have `display: block` and not
192
+ # `display: inline`.
193
+ response = mock_request(@app).get("/assets/stylesheets/app.css")
194
+ expect(response).to be_ok
195
+ expect(response.body).to match(/display: ?block/)
196
+ expect(response.body).not_to match(/display: ?inline/)
197
+
198
+ change_fixture(@root, "app/assets/stylesheets/my-styles.scss",
199
+ :pattern => "display: block",
200
+ :replacement => "display: inline"
201
+ )
202
+
203
+ # On the second request, stylesheet should have `display: inline` and not
204
+ # `display: block`.
205
+ response = mock_request(@app).get("/assets/stylesheets/app.css")
206
+ expect(response).to be_ok
207
+ expect(response.body).to match(/display: ?inline/)
208
+ expect(response.body).not_to match(/display: ?block/)
209
+ end
210
+ end
211
+
212
+ context "with views" do
213
+ before :each do
214
+ @root = prepare_fixture(:partials)
215
+ @app = Hyperloop::Application.new(@root)
216
+ end
217
+
218
+ it "reloads changed layouts" do
219
+ # On the first request, <title> text should not be "Changed"
220
+ response = mock_request(@app).get("/")
221
+ expect(response).to be_ok
222
+ expect(text_in(response.body, "title")).not_to eql("Changed")
223
+
224
+ change_fixture(@root, "app/views/layouts/application.html.erb",
225
+ :pattern => /<title>[^<]*<\/title>/,
226
+ :replacement => "<title>Changed</title>"
227
+ )
228
+
229
+ # On the second request, <title> text should be "Changed"
230
+ response = mock_request(@app).get("/")
231
+ expect(response).to be_ok
232
+ expect(text_in(response.body, "title")).to eql("Changed")
233
+ end
234
+
235
+ it "reloads changed partials" do
236
+ # On the first request, <p> text should not be "Changed"
237
+ response = mock_request(@app).get("/")
238
+ expect(response).to be_ok
239
+ expect(text_in(response.body, "p.spec-in-partial")).not_to eql("Changed")
240
+
241
+ change_fixture(@root, "app/views/subdir/_partial.html.erb",
242
+ :pattern => /<p class="spec-in-partial">[^<]*<\/p>/,
243
+ :replacement => "<p class=\"spec-in-partial\">Changed</p>"
244
+ )
245
+
246
+ # On the second request, <p> text should be "Changed"
247
+ response = mock_request(@app).get("/")
248
+ expect(response).to be_ok
249
+ expect(text_in(response.body, "p.spec-in-partial")).to eql("Changed")
250
+ end
251
+
252
+ it "reloads changed views" do
253
+ # On the first request, <h2> text should not be "Changed"
254
+ response = mock_request(@app).get("/")
255
+ expect(response).to be_ok
256
+ expect(text_in(response.body, "h2")).not_to eql("Changed")
257
+
258
+ change_fixture(@root, "app/views/index.html.erb",
259
+ :pattern => /<h2>[^<]*<\/h2>/,
260
+ :replacement => "<h2>Changed</h2>"
261
+ )
262
+
263
+ # On the second request, <h2> text should be "Changed"
264
+ response = mock_request(@app).get("/")
265
+ expect(response).to be_ok
266
+ expect(text_in(response.body, "h2")).to eql("Changed")
267
+ end
268
+ end
269
+
270
+ context "in production" do
271
+ before :each do
272
+ set_rack_env :production
273
+ end
274
+
275
+ after :each do
276
+ reset_rack_env
277
+ end
278
+
279
+ it "doesn't reload changed views" do
280
+ root = prepare_fixture(:erb)
281
+ app = Hyperloop::Application.new(root)
282
+
283
+ # On the first request, <title> text should be "ERB"
284
+ response = mock_request(app).get("/")
285
+ expect(response).to be_ok
286
+ expect(text_in(response.body, "title")).to eql("ERB")
287
+
288
+ change_fixture(root, "app/views/index.html.erb",
289
+ :pattern => "<title>ERB</title>",
290
+ :replacement => "<title>Changed</title>"
291
+ )
292
+
293
+ # On the second request, <title> text should still be "ERB"
294
+ response = mock_request(app).get("/")
295
+ expect(response).to be_ok
296
+ expect(text_in(response.body, "title")).to eql("ERB")
297
+ end
298
+ end
299
+ end
187
300
  end
@@ -1 +1 @@
1
- <p>This is coming from a partial.</p>
1
+ <p class="spec-in-partial">This is coming from a partial.</p>
data/spec/spec_helper.rb CHANGED
@@ -4,6 +4,53 @@ require "pry"
4
4
  require "hyperloop"
5
5
 
6
6
  module Helpers
7
+ # Public: Clean up all prepared fixtures.
8
+ #
9
+ # Returns nothing.
10
+ def cleanup_fixtures
11
+ tmp_fixtures_dir = File.join("tmp", "spec", "fixtures")
12
+ FileUtils.rm_rf(tmp_fixtures_dir)
13
+ end
14
+
15
+ # Public: Change the contents of a file in a fixture.
16
+ #
17
+ # fixture_path - Path to the fixture containing the file we want to change.
18
+ # file_path - Path (relative to fixture_path) of the file we want to
19
+ # change.
20
+ # options - Hash containing the following keys:
21
+ # :pattern - (Required) Regexp or String to find in the
22
+ # file. Only the first occurrence will be
23
+ # matched.
24
+ # :replacement - (Required) String to replace the found pattern
25
+ # with.
26
+ #
27
+ # Examples:
28
+ #
29
+ # change_fixture("tmp/spec/fixtures/erb", "app/views/index.html.erb",
30
+ # :pattern => "<title>ERB</title>",
31
+ # :replacement => "<title>Changed</title>"
32
+ # )
33
+ #
34
+ # change_fixture("tmp/spec/fixtures/erb", "app/views/index.html.erb",
35
+ # :pattern => /<title>[^<]*<\/title>/,
36
+ # :replacement => "<title>Changed</title>"
37
+ # )
38
+ #
39
+ # Returns nothing.
40
+ def change_fixture(fixture_path, file_path, options = {})
41
+ pattern = options[:pattern]
42
+ replacement = options[:replacement]
43
+
44
+ raise ArgumentError, "change_fixture must include a :pattern option" unless pattern
45
+ raise ArgumentError, "change_fixture must include a :replacement option" unless replacement
46
+
47
+ File.open(File.join(fixture_path, file_path), "r+") do |f|
48
+ data = f.read.sub(pattern, replacement)
49
+ f.rewind
50
+ f.write(data)
51
+ end
52
+ end
53
+
7
54
  def html(str)
8
55
  Nokogiri::HTML(str)
9
56
  end
@@ -15,6 +62,58 @@ module Helpers
15
62
  )
16
63
  end
17
64
 
65
+ # Public: Prepare a fixture with the specified name.
66
+ #
67
+ # name - Symbol name of the fixture to prepare. The name passed here will be
68
+ # looked up in the spec/fixtures directory.
69
+ #
70
+ # Note:
71
+ #
72
+ # This method exists along with change_fixture and cleanup_fixtures. If
73
+ # these get used a lot more or more fixture-related functionality is added,
74
+ # it may make sense to extract a Fixture class and move these methods into
75
+ # it.
76
+ #
77
+ # Returns a string filepath representing the new location of the prepared
78
+ # fixture.
79
+ def prepare_fixture(name)
80
+ root = File.join("spec", "fixtures", name.to_s)
81
+ contents = File.join(root, ".")
82
+ tmp_root = File.join("tmp", root)
83
+
84
+ # Delete and recreate the tmp/spec/fixtures/:name directory, then copy the
85
+ # fixture into it.
86
+ FileUtils.rm_rf(tmp_root)
87
+ FileUtils.mkdir_p(tmp_root)
88
+ FileUtils.cp_r(contents, tmp_root)
89
+
90
+ tmp_root
91
+ end
92
+
93
+ # Public: Set the RACK_ENV environment variable back to whatever it was when
94
+ # the spec started running. If RACK_ENV wasn't set before the spec started
95
+ # running, it will be deleted.
96
+ #
97
+ # Returns nothing.
98
+ def reset_rack_env
99
+ if defined?(@old_rack_env)
100
+ ENV["RACK_ENV"] = @old_rack_env
101
+ else
102
+ ENV.delete("RACK_ENV")
103
+ end
104
+ end
105
+
106
+ # Public: Set the RACK_ENV environment variable to the specified value.
107
+ #
108
+ # name - Symbol environment name to set RACK_ENV to. Should be :development,
109
+ # :test, or :production.
110
+ #
111
+ # Returns nothing.
112
+ def set_rack_env(name)
113
+ @old_rack_env = ENV["RACK_ENV"] if ENV.key?("RACK_ENV")
114
+ ENV["RACK_ENV"] = name.to_s
115
+ end
116
+
18
117
  def text_in(html_str, selector)
19
118
  node = html(html_str).at_css(selector)
20
119
  node && node.text
@@ -24,11 +123,17 @@ module Helpers
24
123
  @mock_app ||= double("rack app", :call => Hyperloop::Response.new.finish )
25
124
  end
26
125
 
27
- def mock_request
28
- Rack::MockRequest.new(mock_app)
126
+ def mock_request(app = nil)
127
+ Rack::MockRequest.new(app || mock_app)
29
128
  end
30
129
  end
31
130
 
131
+ ENV["RACK_ENV"] ||= "test"
132
+
32
133
  RSpec.configure do |c|
33
134
  c.include(Helpers)
135
+
136
+ c.after :all do
137
+ cleanup_fixtures
138
+ end
34
139
  end
@@ -1,7 +1,7 @@
1
1
  describe Hyperloop::View::Scope do
2
2
  before :each do
3
3
  view_registry = Hyperloop::View::Registry.new("spec/fixtures/partials/")
4
- @request = Rack::MockRequest.new(mock_app)
4
+ @request = mock_request
5
5
  @scope = Hyperloop::View::Scope.new(@request, view_registry)
6
6
  end
7
7
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: hyperloop
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.3
4
+ version: 0.0.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jake Boxer
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2013-11-10 00:00:00.000000000 Z
11
+ date: 2013-11-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: coffee-script