emerson 0.1.0.pre.1 → 0.1.0.pre.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (70) hide show
  1. data/.gitignore +17 -23
  2. data/.wiprc +0 -0
  3. data/.yardopts +1 -0
  4. data/Gemfile +6 -0
  5. data/Gemfile.lock +177 -0
  6. data/Rakefile +18 -1
  7. data/emerson.gemspec +28 -15
  8. data/lib/emerson.rb +58 -1
  9. data/lib/emerson/engine.rb +5 -0
  10. data/lib/emerson/matchers.rb +5 -0
  11. data/lib/emerson/matchers/action_controller.rb +30 -0
  12. data/lib/emerson/matchers/action_controller/send_json_matcher.rb +106 -0
  13. data/lib/emerson/matchers/integrations/rspec.rb +11 -0
  14. data/lib/emerson/matchers/integrations/test_unit.rb +12 -0
  15. data/lib/emerson/responder.rb +61 -51
  16. data/lib/emerson/response.rb +17 -3
  17. data/lib/emerson/scope.rb +2 -7
  18. data/lib/emerson/version.rb +1 -1
  19. data/spec/dummy/README.rdoc +261 -0
  20. data/spec/dummy/Rakefile +7 -0
  21. data/spec/dummy/app/assets/javascripts/application.js +15 -0
  22. data/spec/dummy/app/assets/stylesheets/application.css +13 -0
  23. data/spec/dummy/app/controllers/application_controller.rb +3 -0
  24. data/spec/dummy/app/helpers/application_helper.rb +2 -0
  25. data/spec/dummy/app/mailers/.gitkeep +0 -0
  26. data/spec/dummy/app/models/.gitkeep +0 -0
  27. data/spec/dummy/app/views/layouts/application.html.erb +14 -0
  28. data/spec/dummy/config.ru +4 -0
  29. data/spec/dummy/config/application.rb +65 -0
  30. data/spec/dummy/config/boot.rb +10 -0
  31. data/spec/dummy/config/database.yml +25 -0
  32. data/spec/dummy/config/environment.rb +5 -0
  33. data/spec/dummy/config/environments/development.rb +37 -0
  34. data/spec/dummy/config/environments/production.rb +67 -0
  35. data/spec/dummy/config/environments/test.rb +37 -0
  36. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  37. data/spec/dummy/config/initializers/inflections.rb +15 -0
  38. data/spec/dummy/config/initializers/jasmine.rb +3 -0
  39. data/spec/dummy/config/initializers/mime_types.rb +5 -0
  40. data/spec/dummy/config/initializers/secret_token.rb +7 -0
  41. data/spec/dummy/config/initializers/session_store.rb +8 -0
  42. data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
  43. data/spec/dummy/config/locales/en.yml +5 -0
  44. data/spec/dummy/config/routes.rb +6 -0
  45. data/spec/dummy/lib/assets/.gitkeep +0 -0
  46. data/spec/dummy/log/.gitkeep +0 -0
  47. data/spec/dummy/public/404.html +26 -0
  48. data/spec/dummy/public/422.html +26 -0
  49. data/spec/dummy/public/500.html +25 -0
  50. data/spec/dummy/public/favicon.ico +0 -0
  51. data/spec/dummy/script/rails +6 -0
  52. data/spec/dummy/spec/support/fixtures/responses/products/extend-array.json +1 -0
  53. data/spec/dummy/spec/support/fixtures/responses/products/extend-failure.json +1 -0
  54. data/spec/dummy/spec/support/fixtures/responses/products/extend-success.json +4 -0
  55. data/spec/dummy/spec/support/fixtures/responses/products/simple.json +4 -0
  56. data/spec/emerson/matchers/action_controller/send_json_matcher_spec.rb +126 -0
  57. data/spec/emerson/responder_spec.rb +222 -0
  58. data/spec/emerson/response_spec.rb +75 -0
  59. data/spec/emerson/scope_spec.rb +146 -0
  60. data/spec/emerson_spec.rb +105 -0
  61. data/spec/spec_helper.rb +67 -0
  62. data/spec/support/helpers/controller_helpers.rb +98 -0
  63. data/spec/support/helpers/feature_helpers.rb +12 -0
  64. data/spec/support/helpers/resource_helpers.rb +95 -0
  65. data/spec/support/helpers/template_helpers.rb +31 -0
  66. data/vendor/assets/javascripts/emerson.js +1 -0
  67. data/vendor/assets/javascripts/emerson/sink.js +3 -0
  68. metadata +309 -11
  69. data/lib/emerson/rails.rb +0 -6
  70. data/lib/emerson/rails/engine.rb +0 -7
