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.
Files changed (87) hide show
  1. data/.gitignore +5 -0
  2. data/.travis.yml +15 -0
  3. data/Appraisals +11 -0
  4. data/Gemfile +4 -0
  5. data/README.md +1 -0
  6. data/Rakefile +21 -0
  7. data/focused_controller.gemspec +30 -0
  8. data/gemfiles/rails-3-0.gemfile +7 -0
  9. data/gemfiles/rails-3-1.gemfile +7 -0
  10. data/gemfiles/rails-3-2.gemfile +7 -0
  11. data/lib/focused_controller.rb +4 -0
  12. data/lib/focused_controller/action_name.rb +6 -0
  13. data/lib/focused_controller/functional_test_helper.rb +25 -0
  14. data/lib/focused_controller/mixin.rb +44 -0
  15. data/lib/focused_controller/route.rb +15 -0
  16. data/lib/focused_controller/route_mapper.rb +58 -0
  17. data/lib/focused_controller/rspec_controller_class.rb +15 -0
  18. data/lib/focused_controller/rspec_functional_helper.rb +25 -0
  19. data/lib/focused_controller/rspec_helper.rb +42 -0
  20. data/lib/focused_controller/test_helper.rb +183 -0
  21. data/lib/focused_controller/version.rb +3 -0
  22. data/test/acceptance/app_test.rb +156 -0
  23. data/test/app/.gitignore +15 -0
  24. data/test/app/Gemfile +6 -0
  25. data/test/app/README.rdoc +261 -0
  26. data/test/app/Rakefile +7 -0
  27. data/test/app/app/controllers/application_controller.rb +6 -0
  28. data/test/app/app/controllers/posts_controller.rb +60 -0
  29. data/test/app/app/models/.gitkeep +0 -0
  30. data/test/app/app/models/post.rb +88 -0
  31. data/test/app/app/views/layouts/application.html.erb +13 -0
  32. data/test/app/app/views/posts/_form.html.erb +31 -0
  33. data/test/app/app/views/posts/edit.html.erb +6 -0
  34. data/test/app/app/views/posts/index.html.erb +23 -0
  35. data/test/app/app/views/posts/new.html.erb +5 -0
  36. data/test/app/app/views/posts/show.html.erb +8 -0
  37. data/test/app/config.ru +4 -0
  38. data/test/app/config/application.rb +16 -0
  39. data/test/app/config/boot.rb +6 -0
  40. data/test/app/config/environment.rb +5 -0
  41. data/test/app/config/environments/development.rb +21 -0
  42. data/test/app/config/environments/test.rb +29 -0
  43. data/test/app/config/initializers/backtrace_silencers.rb +7 -0
  44. data/test/app/config/initializers/inflections.rb +15 -0
  45. data/test/app/config/initializers/mime_types.rb +5 -0
  46. data/test/app/config/initializers/secret_token.rb +7 -0
  47. data/test/app/config/initializers/session_store.rb +8 -0
  48. data/test/app/config/locales/en.yml +5 -0
  49. data/test/app/config/routes.rb +62 -0
  50. data/test/app/db/seeds.rb +7 -0
  51. data/test/app/doc/README_FOR_APP +2 -0
  52. data/test/app/lib/assets/.gitkeep +0 -0
  53. data/test/app/lib/tasks/.gitkeep +0 -0
  54. data/test/app/log/.gitkeep +0 -0
  55. data/test/app/public/404.html +26 -0
  56. data/test/app/public/422.html +26 -0
  57. data/test/app/public/500.html +25 -0
  58. data/test/app/public/favicon.ico +0 -0
  59. data/test/app/public/index.html +241 -0
  60. data/test/app/public/javascripts/application.js +9663 -0
  61. data/test/app/public/robots.txt +5 -0
  62. data/test/app/public/stylesheets/application.css +83 -0
  63. data/test/app/script/rails +6 -0
  64. data/test/app/spec/controllers/posts_controller_spec.rb +59 -0
  65. data/test/app/spec/isolated_spec_helper.rb +9 -0
  66. data/test/app/spec/spec_helper.rb +5 -0
  67. data/test/app/spec/unit/controllers/posts_controller_isolated_spec.rb +60 -0
  68. data/test/app/spec/unit/controllers/posts_controller_spec.rb +59 -0
  69. data/test/app/test/functional/.gitkeep +0 -0
  70. data/test/app/test/functional/posts_controller_test.rb +67 -0
  71. data/test/app/test/isolated_test_helper.rb +10 -0
  72. data/test/app/test/test_helper.rb +6 -0
  73. data/test/app/test/unit/.gitkeep +0 -0
  74. data/test/app/test/unit/controllers/posts_controller_isolated_test.rb +69 -0
  75. data/test/app/test/unit/controllers/posts_controller_test.rb +67 -0
  76. data/test/app/vendor/assets/javascripts/.gitkeep +0 -0
  77. data/test/app/vendor/assets/stylesheets/.gitkeep +0 -0
  78. data/test/app/vendor/plugins/.gitkeep +0 -0
  79. data/test/helper.rb +33 -0
  80. data/test/unit/functional_test_helper_test.rb +65 -0
  81. data/test/unit/mixin_test.rb +70 -0
  82. data/test/unit/route_mapper_test.rb +73 -0
  83. data/test/unit/route_test.rb +39 -0
  84. data/test/unit/rspec_functional_helper.rb +42 -0
  85. data/test/unit/rspec_helper_test.rb +91 -0
  86. data/test/unit/test_helper_test.rb +235 -0
  87. metadata +285 -0
data/.gitignore ADDED
@@ -0,0 +1,5 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
5
+ /gemfiles/*.lock
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
@@ -0,0 +1,11 @@
1
+ appraise 'rails-3-2' do
2
+ gem 'rails', '~> 3.2.0'
3
+ end
4
+
5
+ appraise 'rails-3-1' do
6
+ gem 'rails', '~> 3.1.0'
7
+ end
8
+
9
+ appraise 'rails-3-0' do
10
+ gem 'rails', '~> 3.0.0'
11
+ end
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in focused_controller.gemspec
4
+ gemspec
data/README.md ADDED
@@ -0,0 +1 @@
1
+ [![Build Status](https://secure.travis-ci.org/jonleighton/focused_controller.png?branch=master)](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,7 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "http://rubygems.org"
4
+
5
+ gem "rails", "~> 3.0.0"
6
+
7
+ gemspec :path=>"../"
@@ -0,0 +1,7 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "http://rubygems.org"
4
+
5
+ gem "rails", "~> 3.1.0"
6
+
7
+ gemspec :path=>"../"
@@ -0,0 +1,7 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "http://rubygems.org"
4
+
5
+ gem "rails", "~> 3.2.0"
6
+
7
+ gemspec :path=>"../"
@@ -0,0 +1,4 @@
1
+ require 'focused_controller/version'
2
+ require 'focused_controller/route'
3
+ require 'focused_controller/mixin'
4
+ require 'focused_controller/route_mapper'
@@ -0,0 +1,6 @@
1
+ module FocusedController
2
+ class << self
3
+ attr_accessor :action_name
4
+ end
5
+ self.action_name = 'run'
6
+ 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,15 @@
1
+ module FocusedController
2
+ class Route
3
+ attr_reader :name
4
+
5
+ def initialize(name)
6
+ @name = name
7
+ end
8
+
9
+ def call(env)
10
+ name.constantize.call(env)
11
+ end
12
+
13
+ alias to_s name
14
+ end
15
+ 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