focused_controller 0.1.0
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.
- data/.gitignore +5 -0
- data/.travis.yml +15 -0
- data/Appraisals +11 -0
- data/Gemfile +4 -0
- data/README.md +1 -0
- data/Rakefile +21 -0
- data/focused_controller.gemspec +30 -0
- data/gemfiles/rails-3-0.gemfile +7 -0
- data/gemfiles/rails-3-1.gemfile +7 -0
- data/gemfiles/rails-3-2.gemfile +7 -0
- data/lib/focused_controller.rb +4 -0
- data/lib/focused_controller/action_name.rb +6 -0
- data/lib/focused_controller/functional_test_helper.rb +25 -0
- data/lib/focused_controller/mixin.rb +44 -0
- data/lib/focused_controller/route.rb +15 -0
- data/lib/focused_controller/route_mapper.rb +58 -0
- data/lib/focused_controller/rspec_controller_class.rb +15 -0
- data/lib/focused_controller/rspec_functional_helper.rb +25 -0
- data/lib/focused_controller/rspec_helper.rb +42 -0
- data/lib/focused_controller/test_helper.rb +183 -0
- data/lib/focused_controller/version.rb +3 -0
- data/test/acceptance/app_test.rb +156 -0
- data/test/app/.gitignore +15 -0
- data/test/app/Gemfile +6 -0
- data/test/app/README.rdoc +261 -0
- data/test/app/Rakefile +7 -0
- data/test/app/app/controllers/application_controller.rb +6 -0
- data/test/app/app/controllers/posts_controller.rb +60 -0
- data/test/app/app/models/.gitkeep +0 -0
- data/test/app/app/models/post.rb +88 -0
- data/test/app/app/views/layouts/application.html.erb +13 -0
- data/test/app/app/views/posts/_form.html.erb +31 -0
- data/test/app/app/views/posts/edit.html.erb +6 -0
- data/test/app/app/views/posts/index.html.erb +23 -0
- data/test/app/app/views/posts/new.html.erb +5 -0
- data/test/app/app/views/posts/show.html.erb +8 -0
- data/test/app/config.ru +4 -0
- data/test/app/config/application.rb +16 -0
- data/test/app/config/boot.rb +6 -0
- data/test/app/config/environment.rb +5 -0
- data/test/app/config/environments/development.rb +21 -0
- data/test/app/config/environments/test.rb +29 -0
- data/test/app/config/initializers/backtrace_silencers.rb +7 -0
- data/test/app/config/initializers/inflections.rb +15 -0
- data/test/app/config/initializers/mime_types.rb +5 -0
- data/test/app/config/initializers/secret_token.rb +7 -0
- data/test/app/config/initializers/session_store.rb +8 -0
- data/test/app/config/locales/en.yml +5 -0
- data/test/app/config/routes.rb +62 -0
- data/test/app/db/seeds.rb +7 -0
- data/test/app/doc/README_FOR_APP +2 -0
- data/test/app/lib/assets/.gitkeep +0 -0
- data/test/app/lib/tasks/.gitkeep +0 -0
- data/test/app/log/.gitkeep +0 -0
- data/test/app/public/404.html +26 -0
- data/test/app/public/422.html +26 -0
- data/test/app/public/500.html +25 -0
- data/test/app/public/favicon.ico +0 -0
- data/test/app/public/index.html +241 -0
- data/test/app/public/javascripts/application.js +9663 -0
- data/test/app/public/robots.txt +5 -0
- data/test/app/public/stylesheets/application.css +83 -0
- data/test/app/script/rails +6 -0
- data/test/app/spec/controllers/posts_controller_spec.rb +59 -0
- data/test/app/spec/isolated_spec_helper.rb +9 -0
- data/test/app/spec/spec_helper.rb +5 -0
- data/test/app/spec/unit/controllers/posts_controller_isolated_spec.rb +60 -0
- data/test/app/spec/unit/controllers/posts_controller_spec.rb +59 -0
- data/test/app/test/functional/.gitkeep +0 -0
- data/test/app/test/functional/posts_controller_test.rb +67 -0
- data/test/app/test/isolated_test_helper.rb +10 -0
- data/test/app/test/test_helper.rb +6 -0
- data/test/app/test/unit/.gitkeep +0 -0
- data/test/app/test/unit/controllers/posts_controller_isolated_test.rb +69 -0
- data/test/app/test/unit/controllers/posts_controller_test.rb +67 -0
- data/test/app/vendor/assets/javascripts/.gitkeep +0 -0
- data/test/app/vendor/assets/stylesheets/.gitkeep +0 -0
- data/test/app/vendor/plugins/.gitkeep +0 -0
- data/test/helper.rb +33 -0
- data/test/unit/functional_test_helper_test.rb +65 -0
- data/test/unit/mixin_test.rb +70 -0
- data/test/unit/route_mapper_test.rb +73 -0
- data/test/unit/route_test.rb +39 -0
- data/test/unit/rspec_functional_helper.rb +42 -0
- data/test/unit/rspec_helper_test.rb +91 -0
- data/test/unit/test_helper_test.rb +235 -0
- metadata +285 -0
data/.gitignore
ADDED
data/.travis.yml
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
language: ruby
|
2
|
+
rvm:
|
3
|
+
- 1.9.3
|
4
|
+
- 1.9.2
|
5
|
+
- 1.8.7
|
6
|
+
- rbx-18mode
|
7
|
+
# - rbx-19mode # Seems to hang, try again another day
|
8
|
+
# Add JRuby support when poltergeist handles JRuby
|
9
|
+
gemfile:
|
10
|
+
- gemfiles/rails-3-2.gemfile
|
11
|
+
- gemfiles/rails-3-1.gemfile
|
12
|
+
- gemfiles/rails-3-0.gemfile
|
13
|
+
before_script:
|
14
|
+
- "export DISPLAY=:99.0"
|
15
|
+
- "sh -e /etc/init.d/xvfb start"
|
data/Appraisals
ADDED
data/Gemfile
ADDED
data/README.md
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
[](http://travis-ci.org/jonleighton/focused_controller)
|
data/Rakefile
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'bundler/setup'
|
2
|
+
require 'appraisal'
|
3
|
+
require "bundler/gem_tasks"
|
4
|
+
require 'rake/testtask'
|
5
|
+
|
6
|
+
namespace :test do
|
7
|
+
Rake::TestTask.new(:acceptance) do |t|
|
8
|
+
t.libs << "test"
|
9
|
+
t.test_files = FileList['test/acceptance/*_test.rb']
|
10
|
+
t.verbose = true
|
11
|
+
end
|
12
|
+
|
13
|
+
Rake::TestTask.new(:unit) do |t|
|
14
|
+
t.libs << "test"
|
15
|
+
t.test_files = FileList['test/unit/*_test.rb']
|
16
|
+
t.verbose = true
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
task :test => ['test:unit', 'test:acceptance']
|
21
|
+
task :default => :test
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "focused_controller/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "focused_controller"
|
7
|
+
s.version = FocusedController::VERSION
|
8
|
+
s.authors = ["Jon Leighton"]
|
9
|
+
s.email = ["j@jonathanleighton.com"]
|
10
|
+
s.homepage = "http://github.com/jonleighton/focused_controller"
|
11
|
+
s.summary = %q{Write Rails controllers that don't violate SRP}
|
12
|
+
s.description = %q{Write Rails controllers that don't violate SRP}
|
13
|
+
|
14
|
+
s.rubyforge_project = "focused_controller"
|
15
|
+
|
16
|
+
s.files = `git ls-files`.split("\n")
|
17
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
18
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
19
|
+
s.require_paths = ["lib"]
|
20
|
+
|
21
|
+
s.add_dependency 'actionpack', '~> 3.0'
|
22
|
+
|
23
|
+
s.add_development_dependency 'minitest', '~> 2.11.2'
|
24
|
+
s.add_development_dependency 'capybara', '~> 1.1.2'
|
25
|
+
s.add_development_dependency 'capybara_minitest_spec', '~> 0.2.1'
|
26
|
+
s.add_development_dependency 'poltergeist', '~> 0.4.0'
|
27
|
+
s.add_development_dependency 'rspec', '~> 2.8.0'
|
28
|
+
s.add_development_dependency 'rspec-rails', '~> 2.8.0'
|
29
|
+
s.add_development_dependency 'appraisal', '~> 0.4.1'
|
30
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'active_support/concern'
|
2
|
+
|
3
|
+
module FocusedController
|
4
|
+
module FunctionalTestHelper
|
5
|
+
def get(*args)
|
6
|
+
super(FocusedController.action_name, *args)
|
7
|
+
end
|
8
|
+
|
9
|
+
def post(*args)
|
10
|
+
super(FocusedController.action_name, *args)
|
11
|
+
end
|
12
|
+
|
13
|
+
def put(*args)
|
14
|
+
super(FocusedController.action_name, *args)
|
15
|
+
end
|
16
|
+
|
17
|
+
def delete(*args)
|
18
|
+
super(FocusedController.action_name, *args)
|
19
|
+
end
|
20
|
+
|
21
|
+
def head(*args)
|
22
|
+
super(FocusedController.action_name, *args)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
require 'focused_controller/action_name'
|
2
|
+
require 'active_support/concern'
|
3
|
+
require 'active_support/core_ext/string/conversions'
|
4
|
+
require 'active_support/core_ext/class/attribute'
|
5
|
+
|
6
|
+
module FocusedController
|
7
|
+
module Mixin
|
8
|
+
extend ActiveSupport::Concern
|
9
|
+
|
10
|
+
included do
|
11
|
+
class_attribute :allow_view_assigns
|
12
|
+
self.allow_view_assigns = false
|
13
|
+
end
|
14
|
+
|
15
|
+
module ClassMethods
|
16
|
+
def controller_path
|
17
|
+
@focused_controller_path ||= name && name.sub(/\:\:[^\:]+$/, '').sub(/Controller$/, '').underscore
|
18
|
+
end
|
19
|
+
|
20
|
+
def call(env)
|
21
|
+
action(FocusedController.action_name).call(env)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def action_name
|
26
|
+
self.class.name.demodulize.underscore
|
27
|
+
end
|
28
|
+
|
29
|
+
def method_for_action(name)
|
30
|
+
FocusedController.action_name
|
31
|
+
end
|
32
|
+
|
33
|
+
def view_assigns
|
34
|
+
if self.class.allow_view_assigns
|
35
|
+
super
|
36
|
+
else
|
37
|
+
{}
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def run
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
require 'focused_controller/action_name'
|
2
|
+
require 'action_dispatch'
|
3
|
+
|
4
|
+
module FocusedController
|
5
|
+
# The monkey-patching in this file makes me sadface but I can't see
|
6
|
+
# another way ;(
|
7
|
+
class RouteMapper
|
8
|
+
def initialize(scope, options)
|
9
|
+
@scope, @options = scope, options
|
10
|
+
end
|
11
|
+
|
12
|
+
def options
|
13
|
+
options = @options.dup
|
14
|
+
|
15
|
+
if to = to_option
|
16
|
+
options[:to] = FocusedController::Route.new(to)
|
17
|
+
options[:action] = FocusedController.action_name # necessary for rails <= 3.1
|
18
|
+
end
|
19
|
+
|
20
|
+
options
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def to_option
|
26
|
+
if @options[:to] && !@options[:to].respond_to?(:call)
|
27
|
+
@options[:to]
|
28
|
+
elsif @options[:action] && @scope[:controller]
|
29
|
+
name = ''
|
30
|
+
name << @scope[:module].camelize << '::' if @scope[:module]
|
31
|
+
name << @scope[:controller].camelize << 'Controller::'
|
32
|
+
name << @options[:action].to_s.camelize
|
33
|
+
name
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
class ActionDispatch::Routing::Mapper
|
39
|
+
def focused_controller_routes(&block)
|
40
|
+
prev, @scope[:focused_controller_routes] = @scope[:focused_controller_routes], true
|
41
|
+
yield
|
42
|
+
ensure
|
43
|
+
@scope[:focused_controller_routes] = false
|
44
|
+
end
|
45
|
+
|
46
|
+
class Mapping
|
47
|
+
def initialize_with_focused_controller(set, scope, path, options)
|
48
|
+
if scope[:focused_controller_routes]
|
49
|
+
options = FocusedController::RouteMapper.new(scope, options).options
|
50
|
+
end
|
51
|
+
|
52
|
+
initialize_without_focused_controller(set, scope, path, options)
|
53
|
+
end
|
54
|
+
|
55
|
+
alias_method_chain :initialize, :focused_controller
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module FocusedController
|
2
|
+
module RSpecControllerClass
|
3
|
+
def controller_class
|
4
|
+
metadata = self.metadata[:example_group]
|
5
|
+
klass = nil
|
6
|
+
|
7
|
+
until metadata.nil? || klass.respond_to?(:new)
|
8
|
+
klass = metadata[:description_args].first
|
9
|
+
metadata = metadata[:example_group]
|
10
|
+
end
|
11
|
+
|
12
|
+
klass.respond_to?(:new) ? klass : super
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'action_controller'
|
2
|
+
require 'action_view'
|
3
|
+
require 'action_dispatch'
|
4
|
+
require 'rspec/rails'
|
5
|
+
require 'focused_controller/functional_test_helper'
|
6
|
+
require 'focused_controller/rspec_controller_class'
|
7
|
+
|
8
|
+
module FocusedController
|
9
|
+
module RSpecFunctionalHelper
|
10
|
+
def self.append_features(base)
|
11
|
+
base.class_eval do
|
12
|
+
# This must be included first
|
13
|
+
include RSpec::Rails::ControllerExampleGroup
|
14
|
+
extend ClassMethods
|
15
|
+
include FocusedController::FunctionalTestHelper
|
16
|
+
end
|
17
|
+
|
18
|
+
super
|
19
|
+
end
|
20
|
+
|
21
|
+
module ClassMethods
|
22
|
+
include FocusedController::RSpecControllerClass
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'focused_controller/test_helper'
|
2
|
+
require 'focused_controller/rspec_controller_class'
|
3
|
+
|
4
|
+
begin
|
5
|
+
# Requiring specific files rather than just 'rspec/rails' because I don't
|
6
|
+
# want to force the configuration that 'rspec/rails' adds on people if they
|
7
|
+
# haven't specifically chosen to receive it.
|
8
|
+
require 'rspec/rails/matchers'
|
9
|
+
require 'rspec/rails/adapters'
|
10
|
+
require 'rspec/rails/example/rails_example_group'
|
11
|
+
rescue LoadError
|
12
|
+
end
|
13
|
+
|
14
|
+
module FocusedController
|
15
|
+
module RSpecHelper
|
16
|
+
def self.append_features(base)
|
17
|
+
base.class_eval do
|
18
|
+
# This must get included higher in the ancestor chain than
|
19
|
+
# this module so that inheritance works as desired
|
20
|
+
include FocusedController::TestHelper
|
21
|
+
extend ClassMethods
|
22
|
+
subject { controller }
|
23
|
+
end
|
24
|
+
|
25
|
+
super
|
26
|
+
end
|
27
|
+
|
28
|
+
if defined?(RSpec::Rails)
|
29
|
+
include RSpec::Rails::RailsExampleGroup
|
30
|
+
include RSpec::Rails::Matchers::RedirectTo
|
31
|
+
include RSpec::Rails::Matchers::RenderTemplate
|
32
|
+
end
|
33
|
+
|
34
|
+
module ClassMethods
|
35
|
+
include FocusedController::RSpecControllerClass
|
36
|
+
|
37
|
+
def stub_url(*helper_names)
|
38
|
+
before { stub_url(*helper_names) }
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,183 @@
|
|
1
|
+
require 'action_dispatch'
|
2
|
+
require 'active_support/concern'
|
3
|
+
require 'active_support/core_ext/class/attribute'
|
4
|
+
require 'active_support/hash_with_indifferent_access'
|
5
|
+
|
6
|
+
module FocusedController
|
7
|
+
module TestHooks
|
8
|
+
attr_reader :_render_options
|
9
|
+
|
10
|
+
def render_to_body(options = {})
|
11
|
+
_process_options(options)
|
12
|
+
@_render_options = options
|
13
|
+
end
|
14
|
+
|
15
|
+
def url_for(options = nil)
|
16
|
+
if options.is_a?(StubbedURL)
|
17
|
+
options
|
18
|
+
else
|
19
|
+
super
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
class TestRequest < ActionDispatch::TestRequest
|
25
|
+
def initialize(env = {})
|
26
|
+
super
|
27
|
+
self.session = HashWithIndifferentAccess.new
|
28
|
+
end
|
29
|
+
|
30
|
+
def cookie_jar
|
31
|
+
@cookie_jar ||= ActionDispatch::Cookies::CookieJar.new
|
32
|
+
end
|
33
|
+
|
34
|
+
def flash
|
35
|
+
session['flash'] ||= ActionDispatch::Flash::FlashHash.new
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
class TestResponse < ActionDispatch::TestResponse
|
40
|
+
end
|
41
|
+
|
42
|
+
class StubbedURL
|
43
|
+
attr_reader :helper_name, :args
|
44
|
+
|
45
|
+
def initialize(helper_name, args)
|
46
|
+
@helper_name = helper_name.to_s
|
47
|
+
@args = args
|
48
|
+
end
|
49
|
+
|
50
|
+
def ==(other)
|
51
|
+
other.is_a?(self.class) &&
|
52
|
+
helper_name == other.helper_name &&
|
53
|
+
args == other.args
|
54
|
+
end
|
55
|
+
|
56
|
+
# Deals with _compute_redirect_to_location in action_controller/metal/redirecting
|
57
|
+
# (I don't feel proud about this...)
|
58
|
+
def gsub(*)
|
59
|
+
self
|
60
|
+
end
|
61
|
+
|
62
|
+
def to_s
|
63
|
+
"#{helper_name}(#{args.each(&:to_s).join(', ')})"
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
module TestHelper
|
68
|
+
extend ActiveSupport::Concern
|
69
|
+
include ActionDispatch::Assertions::ResponseAssertions
|
70
|
+
|
71
|
+
included do
|
72
|
+
class_attribute :_controller_class, :instance_reader => false, :instance_writer => false
|
73
|
+
end
|
74
|
+
|
75
|
+
module ClassMethods
|
76
|
+
def controller_class=(klass)
|
77
|
+
self._controller_class = klass
|
78
|
+
end
|
79
|
+
|
80
|
+
def controller_class
|
81
|
+
_controller_class || name.sub(/Test$/, '').constantize
|
82
|
+
end
|
83
|
+
|
84
|
+
def include_routes
|
85
|
+
if controller_class.respond_to?(:_routes) && controller_class._routes
|
86
|
+
include controller_class._routes.named_routes.module
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
def stub_url(*names)
|
91
|
+
setup { stub_url(*names) }
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
def controller
|
96
|
+
@controller ||= begin
|
97
|
+
controller = self.class.controller_class.new
|
98
|
+
controller.singleton_class.send :include, TestHooks
|
99
|
+
controller.request = request
|
100
|
+
controller.response = response
|
101
|
+
controller
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
def request
|
106
|
+
@request ||= TestRequest.new
|
107
|
+
end
|
108
|
+
|
109
|
+
def response
|
110
|
+
@response ||= TestResponse.new
|
111
|
+
end
|
112
|
+
|
113
|
+
def req(params = nil, session = nil, flash = nil)
|
114
|
+
controller.params = params if params
|
115
|
+
controller.session.update session if session
|
116
|
+
controller.flash.update flash if flash
|
117
|
+
controller.run
|
118
|
+
end
|
119
|
+
|
120
|
+
def session
|
121
|
+
controller.session
|
122
|
+
end
|
123
|
+
|
124
|
+
def flash
|
125
|
+
controller.flash
|
126
|
+
end
|
127
|
+
|
128
|
+
def cookies
|
129
|
+
request.cookie_jar
|
130
|
+
end
|
131
|
+
|
132
|
+
def assert_template(template, message = nil)
|
133
|
+
assert_equal template.to_s, controller._render_options[:template], message
|
134
|
+
end
|
135
|
+
|
136
|
+
def assert_response(type, message = nil)
|
137
|
+
controller # make sure controller is initialized
|
138
|
+
super
|
139
|
+
end
|
140
|
+
|
141
|
+
def assert_redirected_to(location, message = nil)
|
142
|
+
controller # make sure controller is initialized
|
143
|
+
super
|
144
|
+
end
|
145
|
+
|
146
|
+
def url_for(*args)
|
147
|
+
controller.url_for(*args)
|
148
|
+
end
|
149
|
+
|
150
|
+
def respond_to?(method_name)
|
151
|
+
unless defined?(@_routes_included) && @_routes_included
|
152
|
+
self.class.include_routes
|
153
|
+
@_routes_included = true
|
154
|
+
end
|
155
|
+
|
156
|
+
super
|
157
|
+
end
|
158
|
+
|
159
|
+
def method_missing(method_name, *args, &block)
|
160
|
+
if respond_to?(method_name)
|
161
|
+
send(method_name, *args, &block)
|
162
|
+
else
|
163
|
+
super
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
def stub_url(*names)
|
168
|
+
[self, controller].each do |host|
|
169
|
+
host.singleton_class.class_eval do
|
170
|
+
names.each do |name|
|
171
|
+
define_method("#{name}_url") do |*args|
|
172
|
+
StubbedURL.new("#{name}_url", args)
|
173
|
+
end
|
174
|
+
|
175
|
+
define_method("#{name}_path") do |*args|
|
176
|
+
StubbedURL.new("#{name}_path", args)
|
177
|
+
end
|
178
|
+
end
|
179
|
+
end
|
180
|
+
end
|
181
|
+
end
|
182
|
+
end
|
183
|
+
end
|