@@ -0,0 +1,26 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>The change you wanted was rejected (422)</title>
5
+ <style type="text/css">
6
+ body { background-color: #fff; color: #666; text-align: center; font-family: arial, sans-serif; }
7
+ div.dialog {
8
+ width: 25em;
9
+ padding: 0 4em;
10
+ margin: 4em auto 0 auto;
11
+ border: 1px solid #ccc;
12
+ border-right-color: #999;
13
+ border-bottom-color: #999;
14
+ }
15
+ h1 { font-size: 100%; color: #f00; line-height: 1.5em; }
16
+ </style>
17
+ </head>
18
+
19
+ <body>
20
+ <!-- This file lives in public/422.html -->
21
+ <div class="dialog">
22
+ <h1>The change you wanted was rejected.</h1>
23
+ <p>Maybe you tried to change something you didn't have access to.</p>
24
+ </div>
25
+ </body>
26
+ </html>
@@ -0,0 +1,25 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>We're sorry, but something went wrong (500)</title>
5
+ <style type="text/css">
6
+ body { background-color: #fff; color: #666; text-align: center; font-family: arial, sans-serif; }
7
+ div.dialog {
8
+ width: 25em;
9
+ padding: 0 4em;
10
+ margin: 4em auto 0 auto;
11
+ border: 1px solid #ccc;
12
+ border-right-color: #999;
13
+ border-bottom-color: #999;
14
+ }
15
+ h1 { font-size: 100%; color: #f00; line-height: 1.5em; }
16
+ </style>
17
+ </head>
18
+
19
+ <body>
20
+ <!-- This file lives in public/500.html -->
21
+ <div class="dialog">
22
+ <h1>We're sorry, but something went wrong.</h1>
23
+ </div>
24
+ </body>
25
+ </html>
File without changes
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+ # This command will automatically be run when you run "rails" with Rails 3 gems installed from the root of your application.
3
+
4
+ APP_PATH = File.expand_path('../../config/application', __FILE__)
5
+ require File.expand_path('../../config/boot', __FILE__)
6
+ require 'rails/commands'
@@ -0,0 +1 @@
1
+ { "$extends" : ["products/simple.json", "products/extend-success.json"] }
@@ -0,0 +1 @@
1
+ { "$extends" : "products/bogus.json" }
@@ -0,0 +1,4 @@
1
+ {
2
+ "$extends" : "products/simple.json",
3
+ "addition" : "more"
4
+ }
@@ -0,0 +1,126 @@
1
+ require "spec_helper"
2
+
3
+ describe Emerson::Matchers::ActionController::SendJsonMatcher, :type => :controller do
4
+ let(:do_request) { get :index, :format => :json }
5
+ let!(:products) { { :one => 1, :two => 2 } }
6
+
7
+ controller(:products)
8
+
9
+ before do
10
+ controller do
11
+ respond_to :json
12
+
13
+ def index
14
+ respond_with(products)
15
+ end
16
+ end
17
+
18
+ do_request
19
+ expect(response.body).to eq(products.to_json)
20
+ end
21
+
22
+ context "provided a Hash representing the expected JSON" do
23
+ it "provides a helpful description" do
24
+ matcher = send_json({})
25
+ expect(matcher.description).to eq('send JSON: (provided)')
26
+ end
27
+
28
+ it "accepts exact matches" do
29
+ expect(response).to send_json(products)
30
+ end
31
+
32
+ it "accepts valid matches with re-ordered pairs" do
33
+ expect(response).to send_json({ :two => 2, :one => 1})
34
+ end
35
+
36
+ it "rejects invalid matches" do
37
+ expect(response).to_not send_json({})
38
+ expect(response).to_not send_json({ :one => 2, :two => 1 })
39
+ expect(response).to_not send_json(products.to_json)
40
+ end
41
+ end
42
+
43
+ context "provided an Array representing the expected JSON" do
44
+ let(:products) { [:one, :two] }
45
+
46
+ it "provides a helpful description" do
47
+ matcher = send_json([])
48
+ expect(matcher.description).to eq('send JSON: (provided)')
49
+ end
50
+
51
+ it "accepts exact matches" do
52
+ expect(response).to send_json(products)
53
+ end
54
+
55
+ it "rejects invalid matches" do
56
+ expect(response).to_not send_json({})
57
+ expect(response).to_not send_json([])
58
+ expect(response).to_not send_json([:two, :one])
59
+ end
60
+ end
61
+
62
+ context "provided a String representing a JSON fixture lookup" do
63
+ let(:name) { 'products/simple' }
64
+
65
+ it "provides a helpful description" do
66
+ matcher = send_json(name)
67
+ expect(matcher.description).to eq('send JSON: products/simple.json')
68
+ end
69
+
70
+ it "accepts valid matches" do
71
+ expect(response).to send_json(name)
72
+ expect(response).to send_json("#{name}.json")
73
+ end
74
+
75
+ it "rejects invalid matches" do
76
+ expect(response).to_not send_json('products/bogus')
77
+ end
78
+ end
79
+
80
+ context "provided something other than a Hash or String" do
81
+ it "raises an exception" do
82
+ expect { send_json(:symbol) }.to raise_error(ArgumentError)
83
+ end
84
+ end
85
+
86
+ context "given JSON with the `$extends` keyword" do
87
+ let(:products) { { :one => 1, :two => 2, :addition => 'more' } }
88
+
89
+ it "accepts valid matches" do
90
+ expect(response).to send_json('products/extend-success')
91
+ expect(response).to send_json('products/extend-array')
92
+ end
93
+
94
+ it "rejects valid matches" do
95
+ expect(response).to_not send_json('products/extend-failure')
96
+ end
97
+ end
98
+
99
+ context "given a failed match" do
100
+ it "provides a helpful failure message" do
101
+ matcher = send_json({ :bogus => 'value' })
102
+ expect(matcher.matches?(response)).to eq(false)
103
+
104
+ message = matcher.failure_message
105
+ expect(message).to match(failure_message)
106
+ end
107
+ end
108
+
109
+ private
110
+
111
+ def failure_message
112
+ <<-EOMSG
113
+ Expected actual response:
114
+ ------------------------------------------------------------
115
+ {
116
+ "one": 1,
117
+ "two": 2
118
+ }
119
+ to match:
120
+ ------------------------------------------------------------
121
+ {
122
+ "bogus": "value"
123
+ }
124
+ EOMSG
125
+ end
126
+ end
@@ -0,0 +1,222 @@
1
+ require "spec_helper"
2
+
3
+ describe Emerson::Responder, :type => :controller do
4
+ render_views
5
+ let!(:products) { resources(:product, 2) }
6
+
7
+ describe "GET #index" do
8
+ controller(:products)
9
+
10
+ before do
11
+ controller do
12
+ def index
13
+ respond_with(products)
14
+ end
15
+ end
16
+
17
+ templates do
18
+ def index
19
+ <<-ERB
20
+ <ul>
21
+ <% products.each do |product| %>
22
+ <li><%= product.name %></li>
23
+ <% end %>
24
+ </ul>
25
+ ERB
26
+ end
27
+ end
28
+ end
29
+
30
+ context "as HTML" do
31
+ it "is successful" do
32
+ get(:index)
33
+ expect(response).to be_success
34
+ end
35
+
36
+ it "responds with the expected template" do
37
+ get(:index)
38
+ expect(response).to render_template(:template => 'index')
39
+ end
40
+
41
+ it "responds with the expected locals" do
42
+ get(:index)
43
+ expect(response.body).to have_css('ul > li', :text => products[0].name)
44
+ expect(response.body).to have_css('ul > li', :text => products[1].name)
45
+ end
46
+ end
47
+
48
+ context "as JSON (application/json - default)" do
49
+ it "is successful" do
50
+ get(:index, :format => :json)
51
+ expect(response).to be_success
52
+ end
53
+
54
+ it "responds with the expected JSON" do
55
+ get(:index, :format => :json)
56
+ expect(response).to send_json({
57
+ :data => {
58
+ :products => products
59
+ },
60
+ :view => "<ul><li>#{products[0].name}</li><li>#{products[1].name}</li></ul>"
61
+ })
62
+ end
63
+ end
64
+
65
+ context "as JSON (application/vnd.emerson+json)" do
66
+ before do
67
+ request.env['HTTP_ACCEPT'] = 'application/vnd.emerson+json'
68
+ end
69
+
70
+ it "is successful" do
71
+ get(:index, :format => :json)
72
+ expect(response).to be_success
73
+ end
74
+
75
+ it "responds with the expected JSON" do
76
+ get(:index, :format => :json)
77
+
78
+ expect(response).to send_json({
79
+ :data => {
80
+ :products => products
81
+ },
82
+ :view => "<ul><li>#{products[0].name}</li><li>#{products[1].name}</li></ul>"
83
+ })
84
+ end
85
+
86
+ context "when a custom `.json` template is found" do
87
+ before do
88
+ stub_template('products/index.json.erb' => "<%= products.map(&:name).to_json.html_safe %>")
89
+ end
90
+
91
+ it "responds using the template for the :view" do
92
+ get(:index, :format => :json)
93
+
94
+ expect(response).to send_json({
95
+ :data => {
96
+ :products => products
97
+ },
98
+ :view => products.map(&:name).to_json
99
+ })
100
+ end
101
+ end
102
+
103
+ context "when the target template is missing" do
104
+ before do
105
+ controller do
106
+ def index
107
+ respond_with(products, :path => 'bogus/path')
108
+ end
109
+ end
110
+ end
111
+
112
+ it "fails over to the default behavior" do
113
+ get(:index, :format => :json)
114
+ expect(response).to send_json(products)
115
+ end
116
+ end
117
+ end
118
+
119
+ context "as JSON (application/vnd.emerson.data+json)" do
120
+ before do
121
+ request.env['HTTP_ACCEPT'] = 'application/vnd.emerson.data+json'
122
+ end
123
+
124
+ it "is successful" do
125
+ get(:index, :format => :json)
126
+ expect(response).to be_success
127
+ end
128
+
129
+ it "responds with the expected JSON" do
130
+ get(:index, :format => :json)
131
+
132
+ expect(response).to send_json({
133
+ :data => {
134
+ :products => products
135
+ }
136
+ })
137
+ end
138
+ end
139
+
140
+ context "as JSON (application/vnd.emerson.view+json)" do
141
+ before do
142
+ request.env['HTTP_ACCEPT'] = 'application/vnd.emerson.view+json'
143
+ end
144
+
145
+ it "is successful" do
146
+ get(:index, :format => :json)
147
+ expect(response).to be_success
148
+ end
149
+
150
+ it "responds with the expected JSON" do
151
+ get(:index, :format => :json)
152
+
153
+ expect(response).to send_json({
154
+ :view => "<ul><li>#{products[0].name}</li><li>#{products[1].name}</li></ul>"
155
+ })
156
+ end
157
+
158
+ context "when a custom `.json` template is found" do
159
+ before do
160
+ stub_template('products/index.json.erb' => "<%= products.map(&:name).to_json.html_safe %>")
161
+ end
162
+
163
+ it "responds using the template for the :view" do
164
+ get(:index, :format => :json)
165
+
166
+ expect(response).to send_json({
167
+ :view => products.map(&:name).to_json
168
+ })
169
+ end
170
+ end
171
+ end
172
+
173
+ context "with Scope" do
174
+ let(:user) { resource(:user) }
175
+
176
+ before do
177
+ user.products = [products.first]
178
+ end
179
+
180
+ context "when :path is customized as :scoped" do
181
+ before do
182
+ template('users/products/index.html.erb' => '<p>custom template</p>')
183
+
184
+ controller do
185
+ scope :products, :by => :user
186
+
187
+ def index
188
+ respond_with(scoped, :path => :scoped)
189
+ end
190
+ end
191
+ end
192
+
193
+ it "responds with the expected template" do
194
+ get(:index, :user_id => user.id)
195
+ expect(response.body).to have_css('p', :text => 'custom template')
196
+ end
197
+ end
198
+
199
+ context "when :layout is customized as :scoped" do
200
+ before do
201
+ template({
202
+ 'users.html.erb' => '<p>custom layout</p>',
203
+ :layout => true
204
+ })
205
+
206
+ controller do
207
+ scope :products, :by => :user
208
+
209
+ def index
210
+ respond_with(scoped, :layout => :scoped)
211
+ end
212
+ end
213
+ end
214
+
215
+ it "responds with the expected layout" do
216
+ get(:index, :user_id => user.id)
217
+ expect(response.body).to have_css('p', :text => 'custom layout')
218
+ end
219
+ end
220
+ end
221
+ end
222
+ end
@@ -0,0 +1,75 @@
1
+ require "spec_helper"
2
+
3
+ describe Emerson::Response, :type => :controller do
4
+ it "is not automatically included" do
5
+ expect(ApplicationController.included_modules).to_not include(Emerson::Response)
6
+ end
7
+
8
+ context "when included" do
9
+ before do
10
+ expect(controller_class).to include(Emerson::Response)
11
+ end
12
+
13
+ it "includes Emerson::Scope" do
14
+ expect(controller_class).to include(Emerson::Scope)
15
+ end
16
+
17
+ it "configures the responder" do
18
+ expect(controller_class.responder).to eq(Emerson::Responder)
19
+ end
20
+
21
+ it "configures the :respond_to mimes" do
22
+ expect(controller_class.mimes_for_respond_to).to eq({ :html => {}, :json => {} })
23
+ end
24
+ end
25
+
26
+ context "when the :responder feature is disabled" do
27
+ let(:inline_controller) do
28
+ Class.new(ApplicationController) do
29
+ include Emerson::Response
30
+ end
31
+ end
32
+
33
+ around do |example|
34
+ with_features(nil) { example.run }
35
+ end
36
+
37
+ it "does not configure the responder" do
38
+ expect(inline_controller.responder).to eq(ActionController::Responder)
39
+ end
40
+
41
+ it "does not configure the :respond_to mimes" do
42
+ expect(inline_controller.mimes_for_respond_to).to eq({})
43
+ end
44
+ end
45
+
46
+ context "when the :scope feature is disabled" do
47
+ let(:inline_controller) do
48
+ Class.new(ApplicationController) do
49
+ include Emerson::Response
50
+ end
51
+ end
52
+
53
+ around do |example|
54
+ with_features(nil) { example.run }
55
+ end
56
+
57
+ it "does not include Emerson::Scope" do
58
+ expect(inline_controller).to_not include(Emerson::Scope)
59
+ end
60
+ end
61
+
62
+ private
63
+
64
+ controller(ApplicationController) do
65
+ include Emerson::Response
66
+
67
+ def self.name
68
+ 'ProductsController'
69
+ end
70
+ end
71
+
72
+ def controller_class
73
+ described_class
74
+ end
75
+ end