spin 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 (2) hide show
  1. data/bin/spin +120 -0
  2. metadata +71 -0
data/bin/spin ADDED
@@ -0,0 +1,120 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # Spin will speed up your autotest(ish) workflow for Rails.
4
+
5
+ # Spin preloads your Rails environment for testing, so you don't load the same code over and over and over... Spin works best with an autotest(ish) workflow.
6
+
7
+ require 'socket'
8
+ # This brings in `Dir.tmpdir`
9
+ require 'tempfile'
10
+ # This lets us hash the parameters we want to include in the filename
11
+ # without having to worry about subdirectories, special chars, etc.
12
+ require 'digest/md5'
13
+ # So we can tell users how much time they're saving by preloading their
14
+ # environment.
15
+ require 'benchmark'
16
+
17
+ def usage(stream = $stderr)
18
+ stream.puts <<-USAGE
19
+ Usage: spin serve
20
+ spin push <file>...
21
+ Spin preloads your Rails environment to speed up your autotest(ish) workflow.
22
+ USAGE
23
+
24
+ exit 1
25
+ end
26
+
27
+ def socket_file
28
+ key = Digest::MD5.hexdigest [Dir.pwd, 'spin-gem'].join
29
+ [Dir.tmpdir, key].join('-')
30
+ end
31
+
32
+ def require_relative?
33
+ @require_relative ||= respond_to?(:require_relative)
34
+ end
35
+
36
+ # ## spin serve
37
+ def serve
38
+ file = socket_file
39
+ # We delete the tmp file for the Unix socket if it already exists. The file
40
+ # is scoped to the `pwd`, so if it already exists then it must be from an
41
+ # old run of `spin serve` and can be cleaned up.
42
+ File.delete(file) if File.exist?(file)
43
+ # This socket is how we communicate with `spin push`.
44
+ socket = UNIXServer.open(file)
45
+
46
+ ENV['RAILS_ENV'] = 'test' unless ENV['RAILS_ENV']
47
+
48
+ if File.exist? 'config/application.rb'
49
+ sec = Benchmark.realtime {
50
+ # We require config/application because that file (typically) loads Rails
51
+ # and any Bundler deps, as well as loading the initialization code for
52
+ # the app, but it doesn't actually perform the initialization. That happens
53
+ # in config/environment.
54
+ #
55
+ # In my experience that's the best we can do in terms of preloading. Rails
56
+ # and the gem dependencies rarely change and so don't need to be reloaded.
57
+ # But you can't initialize the application because any non-trivial app will
58
+ # involve it's models/controllers, etc. in its initialization, which you
59
+ # definitely don't want to preload.
60
+ require File.expand_path 'config/application'
61
+ }
62
+ # This is the amount of time that you'll save on each subsequent test run.
63
+ puts "Preloaded Rails env in #{sec}s..."
64
+ else
65
+ warn "Could not find config/application.rb. Are you running this from the root of a Rails project?"
66
+ end
67
+
68
+ loop do
69
+ # Since `spin push` reconnects each time it has a new file for us we just
70
+ # need to accept(2) connections from it.
71
+ conn = socket.accept
72
+ # This should be a relative path to a file.
73
+ file = conn.gets.chomp
74
+
75
+ # We fork(2) before loading the file so that our pristine preloaded
76
+ # environment is untouched. The child process will load whatever code it
77
+ # needs to, then it exits and we're back to the baseline preloaded app.
78
+ fork do
79
+ puts
80
+ puts "Loading #{file}"
81
+
82
+ # We require the full path of the file here in the child process.
83
+ require File.expand_path file
84
+ end
85
+
86
+ # We don't want the parent process handling multiple test runs at the same
87
+ # time because then we'd need to deal with multiple test databases, and
88
+ # that destroys the idea of being simple to use. So we wait(2) until the
89
+ # child process has finished running the test.
90
+ Process.wait
91
+ end
92
+ end
93
+
94
+ # ## spin push
95
+ def push
96
+ # This is the other end of the socket that `spin serve` opens. At this point
97
+ # `spin serve` will accept(2) our connection.
98
+ socket = UNIXSocket.open(socket_file)
99
+ # The filenames that we will spin up to `spin serve` are passed in as
100
+ # arguments.
101
+ files_to_load = ARGV
102
+
103
+ # We reject anything in ARGV that isn't a file that exists. This takes
104
+ # care of scripts that specify files like `spin push -r file.rb`. The `-r`
105
+ # bit will just be ignored.
106
+ files_to_load.select { |f| File.exist?(f) }.each do |f|
107
+ puts "Spinning up #{f}"
108
+ # We put the filename on the socket for the server to read and then load.
109
+ socket.puts f
110
+ end
111
+ rescue Errno::ECONNREFUSED
112
+ abort "Connection was refused. Have you started up `spin serve` yet?"
113
+ end
114
+
115
+ subcommand = ARGV.shift
116
+ case subcommand
117
+ when 'serve' then serve
118
+ when 'push' then push
119
+ else usage
120
+ end
metadata ADDED
@@ -0,0 +1,71 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: spin
3
+ version: !ruby/object:Gem::Version
4
+ hash: 27
5
+ prerelease:
6
+ segments:
7
+ - 0
8
+ - 1
9
+ - 0
10
+ version: 0.1.0
11
+ platform: ruby
12
+ authors:
13
+ - Jesse Storimer
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2011-10-28 00:00:00 -04:00
19
+ default_executable:
20
+ dependencies: []
21
+
22
+ description: |-
23
+ Spin preloads your Rails environment to speed up your autotest(ish) workflow.
24
+
25
+ By preloading your Rails environment for testing you don't load the same code over and over and over... Spin works best for an autotest(ish) workflow.
26
+ email:
27
+ - jstorimer@gmail.com
28
+ executables:
29
+ - spin
30
+ extensions: []
31
+
32
+ extra_rdoc_files: []
33
+
34
+ files:
35
+ - bin/spin
36
+ has_rdoc: true
37
+ homepage: http://jstorimer.github.com/spin
38
+ licenses: []
39
+
40
+ post_install_message:
41
+ rdoc_options: []
42
+
43
+ require_paths:
44
+ - lib
45
+ required_ruby_version: !ruby/object:Gem::Requirement
46
+ none: false
47
+ requirements:
48
+ - - ">="
49
+ - !ruby/object:Gem::Version
50
+ hash: 3
51
+ segments:
52
+ - 0
53
+ version: "0"
54
+ required_rubygems_version: !ruby/object:Gem::Requirement
55
+ none: false
56
+ requirements:
57
+ - - ">="
58
+ - !ruby/object:Gem::Version
59
+ hash: 3
60
+ segments:
61
+ - 0
62
+ version: "0"
63
+ requirements: []
64
+
65
+ rubyforge_project:
66
+ rubygems_version: 1.6.2
67
+ signing_key:
68
+ specification_version: 3
69
+ summary: Spin preloads your Rails environment to speed up your autotest(ish) workflow.
70
+ test_files: []
71
+