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