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

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