Skip to content

Commit

Permalink
Merge pull request #15 from hosh/master
Browse files Browse the repository at this point in the history
Fixes to get working with Rails 3.1 and Ruby 1.9.2
  • Loading branch information
hosh committed Oct 19, 2011
2 parents 883c616 + 9468559 commit 0789dd0
Show file tree
Hide file tree
Showing 13 changed files with 166 additions and 44 deletions.
10 changes: 6 additions & 4 deletions lib/intermodal.rb
Original file line number Diff line number Diff line change
Expand Up @@ -87,10 +87,12 @@ module RSpec
autoload :ResourceLinking, 'intermodal/rspec/models/resource_linking'

# Requests
autoload :Rack, 'intermodal/rspec/requests/rack'
autoload :HTTP, 'intermodal/rspec/requests/rfc2616_status_codes'
autoload :Resources, 'intermodal/rspec/requests/resources'
autoload :LinkedResources, 'intermodal/rspec/requests/linked_resources'
autoload :Rack, 'intermodal/rspec/requests/rack'
autoload :HTTP, 'intermodal/rspec/requests/rfc2616_status_codes'
autoload :AuthenticatedRequests, 'intermodal/rspec/requests/authenticated_requests'
autoload :PaginatedCollection, 'intermodal/rspec/requests/paginated_collection'
autoload :Resources, 'intermodal/rspec/requests/resources'
autoload :LinkedResources, 'intermodal/rspec/requests/linked_resources'
end
end

Expand Down
24 changes: 18 additions & 6 deletions lib/intermodal/api.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,15 @@ module API
self.max_per_page = Intermodal.max_per_page
self.default_per_page = Intermodal.default_per_page

initializer 'intermodal.load_presentation', :after => 'load_config_initializer' do
initializer 'intermodal.load_presentation', :after => 'eager_load!' do
self.load_presentations!
end

initializer 'intermodal.load_controllers', :after => 'load_config_initializer' do
initializer 'intermodal.load_controllers', :after => 'eager_load!' do
self.class.load_controllers!
end

initializer 'intermodal.load_x_auth_token_warden', :before => 'load_config_initializer' do
initializer 'intermodal.load_x_auth_token_warden', :before => 'build_middleware_stack' do
Warden::Strategies.add(:x_auth_token) do
def valid?
env['HTTP_X_AUTH_TOKEN']
Expand All @@ -36,9 +36,9 @@ def default_middleware_stack
ActionDispatch::MiddlewareStack.new.tap do |middleware|
middleware.use ::Intermodal::Rack::Rescue

middleware.use ::Rack::Lock
middleware.use ::Rack::Runtime
middleware.use ::Rails::Rack::Logger
#middleware.use ::Rack::Lock
#middleware.use ::Rack::Runtime
#middleware.use ::Rails::Rack::Logger
#middleware.use ::ActionDispatch::RemoteIp, config.action_dispatch.ip_spoofing_check, config.action_dispatch.trusted_proxies
#middleware.use ::Rack::Sendfile, config.action_dispatch.x_sendfile_header
#middleware.use ::ActionDispatch::Callbacks, !config.cache_classes
Expand All @@ -60,6 +60,18 @@ def default_middleware_stack
middleware.use ::ActionDispatch::Head
end
end

# Epiphyte (hack)
# Apparently, Rails does not want you to define routes within the engine itself
def self.routes
instance.routes
end

def routes
@routes ||= ActionDispatch::Routing::RouteSet.new
@routes.append(&Proc.new) if block_given?
@routes
end
end
end
end
13 changes: 10 additions & 3 deletions lib/intermodal/declare_controllers.rb
Original file line number Diff line number Diff line change
Expand Up @@ -59,9 +59,12 @@ def load_controllers!
# API: private
def _create_controller(collection_name, controller_name, customizations, options = {}, &blk)
_ancestor = options[:ancestor] || ApplicationController
_namespace = options[:namespace] || Object
_namespace = options[:namespace] #|| Object

_unload_controller_if_exists(controller_name, _namespace)

_namespace ||= Object

