rails-dev-tweaks 0.3.1
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/MIT-LICENSE +15 -0
- data/README.md +97 -0
- data/Rakefile +2 -0
- data/lib/rails-dev-tweaks.rb +14 -0
- data/lib/rails_dev_tweaks/configuration.rb +82 -0
- data/lib/rails_dev_tweaks/granular_autoload/matchers/all_matcher.rb +8 -0
- data/lib/rails_dev_tweaks/granular_autoload/matchers/asset_matcher.rb +29 -0
- data/lib/rails_dev_tweaks/granular_autoload/matchers/forced_matcher.rb +8 -0
- data/lib/rails_dev_tweaks/granular_autoload/matchers/path_matcher.rb +12 -0
- data/lib/rails_dev_tweaks/granular_autoload/matchers/xhr_matcher.rb +8 -0
- data/lib/rails_dev_tweaks/granular_autoload/middleware.rb +37 -0
- data/lib/rails_dev_tweaks/railtie.rb +14 -0
- data/lib/rails_dev_tweaks/version.rb +4 -0
- metadata +77 -0
data/MIT-LICENSE
ADDED
@@ -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
|
+
|
data/README.md
ADDED
@@ -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
|
+
|
data/Rakefile
ADDED
@@ -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,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,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
|
+
|
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: []
|