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,146 @@
1
+ require "spec_helper"
2
+
3
+ describe Emerson::Scope, :type => :controller do
4
+ render_views
5
+ let!(:products) { resources(:product, 2) }
6
+
7
+ controller(:products)
8
+
9
+ before do
10
+ templates do
11
+ def index
12
+ <<-ERB
13
+ <ul>
14
+ <% products.each do |product| %>
15
+ <li><%= product.name %></li>
16
+ <% end %>
17
+ </ul>
18
+ ERB
19
+ end
20
+ end
21
+ end
22
+
23
+ describe ".scope" do
24
+ context "called without a 'resources' argument" do
25
+ it "raises an exception" do
26
+ expect {
27
+ controller_class.class_eval do
28
+ scope :by => :user
29
+ end
30
+ }.to raise_error(ArgumentError)
31
+ end
32
+ end
33
+
34
+ context "called without the :by requirement" do
35
+ it "raises an exception" do
36
+ expect {
37
+ controller_class.class_eval do
38
+ scope :products
39
+ end
40
+ }.to raise_error(ArgumentError)
41
+ end
42
+ end
43
+ end
44
+
45
+ describe "#current_scope" do
46
+ let(:user) { resource(:user) }
47
+
48
+ before do
49
+ user.products = [products.first]
50
+
51
+ controller do
52
+ scope :products, :by => :user
53
+
54
+ def index
55
+ render(:json => { :user => current_scope.id })
56
+ end
57
+ end
58
+ end
59
+
60
+ it "returns the record representing the current scope" do
61
+ get(:index, :user_id => user.id)
62
+ expect(response).to send_json({
63
+ :user => user.id
64
+ })
65
+ end
66
+
67
+ context "detailed scope configurations and environments" do
68
+ it "is pending" do
69
+ pending "TODO"
70
+ end
71
+ end
72
+ end
73
+
74
+ describe "#scoped" do
75
+ context "without a scope configuration" do
76
+ before do
77
+ controller do
78
+ def index
79
+ respond_with(scoped)
80
+ end
81
+ end
82
+ end
83
+
84
+ it "selects the resource using the default scope, from the controller name" do
85
+ get(:index)
86
+ expect(response.body).to have_css('ul > li', :text => products[0].name)
87
+ expect(response.body).to have_css('ul > li', :text => products[1].name)
88
+ end
89
+ end
90
+
91
+ context "with a scope configuration" do
92
+ let(:user) { resource(:user) }
93
+
94
+ before do
95
+ user.products = [products.first]
96
+
97
+ controller do
98
+ scope :products, :by => :user
99
+
100
+ def index
101
+ respond_with(scoped)
102
+ end
103
+ end
104
+ end
105
+
106
+ context "given no scoping environment" do
107
+ it "selects the resource using the default scope, from configuration" do
108
+ get(:index)
109
+ expect(response.body).to have_css('ul > li', :text => products[0].name)
110
+ expect(response.body).to have_css('ul > li', :text => products[1].name)
111
+ end
112
+ end
113
+
114
+ context "given a scoping environment based on request params" do
115
+ it "selects the resource using the provided scope" do
116
+ get(:index, :user_id => user.id)
117
+ expect(response.body).to have_css('ul > li', :text => products[0].name)
118
+ expect(response.body).to_not have_css('ul > li', :text => products[1].name)
119
+ end
120
+ end
121
+ end
122
+
123
+ context "with a scope configuration and a scoping environment as a specific object" do
124
+ let(:user) { resource(:user) }
125
+
126
+ before do
127
+ user.products = [products.first]
128
+
129
+ controller.stub(:user) { user }
130
+ controller do
131
+ scope :products, :by => :user
132
+
133
+ def index
134
+ respond_with(scoped(user))
135
+ end
136
+ end
137
+ end
138
+
139
+ it "selects the resource using the provided scope" do
140
+ get(:index)
141
+ expect(response.body).to have_css('ul > li', :text => products[0].name)
142
+ expect(response.body).to_not have_css('ul > li', :text => products[1].name)
143
+ end
144
+ end
145
+ end
146
+ end
@@ -0,0 +1,105 @@
1
+ require "spec_helper"
2
+
3
+ describe Emerson do
4
+ let(:features) { Emerson.features }
5
+
6
+ around do |example|
7
+ with_features(features) { example.run }
8
+ end
9
+
10
+ describe ".responder_enabled?" do
11
+ context "with the default feature set" do
12
+ it "returns true" do
13
+ expect(Emerson).to be_responder_enabled
14
+ end
15
+ end
16
+
17
+ context "when the configured feature set is :all" do
18
+ let(:features) { :all }
19
+
20
+ it "returns true" do
21
+ expect(Emerson).to be_responder_enabled
22
+ end
23
+ end
24
+
25
+ context "when the configured feature set includes :responder" do
26
+ let(:features) { [:responder] }
27
+
28
+ it "returns true" do
29
+ expect(Emerson).to be_responder_enabled
30
+ end
31
+ end
32
+
33
+ context "when the configured feature set is nil" do
34
+ let(:features) { nil }
35
+
36
+ it "returns false" do
37
+ expect(Emerson).to_not be_responder_enabled
38
+ end
39
+ end
40
+
41
+ context "when the configured feature set is false" do
42
+ let(:features) { false }
43
+
44
+ it "returns false" do
45
+ expect(Emerson).to_not be_responder_enabled
46
+ end
47
+ end
48
+
49
+ context "when the configured feature set is []" do
50
+ let(:features) { [] }
51
+
52
+ it "returns false" do
53
+ expect(Emerson).to_not be_responder_enabled
54
+ end
55
+ end
56
+ end
57
+
58
+ describe ".scope_enabled?" do
59
+ context "with the default feature set" do
60
+ it "returns true" do
61
+ expect(Emerson).to be_scope_enabled
62
+ end
63
+ end
64
+
65
+ context "when the configured feature set is :all" do
66
+ let(:features) { :all }
67
+
68
+ it "returns true" do
69
+ expect(Emerson).to be_scope_enabled
70
+ end
71
+ end
72
+
73
+ context "when the configured feature set includes :scope" do
74
+ let(:features) { [:scope] }
75
+
76
+ it "returns true" do
77
+ expect(Emerson).to be_scope_enabled
78
+ end
79
+ end
80
+
81
+ context "when the configured feature set is nil" do
82
+ let(:features) { nil }
83
+
84
+ it "returns false" do
85
+ expect(Emerson).to_not be_scope_enabled
86
+ end
87
+ end
88
+
89
+ context "when the configured feature set is false" do
90
+ let(:features) { false }
91
+
92
+ it "returns false" do
93
+ expect(Emerson).to_not be_scope_enabled
94
+ end
95
+ end
96
+
97
+ context "when the configured feature set is []" do
98
+ let(:features) { [] }
99
+
100
+ it "returns false" do
101
+ expect(Emerson).to_not be_scope_enabled
102
+ end
103
+ end
104
+ end
105
+ end
@@ -0,0 +1,67 @@
1
+ # This file is copied to spec/ when you run 'rails generate rspec:install'
2
+ ENV["RAILS_ENV"] ||= 'test'
3
+ require File.expand_path("../dummy/config/environment", __FILE__)
4
+ require 'rspec/rails'
5
+ require 'rspec/autorun'
6
+ require 'capybara/rspec'
7
+ require 'ffaker'
8
+
9
+ require 'emerson/matchers'
10
+
11
+ # Requires supporting ruby files with custom matchers and macros, etc,
12
+ # in spec/support/ and its subdirectories.
13
+ Dir[Rails.root.join("../support/**/*.rb")].each {|f| require f}
14
+
15
+ Capybara.register_driver :firefox do |app|
16
+ Capybara::Selenium::Driver.new(app, :browser => :firefox)
17
+ end
18
+
19
+ RSpec.configure do |config|
20
+ config.include Capybara::RSpecMatchers
21
+ config.include Support::ControllerHelpers
22
+ config.include Support::FeatureHelpers
23
+ config.include Support::ResourceHelpers
24
+ config.include Support::TemplateHelpers
25
+
26
+ # ## Mock Framework
27
+ #
28
+ # If you prefer to use mocha, flexmock or RR, uncomment the appropriate line:
29
+ #
30
+ # config.mock_with :mocha
31
+ # config.mock_with :flexmock
32
+ # config.mock_with :rr
33
+
34
+ # Remove this line if you're not using ActiveRecord or ActiveRecord fixtures
35
+ config.fixture_path = "#{::Rails.root}/spec/support/fixtures"
36
+
37
+ # If you're not using ActiveRecord, or you'd prefer not to run each of your
38
+ # examples within a transaction, remove the following line or assign false
39
+ # instead of true.
40
+ config.use_transactional_fixtures = true
41
+
42
+ # If true, the base class of anonymous controllers will be inferred
43
+ # automatically. This will be the default behavior in future versions of
44
+ # rspec-rails.
45
+ config.infer_base_class_for_anonymous_controllers = false
46
+
47
+ # Run specs in random order to surface order dependencies. If you find an
48
+ # order dependency and want to debug it, you can fix the order by providing
49
+ # the seed, which is printed after each run.
50
+ # --seed 1234
51
+ config.order = "random"
52
+
53
+ config.before do
54
+ reset_resources
55
+ end
56
+
57
+ config.after do
58
+ reset_resources
59
+ end
60
+ end
61
+
62
+ Emerson.setup do |config|
63
+ # Uncomment this line to specify a custom fixture path for Emerson. It will
64
+ # default to the RSpec fixture path and is required for the response tests.
65
+ #
66
+ # config.fixture_path = "#{::Rails.root}/spec/support/fixtures"
67
+ end
@@ -0,0 +1,98 @@
1
+ module Support
2
+ module ControllerHelpers
3
+ extend ActiveSupport::Concern
4
+
5
+ module ClassMethods
6
+ # Override `ControllerExampleGroup.controller` for some nice sugar.
7
+ # See instance method below.
8
+ def controller(key, base = nil)
9
+ klass = Class.new(base || ApplicationController) do
10
+ include Emerson::Response
11
+ end
12
+
13
+ klass.class_eval <<-CODE
14
+ def self.name
15
+ @_name ||= [key, 'controller'].join('_').camelcase
16
+ end
17
+
18
+ def self.key
19
+ @_key ||= '#{key}'.intern
20
+ end
21
+
22
+ def #{key}
23
+ resources
24
+ end
25
+
26
+ def resources=(value)
27
+ @resources = value
28
+ end
29
+
30
+ def resources
31
+ @resources
32
+ end
33
+
34
+ # Scope helper
35
+ def class_for(type)
36
+ "Support::ResourceHelpers::\#{type.to_s.classify}".constantize
37
+ end
38
+ CODE
39
+
40
+ metadata[:example_group][:described_class] = klass
41
+
42
+ before do
43
+ @_resource_type = key
44
+ end
45
+ end
46
+ end
47
+
48
+ # Add `#controller` ExampleGroup instance method which, combined with the
49
+ # overriden class method above, provides the ability to:
50
+ #
51
+ # @example
52
+ # describe "GET #index" do
53
+ # controller(:products)
54
+ #
55
+ # before do
56
+ # controller do
57
+ # def index
58
+ # respond_with(products)
59
+ # end
60
+ # end
61
+ # end
62
+ #
63
+ # it "is successful" do
64
+ # get(:index)
65
+ # expect(response).to be_success
66
+ # end
67
+ # end
68
+ def controller(*args, &body)
69
+ if block_given?
70
+ controller_class.class_eval(&body)
71
+
72
+ resource_set = self.instance_variable_get('@_resources')
73
+ resource_set = self.instance_variable_get('@__memoized') unless resource_set.present?
74
+ resource_key = "#{controller_class.key}".singularize.intern
75
+
76
+ @controller.resources = (resource_set[resource_key] || resource_set[controller_class.key])
77
+ end
78
+
79
+ super()
80
+ end
81
+
82
+ def controller_class
83
+ described_class
84
+ end
85
+
86
+ # Wrap `ActionController::TestCase::Behavior` actions in
87
+ # a warm routing embrace.
88
+ def process(*)
89
+ with_routing do |routes|
90
+ routes.instance_eval "
91
+ draw { resources #{@_resource_type.inspect} }
92
+ "
93
+
94
+ super
95
+ end
96
+ end
97
+ end
98
+ end
@@ -0,0 +1,12 @@
1
+ module Support
2
+ module FeatureHelpers
3
+ def with_features(enabled, &block)
4
+ originals = Emerson.features
5
+ Emerson.features = enabled
6
+
7
+ yield
8
+
9
+ Emerson.features = originals
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,95 @@
1
+ require 'virtus'
2
+
3
+ module Support
4
+ module ResourceHelpers
5
+ def reset_resources
6
+ Product.records = []
7
+ User.records = []
8
+ end
9
+
10
+ def resource(type)
11
+ resources(type)[0]
12
+ end
13
+
14
+ def resources(type, count = nil)
15
+ @_resources ||= {}
16
+
17
+ if count.present? || @_resources[type].blank?
18
+ model = resource_class(type)
19
+ count ||= 1
20
+ count.times { model.create }
21
+
22
+ @_resources[type] = model.records
23
+ end
24
+
25
+ @_resources[type]
26
+ end
27
+
28
+ def resource_class(type)
29
+ case type
30
+ when :product
31
+ Product
32
+ when :user
33
+ User
34
+ end
35
+ end
36
+
37
+ class Base
38
+ include Virtus
39
+ extend ActiveModel::Naming
40
+ include ActiveModel::Conversion
41
+ include ActiveModel::Validations
42
+
43
+ attribute :id, Fixnum, :default => :default_id
44
+ attribute :name, String, :default => :default_name
45
+
46
+ class_attribute :records
47
+ self.records = []
48
+
49
+ # Emulating ActiveRecord class methods
50
+ class << self
51
+ def create
52
+ record = self.new
53
+
54
+ self.records << record
55
+ record
56
+ end
57
+
58
+ def find(id)
59
+ self.records.first { |r| r.id == id.to_i }
60
+ end
61
+
62
+ def scoped
63
+ self.records
64
+ end
65
+ end
66
+
67
+ def default_id
68
+ Faker::Lorem.word
69
+ end
70
+
71
+ def default_name
72
+ Faker::Lorem.word
73
+ end
74
+ end
75
+
76
+ class Product < Base
77
+ def default_name
78
+ Faker::Product.product_name
79
+ end
80
+ end
81
+
82
+ class User < Base
83
+ attribute :products, Array, :default => :default_products
84
+
85
+ # self.records = []
86
+ def default_name
87
+ Faker::Name.name.gsub(/[']/, '')
88
+ end
89
+
90
+ def default_products
91
+ [Product.new, Product.new]
92
+ end
93
+ end
94
+ end
95
+ end