controller = Class.new(_ancestor)
_namespace.const_set(controller_name, controller)

Expand Down Expand Up @@ -93,8 +96,12 @@ def _module(module_name)
end
end

def _unload_controller_if_exists(controller_name, _namespace = Object)
_namespace.send(:remove_const, controller_name) if _namespace.const_defined?(controller_name) # Unload existing class
def _unload_controller_if_exists(controller_name, _namespace = nil)
full_controller_name = [_namespace, controller_name].join('::')

# I found no other good way to detect this without using eval that would work
# for both 1.8.7 and 1.9.2
(_namespace || Object).send(:remove_const, controller_name) if eval "defined? #{full_controller_name}" # Unload existing class
end
end
end
7 changes: 6 additions & 1 deletion lib/intermodal/mapping/mapper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,12 @@ def map_attributes(resource, scope = :default)
def map_attribute(resource, mapped_to)
case mapped_to
when Symbol then resource[mapped_to]
when Proc then mapped_to.call(resource)
when Proc then
if mapped_to.arity == 1
mapped_to.call(resource)
else
mapped_to.call()
end
when Array then mapped_to.inject({}) { |m, _element| m.tap { |_m| _m[_element] = map_attribute(resource, _element) } }
end
end
Expand Down
11 changes: 6 additions & 5 deletions lib/intermodal/rspec/models/has_parent_resource.rb
Original file line number Diff line number Diff line change
Expand Up @@ -56,21 +56,22 @@ def should_respond_to_scope(scope_method)
end
end

def concerned_with_parent_resource(parent_resource_name, options = {}, &blk)
def concerned_with_parent_resource(_parent_resource_name, options = {}, &blk)
extra_get_examples = options[:extra_get_examples]

context "when concerned with parent resource #{parent_resource_name}" do
context "when concerned with parent resource #{_parent_resource_name}" do
let(:parent_resource_name) { _parent_resource_name }
let(:parent_id_name) { "#{parent_resource_name}_id" }
let(:parent_model) { parent_resource_name.to_s.camelize.constantize }
let(:different_parent) { parent_model.make! }
let(:parent_with_different_account) { parent_model.make!(:account => different_account) }

instance_eval(&blk) if blk

it { should belong_to parent_resource_name } unless options[:skip_association_examples]
it { should validate_presence_of parent_resource_name } unless options[:skip_validation_examples]
it { should belong_to _parent_resource_name } unless options[:skip_association_examples]
it { should validate_presence_of _parent_resource_name } unless options[:skip_validation_examples]

[ :by_parent_id, :by_parent, "by_#{parent_resource_name}_id", "by_#{parent_resource_name}" ].each do |scope|
[ :by_parent_id, :by_parent, "by_#{_parent_resource_name}_id", "by_#{_parent_resource_name}" ].each do |scope|
should_respond_to_scope(scope)
end

