rails-dev-tweaks 0.3.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,15 @@
1
+ Copyright (c) 2011 Wavii, inc. http://wavii.com/
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
4
+ documentation files (the "Software"), to deal in the Software without restriction, including without limitation the
5
+ rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit
6
+ persons to whom the Software is furnished to do so, subject to the following conditions:
7
+
8
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the
9
+ Software.
10
+
11
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
12
+ WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
13
+ COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
14
+ OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
15
+
@@ -0,0 +1,97 @@
1
+ # rails-dev-tweaks
2
+ A collection of tweaks to improve your Rails (3.1+) development experience.
3
+
4
+ To install, simply add it to your gemfile:
5
+
6
+ gem 'rails-dev-tweaks', '~> 0.3.1'
7
+
8
+ At the moment, the current tweaks center around speeding up requests by giving granular control over which requests
9
+ cause the Rails autoloader to kick in:
10
+
11
+
12
+ # Granular Autoload
13
+ Rails' autoloading facility is a wonderful help for development mode, but sometimes it's a little overkill and ends up
14
+ hampering your rate of iteration while developing a Rails app. rails-dev-tweaks introduces granular control over which
15
+ kinds of requests are autoloaded.
16
+
17
+ However, why should you use request-based autoload control instead of smart autoloaders that check file modification
18
+ times, such as [rails-dev-boost](https://github.com/thedarkone/rails-dev-boost)? The primary worry with smart
19
+ autoloaders is that they have an extremely difficult time tracking all dependencies of a particular constant. This can
20
+ result in extremely confusing and difficult to debug issues; Theoretically, request-based autoloading should be a bit
21
+ less finicky.
22
+
23
+ You can specify autoload rules for your app via a configuration block in your application or environment configuration.
24
+ These rules are specified via exclusion (`skip`) and inclusion (`keep`). Rules defined later override those defined
25
+ before.
26
+
27
+ config.dev_tweaks.autoload_rules do
28
+ # You can used named matchers (see below). This particular matcher effectively clears any default matchers
29
+ keep :all
30
+
31
+ # Exclude all requests that begin with /search
32
+ skip '/search'
33
+ # But include routes that include smerch
34
+ keep /smerch/
35
+
36
+ # Use a block if you want to inspect the request
37
+ skip {|request| request.post?}
38
+ end
39
+
40
+ The default autoload rules should cover most development patterns:
41
+
42
+ config.dev_tweaks.autoload_rules do
43
+ keep :all
44
+
45
+ skip '/favicon.ico'
46
+ skip :assets
47
+ keep :forced
48
+ end
49
+
50
+ ## Named Matchers
51
+ Named matchers are classes defined under RailsDevTweaks::GranularAutoload::Matchers:: and simply define a call
52
+ method that is given a ActionDispatch::Request and returns true/false on whether that request matches. Match names
53
+ are converted into a module name via "#{name.to\_s.classify}Matcher". E.g. :assets will specify the
54
+ RailsDevTweaks::GranularAutoload::Matchers::AssetMatcher.
55
+
56
+ Any additional arguments given to a `skip` or `keep` call will be passed as initializer arguments to the matcher.
57
+
58
+ ### :all
59
+ Matches every request passed to it.
60
+
61
+ ### :assets
62
+ Rails 3.1 integrated [Sprockets](http://getsprockets.org/) as its asset packager. Unfortunately, since the asset
63
+ packager is mounted using the traditional Rails dispatching infrastructure, it's hidden behind the Rails autoloader
64
+ (unloader). This matcher will match any requests that are routed to Sprockets (specifically any mounted
65
+ Sprockets::Environment instance).
66
+
67
+ _The downside_ to this matcher is that your Rails environment won't reload until you make a regular request to the dev
68
+ server (which should be your usual request pattern, anyway). Assets still reload properly (unless you're referencing
69
+ your application's Ruby code).
70
+
71
+ ### :forced
72
+ To aid in live-debugging when you need to, this matcher will match any request that has `force_autoload` set as a
73
+ parameter (GET or POST), or that has the `Force-Autoload` header set to something.
74
+
75
+ If you are live-debugging jQuery ajax requests, this helpful snippet will turn on forced autoloading for the remainder
76
+ of the browser's session:
77
+
78
+ $.ajaxSetup({"beforeSend": function(xhr) {xhr.setRequestHeader("Force-Autoload", "true")} })
79
+
80
+ ### :path
81
+ Matches the path of the request via a regular expression.
82
+
83
+ keep :path, /thing/ # Match any request with "thing" in the path.
84
+
85
+ Note that `keep '/stuff'` is just shorthand for `keep :path, /^\/stuff/`. Similarly, `keep /thing/` is shorthand for
86
+ `keep :path, /thing/`
87
+
88
+ ### :xhr
89
+ Matches any XHR request (via request.xhr?). The assumption here is that you generally don't live-debug your XHR
90
+ requests, and are instead refreshing the page that kicks them off before running against new response code.
91
+
92
+
93
+ # License
94
+ rails-dev-tweaks is MIT licensed by Wavii, Inc. http://wavii.com
95
+
96
+ See the accompanying file, `MIT-LICENSE`, for the full text.
97
+
@@ -0,0 +1,2 @@
1
+ require 'bundler/gem_tasks'
2
+
@@ -0,0 +1,14 @@
1
+ require 'active_support'
2
+ require 'active_support/dependencies'
3
+
4
+ module RailsDevTweaks
5
+ LIB_PATH = File.expand_path('..', __FILE__)
6
+ end
7
+
8
+ # Ironically, we use autoloading ourselves to enforce our file structure, and less typing.
9
+ ActiveSupport::Dependencies.autoload_paths << RailsDevTweaks::LIB_PATH
10
+ ActiveSupport::Dependencies.autoload_once_paths << RailsDevTweaks::LIB_PATH # But don't allow *auto-reloading*!
11
+
12
+ # Reference the railtie to force it to load
13
+ RailsDevTweaks::Railtie
14
+
@@ -0,0 +1,82 @@
1
+ class RailsDevTweaks::Configuration
2
+
3
+ attr_reader :granular_autoload_config
4
+
5
+ def initialize
6
+ @granular_autoload_config = GranularAutoloadConfiguration.new
7
+
8
+ # And set our defaults
9
+ self.autoload_rules do
10
+ keep :all
11
+
12
+ skip '/favicon.ico'
13
+ skip :assets
14
+ keep :forced
15
+ end
16
+ end
17
+
18
+ # Takes a block that configures the granular autoloader's rules.
19
+ def autoload_rules(&block)
20
+ @granular_autoload_config.instance_eval(&block)
21
+ end
22
+
23
+ class GranularAutoloadConfiguration
24
+
25
+ def initialize
26
+ # Each rule is a simple pair: [:skip, callable], [:keep, callable], etc.
27
+ @rules = []
28
+ end
29
+
30
+ def keep(*args, &block)
31
+ self.append_rule(:keep, *args, &block)
32
+ end
33
+
34
+ def skip(*args, &block)
35
+ self.append_rule(:skip, *args, &block)
36
+ end
37
+
38
+ def append_rule(rule_type, *args, &block)
39
+ unless rule_type == :skip || rule_type == :keep
40
+ raise TypeError, "Rule must be :skip or :keep. Got: #{rule_type.inspect}"
41
+ end
42
+
43
+ # Simple matcher blocks
44
+ if args.size == 0 && block.present?
45
+ @rules.unshift [rule_type, block]
46
+ return self
47
+ end
48
+
49
+ # String match shorthand
50
+ args[0] = /^#{args[0]}/ if args.size == 1 && args[0].kind_of?(String)
51
+
52
+ # Regex match shorthand
53
+ args = [:path, args[0]] if args.size == 1 && args[0].kind_of?(Regexp)
54
+
55
+ if args.size == 0 && block.blank?
56
+ raise TypeError, 'Cannot process autoload rule as specified. Expecting a named matcher (symbol), path prefix (string) or block'
57
+ end
58
+
59
+ # Named matcher
60
+ matcher_class = "RailsDevTweaks::GranularAutoload::Matchers::#{args[0].to_s.classify}Matcher".constantize
61
+ matcher = matcher_class.new(*args[1..-1])
62
+ raise TypeError, "Matchers must respond to :call. #{matcher.inspect} does not." unless matcher.respond_to? :call
63
+
64
+ @rules.unshift [rule_type, matcher]
65
+
66
+ self
67
+ end
68
+
69
+ def should_reload?(request)
70
+ @rules.each do |rule_type, callable|
71
+ return rule_type == :keep if callable.call(request)
72
+ end
73
+
74
+ # We default to reloading to preserve behavior, but we should never get to this unless the configuration is
75
+ # all sorts of horked.
76
+ true
77
+ end
78
+
79
+ end
80
+
81
+ end
82
+
@@ -0,0 +1,8 @@
1
+ class RailsDevTweaks::GranularAutoload::Matchers::AllMatcher
2
+
3
+ def call(request)
4
+ true
5
+ end
6
+
7
+ end
8
+
@@ -0,0 +1,29 @@
1
+ class RailsDevTweaks::GranularAutoload::Matchers::AssetMatcher
2
+
3
+ def call(request)
4
+ main_mount = request.headers['action_dispatch.routes'].set.recognize(request)
5
+
6
+ # Unwind until we have an actual app
7
+ while main_mount != nil
8
+ if main_mount.kind_of? Array
9
+ main_mount = main_mount.first
10
+
11
+ elsif main_mount.kind_of? Rack::Mount::Route
12
+ main_mount = main_mount.app
13
+
14
+ elsif main_mount.kind_of? Rack::Mount::Prefix
15
+ # Bah, no accessor here
16
+ main_mount = main_mount.instance_variable_get(:@app)
17
+
18
+ # Well, we got something
19
+ else
20
+ break
21
+ end
22
+ end
23
+
24
+ # what do we have?
25
+ main_mount.kind_of? Sprockets::Environment
26
+ end
27
+
28
+ end
29
+
@@ -0,0 +1,8 @@
1
+ class RailsDevTweaks::GranularAutoload::Matchers::ForcedMatcher
2
+
3
+ def call(request)
4
+ request.headers['Force-Autoload'] || request.params.has_key?(:force_autoload)
5
+ end
6
+
7
+ end
8
+
@@ -0,0 +1,12 @@
1
+ class RailsDevTweaks::GranularAutoload::Matchers::PathMatcher
2
+
3
+ def initialize(regex)
4
+ @regex = regex
5
+ end
6
+
7
+ def call(request)
8
+ @regex =~ request.fullpath
9
+ end
10
+
11
+ end
12
+
@@ -0,0 +1,8 @@
1
+ class RailsDevTweaks::GranularAutoload::Matchers::XhrMatcher
2
+
3
+ def call(request)
4
+ request.xhr?
5
+ end
6
+
7
+ end
8
+
@@ -0,0 +1,37 @@
1
+ # Here's an idea, let's not reload the entire dev environment for each asset request. Let's only do that on regular
2
+ # content requests.
3
+ class RailsDevTweaks::GranularAutoload::Middleware
4
+
5
+ # Don't cleanup before the very first request
6
+ class << self
7
+ attr_writer :processed_a_request
8
+ def processed_a_request?
9
+ @processed_a_request
10
+ end
11
+ end
12
+
13
+ def initialize(app)
14
+ @app = app
15
+ end
16
+
17
+ def call(env)
18
+ request = ActionDispatch::Request.new(env.dup)
19
+
20
+ # reload, or no?
21
+ if Rails.application.config.dev_tweaks.granular_autoload_config.should_reload?(request)
22
+ # Confusingly, we flip the request prepare/cleanup life cycle around so that we're only cleaning up on those
23
+ # requests that want to be reloaded
24
+ if self.class.processed_a_request? # No-op if this is the first request. The initializers take care of that one.
25
+ ActionDispatch::Reloader.cleanup!
26
+ ActionDispatch::Reloader.prepare!
27
+ end
28
+ self.class.processed_a_request = true
29
+
30
+ else
31
+ Rails.logger.info 'RailsDevTweaks: Skipping ActionDispatch::Reloader hooks for this request.'
32
+ end
33
+
34
+ return @app.call(env)
35
+ end
36
+ end
37
+
@@ -0,0 +1,14 @@
1
+ class RailsDevTweaks::Railtie < Rails::Railtie
2
+
3
+ config.dev_tweaks = RailsDevTweaks::Configuration.new
4
+
5
+ config.before_initialize do |app|
6
+ # We can't inspect the stack because it's deferred... For now, just assume we have it when config.cache_clasess is
7
+ # falsy; which should always be the case in the current version of rails anyway.
8
+ unless app.config.cache_classes
9
+ app.config.middleware.swap ActionDispatch::Reloader, RailsDevTweaks::GranularAutoload::Middleware
10
+ end
11
+ end
12
+
13
+ end
14
+
@@ -0,0 +1,4 @@
1
+ module RailsDevTweaks
2
+ VERSION = '0.3.1'
3
+ end
4
+
metadata ADDED
@@ -0,0 +1,77 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rails-dev-tweaks
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.3.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Wavii, Inc.
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2011-07-12 00:00:00.000000000 -07:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: rails
17
+ requirement: &2167156100 !ruby/object:Gem::Requirement
18
+ none: false
19
+ requirements:
20
+ - - ~>
21
+ - !ruby/object:Gem::Version
22
+ version: 3.1.0.rc4
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: *2167156100
26
+ description: A collection of tweaks to improve your Rails (3.1+) development experience.
27
+ email:
28
+ - info@wavii.com
29
+ executables: []
30
+ extensions: []
31
+ extra_rdoc_files: []
32
+ files:
33
+ - lib/rails-dev-tweaks.rb
34
+ - lib/rails_dev_tweaks/configuration.rb
35
+ - lib/rails_dev_tweaks/granular_autoload/matchers/all_matcher.rb
36
+ - lib/rails_dev_tweaks/granular_autoload/matchers/asset_matcher.rb
37
+ - lib/rails_dev_tweaks/granular_autoload/matchers/forced_matcher.rb
38
+ - lib/rails_dev_tweaks/granular_autoload/matchers/path_matcher.rb
39
+ - lib/rails_dev_tweaks/granular_autoload/matchers/xhr_matcher.rb
40
+ - lib/rails_dev_tweaks/granular_autoload/middleware.rb
41
+ - lib/rails_dev_tweaks/railtie.rb
42
+ - lib/rails_dev_tweaks/version.rb
43
+ - MIT-LICENSE
44
+ - Rakefile
45
+ - README.md
46
+ has_rdoc: true
47
+ homepage: http://wavii.com/
48
+ licenses: []
49
+ post_install_message:
50
+ rdoc_options: []
51
+ require_paths:
52
+ - lib
53
+ required_ruby_version: !ruby/object:Gem::Requirement
54
+ none: false
55
+ requirements:
56
+ - - ! '>='
57
+ - !ruby/object:Gem::Version
58
+ version: '0'
59
+ segments:
60
+ - 0
61
+ hash: -1289302315746076260
62
+ required_rubygems_version: !ruby/object:Gem::Requirement
63
+ none: false
64
+ requirements:
65
+ - - ! '>='
66
+ - !ruby/object:Gem::Version
67
+ version: '0'
68
+ segments:
69
+ - 0
70
+ hash: -1289302315746076260
71
+ requirements: []
72
+ rubyforge_project: rails-dev-tweaks
73
+ rubygems_version: 1.6.2
74
+ signing_key:
75
+ specification_version: 3
76
+ summary: A collection of tweaks to improve your Rails (3.1+) development experience.
77
+ test_files: []