hyperloop 0.0.3 → 0.0.4

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.
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