Expand Down
8 changes: 4 additions & 4 deletions lib/intermodal/rspec/models/resource_linking.rb
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,8 @@ def concerned_with_resource_linking(_parent_resource_name, _target_resource_name
let(:target_model_blueprint) { proc do target_model.make!(:account => account) end }
let(:target_model_blueprint_with_different_account) { proc do target_model.make!(:account => different_account) end }
let(:target_accounts) { targets.map(&:account) }
let(:target_with_different_account) { target_model_blueprint_with_different_account[] }
let(:targets_with_different_account) { (1..3).map { target_model_blueprint_with_different_account[] } }
let(:target_with_different_account) { target_model_blueprint_with_different_account.call() }
let(:targets_with_different_account) { (1..3).map { target_model_blueprint_with_different_account.call() } }
let(:target_ids_with_different_account) { targets_with_different_account.map(&:id) }

instance_eval(&blk) if blk
Expand Down Expand Up @@ -101,7 +101,7 @@ def concerned_with_resource_linking(_parent_resource_name, _target_resource_name
end

describe '.replace' do
let(:replacement_targets) { (1..3).map(&target_model_blueprint) }
let(:replacement_targets) { (1..3).map { target_model_blueprint.call() } }
let(:replacement_target_ids) { replacement_targets.map(&:id) }
let(:original_target_ids) { list; parent.send(target_association_name).map(&:id) }
let(:updated_target_ids) { model.get(:all, :parent => parent).to_target_ids }
Expand Down Expand Up @@ -141,7 +141,7 @@ def concerned_with_resource_linking(_parent_resource_name, _target_resource_name
end

describe '.append' do
let(:additional_targets) { (1..3).map(&target_model_blueprint) }
let(:additional_targets) { (1..3).map { target_model_blueprint.call() } }
let(:additional_target_ids) { additional_targets.map(&:id) }
let(:original_target_ids) { list; parent.send(target_association_name).map(&:id) }
let(:updated_target_ids) { parent.send(target_association_name).map(&:id) }
Expand Down
17 changes: 17 additions & 0 deletions lib/intermodal/rspec/requests/authenticated_requests.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
module Intermodal
module RSpec
module AuthenticatedRequests
extend ActiveSupport::Concern

module ClassMethods
def expects_unauthorized_access_to_respond_with_401
context 'with unauthorized access credentials' do
let(:http_headers) { { 'X-Auth-Token' => '', 'Accept' => 'application/json' } }

expects_status(401)
end
end
end
end
end
end
13 changes: 11 additions & 2 deletions lib/intermodal/rspec/requests/linked_resources.rb
Original file line number Diff line number Diff line change
Expand Up @@ -33,13 +33,13 @@ def link_resource(parent_resource, options = {}, &blk)
:with => collection,
:parent_id => model_parents.first.id
end
let(:presented_collection) { parser.parse(collection_proxy.send("to_#{format}")) }
let(:presented_collection) { parser.decode(collection_proxy.send("to_#{format}")) }
instance_eval(&blk)
end
end

def expects_crud_for_linked_resource
expects_index do
expects_index :skip_pagination_examples => true do
it 'should include the parent id' do
collection.should_not be_empty
body[resource_element_name.to_s]['id'].should eql(model_parents.first.id)
Expand All @@ -64,6 +64,9 @@ def expects_list_replace(&blk)
expects_status(201)
expects_content_type(metadata[:mime_type], metadata[:encoding])

with_malformed_data_should_respond_with_400
expects_unauthorized_access_to_respond_with_401

it "should link #{metadata[:target_resources]} to #{metadata[:parent_resource]}" do
model_collection.should_not be_empty
response.should_not be_empty
Expand Down Expand Up @@ -109,6 +112,9 @@ def expects_list_append(&blk)
updated_target_ids.should include(original_target_id)
end
end

with_malformed_data_should_respond_with_400
expects_unauthorized_access_to_respond_with_401
end
end

Expand Down Expand Up @@ -140,6 +146,9 @@ def expects_list_remove(&blk)
updated_target_ids.should include(remaining_target_id)
end
end

with_malformed_data_should_respond_with_400
expects_unauthorized_access_to_respond_with_401
end
end

Expand Down
54 changes: 54 additions & 0 deletions lib/intermodal/rspec/requests/paginated_collection.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
module Intermodal
module RSpec
module PaginatedCollection
extend ActiveSupport::Concern

module ClassMethods
def expects_pagination(options = {})
# Default behavior for will_paginate
options[:page] ||= 1
options[:collection_name]

context 'when paginating' do
let(:expected_total_pages) { collection.size/per_page + 1 }
let(:collection_element_name) { options[:collection_name] } if options[:collection_name]
let(:responded_collection_metadata) do
case format
when :xml
body[collection_element_name]
else
body
end
end

if options[:empty_collection]
it 'should have an empty collection' do
body[collection_element_name.to_s].should be_empty
end
else
it 'should have a collection' do
collection
body[collection_element_name.to_s].should_not be_empty
end
end

it "should be on page #{options[:page]}" do
collection
responded_collection_metadata['page'].should eql(options[:page])
end

it 'should have total_pages' do
collection
responded_collection_metadata['total_pages'].should eql(expected_total_pages)
end

it 'should have total_entries' do
collection
responded_collection_metadata['total_entries'].should eql(collection.size)
end
end
end
end
end
end
end
2 changes: 1 addition & 1 deletion lib/intermodal/rspec/requests/rack.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ def self.decode(*args)
subject { response }

# Define the Rack Application you are testing
let(:application) { fail NotImplemented, 'Must define let(:application)' }
let(:application) { fail NotImplementedError, 'Must define let(:application)' }
let(:http_headers) { Hash.new }
let(:request_headers) do
http_headers.to_a.inject({}) do |m,kv|
Expand Down
33 changes: 26 additions & 7 deletions lib/intermodal/rspec/requests/resources.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ module Resources

included do
include Intermodal::RSpec::Rack
include Intermodal::RSpec::AuthenticatedRequests
include Intermodal::RSpec::PaginatedCollection

let(:resource_collection_name) { resource_name.pluralize }
let(:model) { resource_name.camelize.constantize }
Expand Down Expand Up @@ -156,6 +158,8 @@ def expects_index(options = {}, &additional_examples)
body.should eql(presented_collection)
end

expects_unauthorized_access_to_respond_with_401
expects_pagination unless options[:skip_pagination_examples]
instance_eval(&additional_examples) if additional_examples
end
end
Expand All @@ -167,6 +171,7 @@ def expects_show(options = {}, &additional_examples)
body.should eql(resource)
end

expects_unauthorized_access_to_respond_with_401
instance_eval(&additional_examples) if additional_examples
end
end
Expand All @@ -177,13 +182,8 @@ def expects_create(options = {}, &additional_examples)
body.should eql(parser.decode(model.find(body[resource_name]['id']).send("to_#{format}", { :presenter => presenter, :root => resource_element_name})))
end

context "with malformed #{metadata[:format]} payload" do
let(:request_raw_payload) { send("malformed_#{format}_payload") }

expects_status(400)
expects_content_type(options[:mime_type], options[:encoding])
end

with_malformed_data_should_respond_with_400
expects_unauthorized_access_to_respond_with_401
instance_eval(&additional_examples) if additional_examples
end
end
Expand All @@ -198,6 +198,8 @@ def expects_update(options = {}, &additional_examples)
end
end

with_malformed_data_should_respond_with_400
expects_unauthorized_access_to_respond_with_401
instance_eval(&additional_examples) if additional_examples
end
end
Expand All @@ -209,10 +211,27 @@ def expects_destroy(options = {}, &additional_examples)
lambda { model.find(resource_id) }.should raise_error(ActiveRecord::RecordNotFound)
end

expects_unauthorized_access_to_respond_with_401
instance_eval(&additional_examples) if additional_examples
end
end

def with_malformed_data_should_respond_with_400
context "with malformed #{metadata[:format]} payload" do
let(:request_raw_payload) { send("malformed_#{format}_payload") }

expects_status(400)
expects_content_type(metadata[:mime_type], metadata[:encoding])
end
end

def expects_json_presentation(_presenter_scope = nil)
let(:presenter_scope) { _presenter_scope } if _presenter_scope

it 'should present a JSON object' do
body.should eql(presented_resource)
end
end
end
end
end
Expand Down
8 changes: 7 additions & 1 deletion spec/spec_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,13 @@
require 'intermodal'
require 'rails'
require 'active_record'

require 'will_paginate/active_record'

# TODO: Figure out how to load this automatically through the epiphyte
require 'intermodal/proxies/will_paginate'
::WillPaginate::Collection.send(:include, Intermodal::Proxies::WillPaginate::Collection)

require 'action_controller'
require 'rspec-rails'
require 'database_cleaner'
Expand All @@ -29,7 +35,7 @@
config.mock_with :rspec
config.filter_run :focus => true
config.filter_run_excluding :external => true
config.run_all_when_everything_filtered = true
config.run_all_when_everything_filtered = true

# Uncomment to use with Rspec Rails
# If you'd prefer not to run each of your examples within a transaction,
Expand Down
Loading

0 comments on commit 0789dd0

Please sign in to comment.