spring 0.0.7 → 0.0.8
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/CHANGELOG.md +11 -0
- data/Gemfile +4 -0
- data/README.md +49 -24
- data/lib/spring/application.rb +30 -30
- data/lib/spring/application_manager.rb +34 -15
- data/lib/spring/client.rb +9 -7
- data/lib/spring/client/binstub.rb +8 -3
- data/lib/spring/client/help.rb +20 -32
- data/lib/spring/client/rails.rb +29 -0
- data/lib/spring/client/run.rb +55 -51
- data/lib/spring/client/start.rb +17 -0
- data/lib/spring/client/status.rb +1 -1
- data/lib/spring/client/stop.rb +1 -1
- data/lib/spring/commands.rb +36 -20
- data/lib/spring/errors.rb +3 -0
- data/lib/spring/server.rb +36 -12
- data/lib/spring/version.rb +1 -1
- data/lib/spring/watcher.rb +28 -0
- data/lib/spring/watcher/abstract.rb +83 -0
- data/lib/spring/watcher/listen.rb +54 -0
- data/lib/spring/watcher/polling.rb +59 -0
- data/test/acceptance/app_test.rb +62 -32
- data/test/apps/rails-3-2/Gemfile +5 -0
- data/test/unit/client/help_test.rb +27 -19
- data/test/unit/commands_test.rb +26 -1
- data/test/unit/watcher_test.rb +171 -0
- metadata +12 -6
- data/lib/spring/application_watcher.rb +0 -43
- data/test/unit/application_watcher_test.rb +0 -67
    
        data/CHANGELOG.md
    ADDED
    
    | @@ -0,0 +1,11 @@ | |
| 1 | 
            +
            ## 0.0.8
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            * Renamed `spring test` to `spring testunit`.
         | 
| 4 | 
            +
            * Implemented `spring rails` to replace `spring
         | 
| 5 | 
            +
              [console|runner|generate]`.
         | 
| 6 | 
            +
            * `config/spring.rb` is only loaded in the server process, so you can
         | 
| 7 | 
            +
              require stuff from other gems there without performance implications.
         | 
| 8 | 
            +
            * File watcher no longer pays attention to files outside of your
         | 
| 9 | 
            +
              application root directory.
         | 
| 10 | 
            +
            * You can use the `listen` gem for less CPU intensive file watching. See
         | 
| 11 | 
            +
              README.
         | 
    
        data/Gemfile
    CHANGED
    
    
    
        data/README.md
    CHANGED
    
    | @@ -67,7 +67,7 @@ cd /path/to/spring/test/apps/rails-3-2 | |
| 67 67 | 
             
            We can run a test:
         | 
| 68 68 |  | 
| 69 69 | 
             
            ```
         | 
| 70 | 
            -
            $ time spring  | 
| 70 | 
            +
            $ time spring testunit test/functional/posts_controller_test.rb
         | 
| 71 71 | 
             
            Run options:
         | 
| 72 72 |  | 
| 73 73 | 
             
            # Running tests:
         | 
| @@ -100,7 +100,7 @@ the processes will be killed automatically. | |
| 100 100 | 
             
            Running the test is faster next time:
         | 
| 101 101 |  | 
| 102 102 | 
             
            ```
         | 
| 103 | 
            -
            $ time spring  | 
| 103 | 
            +
            $ time spring testunit test/functional/posts_controller_test.rb
         | 
| 104 104 | 
             
            Run options:
         | 
| 105 105 |  | 
| 106 106 | 
             
            # Running tests:
         | 
| @@ -116,25 +116,25 @@ user	0m0.276s | |
| 116 116 | 
             
            sys	0m0.059s
         | 
| 117 117 | 
             
            ```
         | 
| 118 118 |  | 
| 119 | 
            -
            Running `spring  | 
| 119 | 
            +
            Running `spring testunit`, `spring rake`, `spring rails`, etc gets a bit
         | 
| 120 120 | 
             
            tedious. It also suffers from a performance issue in Rubygems ([which I
         | 
| 121 121 | 
             
            am actively working on](https://github.com/rubygems/rubygems/pull/435))
         | 
| 122 122 | 
             
            which means the `spring` command takes a while to start up. The more
         | 
| 123 123 | 
             
            gems you have, the longer it takes.
         | 
| 124 124 |  | 
| 125 125 | 
             
            Spring binstubs solve both of these problems. If you will be running the
         | 
| 126 | 
            -
            ` | 
| 126 | 
            +
            `testunit` command regularly, run:
         | 
| 127 127 |  | 
| 128 128 | 
             
            ```
         | 
| 129 | 
            -
            $ spring binstub  | 
| 129 | 
            +
            $ spring binstub testunit
         | 
| 130 130 | 
             
            ```
         | 
| 131 131 |  | 
| 132 | 
            -
            This generates a `bin/spring` and a `bin/ | 
| 133 | 
            -
            `spring` and `spring  | 
| 132 | 
            +
            This generates a `bin/spring` and a `bin/testunit`, which allows you to run
         | 
| 133 | 
            +
            `spring` and `spring testunit` in a way that doesn't trigger the Rubygems
         | 
| 134 134 | 
             
            performance bug:
         | 
| 135 135 |  | 
| 136 136 | 
             
            ```
         | 
| 137 | 
            -
            $ time bin/ | 
| 137 | 
            +
            $ time bin/testunit test/functional/posts_controller_test.rb
         | 
| 138 138 | 
             
            Run options:
         | 
| 139 139 |  | 
| 140 140 | 
             
            # Running tests:
         | 
| @@ -150,6 +150,10 @@ user	0m0.077s | |
| 150 150 | 
             
            sys	0m0.059s
         | 
| 151 151 | 
             
            ```
         | 
| 152 152 |  | 
| 153 | 
            +
            You can add "./bin" to your `PATH` when in your application's directory
         | 
| 154 | 
            +
            [with direnv](https://github.com/zimbatm/direnv), but you should
         | 
| 155 | 
            +
            recognise and understand the security implications of using that.
         | 
| 156 | 
            +
             | 
| 153 157 | 
             
            If we edit any of the application files, or test files, the change will
         | 
| 154 158 | 
             
            be picked up on the next run, without the background process
         | 
| 155 159 | 
             
            having to be restarted.
         | 
| @@ -220,12 +224,12 @@ order to make it easy for people to try spring. However in the future | |
| 220 224 | 
             
            the code to use a specific test framework should not be contained in the
         | 
| 221 225 | 
             
            spring repository.
         | 
| 222 226 |  | 
| 223 | 
            -
            ### ` | 
| 227 | 
            +
            ### `testunit`
         | 
| 224 228 |  | 
| 225 229 | 
             
            Runs a test (e.g. Test::Unit, MiniTest::Unit, etc.) Preloads the `test_helper` file.
         | 
| 226 230 |  | 
| 227 231 | 
             
            This command can also recursively run a directory of tests. For example,
         | 
| 228 | 
            -
            `spring  | 
| 232 | 
            +
            `spring testunit test/functional` will run `test/functional/**/*_test.rb`.
         | 
| 229 233 |  | 
| 230 234 | 
             
            ### `rspec`
         | 
| 231 235 |  | 
| @@ -240,19 +244,12 @@ Runs a cucumber feature. | |
| 240 244 |  | 
| 241 245 | 
             
            Runs a rake task.
         | 
| 242 246 |  | 
| 243 | 
            -
            ### `console`
         | 
| 244 | 
            -
             | 
| 245 | 
            -
            Boots into the Rails console. Currently this is usable but not perfect,
         | 
| 246 | 
            -
            for example you can't scroll back through command history. (That will be
         | 
| 247 | 
            -
            fixed.)
         | 
| 248 | 
            -
             | 
| 249 | 
            -
            ### `generate`
         | 
| 250 | 
            -
             | 
| 251 | 
            -
            Runs a Rails generator.
         | 
| 252 | 
            -
             | 
| 253 | 
            -
            ### `runner`
         | 
| 247 | 
            +
            ### `rails console`, `rails generate`, `rails runner`
         | 
| 254 248 |  | 
| 255 | 
            -
             | 
| 249 | 
            +
            These execute the rails command you already know and love. If you run
         | 
| 250 | 
            +
            a different sub command (e.g. `rails server`) then spring will automatically
         | 
| 251 | 
            +
            pass it through to the underlying `rails` executable (without the
         | 
| 252 | 
            +
            speed-up).
         | 
| 256 253 |  | 
| 257 254 | 
             
            ## Configuration
         | 
| 258 255 |  | 
| @@ -279,13 +276,13 @@ preloads for every command: | |
| 279 276 |  | 
| 280 277 | 
             
            ```ruby
         | 
| 281 278 | 
             
            # if your test helper is called "helper"
         | 
| 282 | 
            -
            Commands::Command:: | 
| 279 | 
            +
            Commands::Command::TestUnit.preloads = %w(helper)
         | 
| 283 280 |  | 
| 284 281 | 
             
            # if you don't want to preload spec_helper.rb
         | 
| 285 282 | 
             
            Commands::Command::RSpec.preloads = []
         | 
| 286 283 |  | 
| 287 284 | 
             
            # if you want to preload additional files for the console
         | 
| 288 | 
            -
            Commands::Command:: | 
| 285 | 
            +
            Commands::Command::RailsConsole.preloads << 'extenstions/console_helper'
         | 
| 289 286 | 
             
            ```
         | 
| 290 287 |  | 
| 291 288 | 
             
            ### after fork callbacks
         | 
| @@ -308,3 +305,31 @@ If you want to register multiple callbacks you can simply call | |
| 308 305 |  | 
| 309 306 | 
             
            Spring needs a tmp directory. This will default to `Rails.root.join('tmp', 'spring')`.
         | 
| 310 307 | 
             
            You can set your own configuration directory by setting the `SPRING_TMP_PATH` environment variable.
         | 
| 308 | 
            +
             | 
| 309 | 
            +
            ### Watching files and directories
         | 
| 310 | 
            +
             | 
| 311 | 
            +
            As mentioned above, Spring will automatically detect file changes to any file loaded when the server
         | 
| 312 | 
            +
            boots. If you would like to watch additional files or directories, use
         | 
| 313 | 
            +
            `Spring.watch`:
         | 
| 314 | 
            +
             | 
| 315 | 
            +
            ```ruby
         | 
| 316 | 
            +
            Spring.watch "#{Rails.root}/spec/factories"
         | 
| 317 | 
            +
            ```
         | 
| 318 | 
            +
             | 
| 319 | 
            +
            ### Filesystem polling
         | 
| 320 | 
            +
             | 
| 321 | 
            +
            By default Spring will check the filesystem for changes once every 0.2 seconds. This
         | 
| 322 | 
            +
            method requires zero configuration, but if you find that it's using too
         | 
| 323 | 
            +
            much CPU, then you can turn on event-based file system listening by
         | 
| 324 | 
            +
            adding the following to to your `Gemfile`:
         | 
| 325 | 
            +
             | 
| 326 | 
            +
            ```ruby
         | 
| 327 | 
            +
            group :development, :test do
         | 
| 328 | 
            +
              gem 'listen'
         | 
| 329 | 
            +
              gem 'rb-inotify', :require => false  # linux
         | 
| 330 | 
            +
              gem 'rb-fsevent', :require => false  # mac os x
         | 
| 331 | 
            +
              gem 'rb-kqueue',  :require => false  # bsd
         | 
| 332 | 
            +
            end
         | 
| 333 | 
            +
            ```
         | 
| 334 | 
            +
             | 
| 335 | 
            +
            Note that this make the initial application startup slightly slower.
         | 
    
        data/lib/spring/application.rb
    CHANGED
    
    | @@ -1,24 +1,21 @@ | |
| 1 | 
            -
            require "spring/configuration"
         | 
| 2 | 
            -
            require "spring/application_watcher"
         | 
| 3 | 
            -
            require "spring/commands"
         | 
| 4 1 | 
             
            require "set"
         | 
| 2 | 
            +
            require "json"
         | 
| 5 3 |  | 
| 6 | 
            -
             | 
| 7 | 
            -
             | 
| 8 | 
            -
                attr_accessor :application_watcher
         | 
| 9 | 
            -
              end
         | 
| 10 | 
            -
             | 
| 11 | 
            -
              self.application_watcher = ApplicationWatcher.new
         | 
| 4 | 
            +
            require "spring/configuration"
         | 
| 5 | 
            +
            require "spring/watcher"
         | 
| 12 6 |  | 
| 7 | 
            +
            module Spring
         | 
| 13 8 | 
             
              class Application
         | 
| 14 | 
            -
                WATCH_INTERVAL = 0.2
         | 
| 15 | 
            -
             | 
| 16 9 | 
             
                attr_reader :manager, :watcher
         | 
| 17 10 |  | 
| 18 | 
            -
                def initialize(manager, watcher = Spring. | 
| 11 | 
            +
                def initialize(manager, watcher = Spring.watcher)
         | 
| 19 12 | 
             
                  @manager = manager
         | 
| 20 13 | 
             
                  @watcher = watcher
         | 
| 21 14 | 
             
                  @setup   = Set.new
         | 
| 15 | 
            +
             | 
| 16 | 
            +
                  # Workaround for GC bug in Ruby 2 which causes segfaults if watcher.to_io
         | 
| 17 | 
            +
                  # instances get dereffed.
         | 
| 18 | 
            +
                  @fds = [manager, watcher.to_io]
         | 
| 22 19 | 
             
                end
         | 
| 23 20 |  | 
| 24 21 | 
             
                def start
         | 
| @@ -33,31 +30,33 @@ module Spring | |
| 33 30 |  | 
| 34 31 | 
             
                  require Spring.application_root_path.join("config", "environment")
         | 
| 35 32 |  | 
| 36 | 
            -
                  watcher. | 
| 37 | 
            -
                  watcher. | 
| 38 | 
            -
                  watcher. | 
| 33 | 
            +
                  watcher.add loaded_application_features
         | 
| 34 | 
            +
                  watcher.add "Gemfile", "Gemfile.lock"
         | 
| 35 | 
            +
                  watcher.add Rails.application.paths["config/initializers"]
         | 
| 39 36 |  | 
| 40 37 | 
             
                  run
         | 
| 41 38 | 
             
                end
         | 
| 42 39 |  | 
| 43 40 | 
             
                def run
         | 
| 41 | 
            +
                  watcher.start
         | 
| 42 | 
            +
             | 
| 44 43 | 
             
                  loop do
         | 
| 45 | 
            -
                     | 
| 46 | 
            -
                    serve manager.recv_io(UNIXSocket)
         | 
| 47 | 
            -
                  end
         | 
| 48 | 
            -
                end
         | 
| 44 | 
            +
                    IO.select(@fds)
         | 
| 49 45 |  | 
| 50 | 
            -
             | 
| 51 | 
            -
             | 
| 52 | 
            -
                     | 
| 46 | 
            +
                    if watcher.stale?
         | 
| 47 | 
            +
                      exit
         | 
| 48 | 
            +
                    else
         | 
| 49 | 
            +
                      serve manager.recv_io(UNIXSocket)
         | 
| 50 | 
            +
                    end
         | 
| 53 51 | 
             
                  end
         | 
| 54 52 | 
             
                end
         | 
| 55 53 |  | 
| 56 54 | 
             
                def serve(client)
         | 
| 57 | 
            -
                   | 
| 58 | 
            -
             | 
| 59 | 
            -
                   | 
| 60 | 
            -
                   | 
| 55 | 
            +
                  manager.puts
         | 
| 56 | 
            +
             | 
| 57 | 
            +
                  streams = 3.times.map { client.recv_io }
         | 
| 58 | 
            +
                  args    = JSON.parse(client.read(client.gets.to_i))
         | 
| 59 | 
            +
                  command = Spring.command(args.shift)
         | 
| 61 60 |  | 
| 62 61 | 
             
                  setup command
         | 
| 63 62 |  | 
| @@ -92,16 +91,13 @@ module Spring | |
| 92 91 | 
             
                # The command might need to require some files in the
         | 
| 93 92 | 
             
                # main process so that they are cached. For example a test command wants to
         | 
| 94 93 | 
             
                # load the helper file once and have it cached.
         | 
| 95 | 
            -
                #
         | 
| 96 | 
            -
                # FIXME: The watcher.add_files will reset the watcher, which may mean that
         | 
| 97 | 
            -
                #        previous changes to already-loaded files are missed.
         | 
| 98 94 | 
             
                def setup(command)
         | 
| 99 95 | 
             
                  return if @setup.include?(command.class)
         | 
| 100 96 | 
             
                  @setup << command.class
         | 
| 101 97 |  | 
| 102 98 | 
             
                  if command.respond_to?(:setup)
         | 
| 103 99 | 
             
                    command.setup
         | 
| 104 | 
            -
                    watcher. | 
| 100 | 
            +
                    watcher.add loaded_application_features # loaded features may have changed
         | 
| 105 101 | 
             
                  end
         | 
| 106 102 | 
             
                end
         | 
| 107 103 |  | 
| @@ -110,5 +106,9 @@ module Spring | |
| 110 106 | 
             
                    callback.call
         | 
| 111 107 | 
             
                  end
         | 
| 112 108 | 
             
                end
         | 
| 109 | 
            +
             | 
| 110 | 
            +
                def loaded_application_features
         | 
| 111 | 
            +
                  $LOADED_FEATURES.select { |f| f.start_with?(File.realpath(Rails.root)) }
         | 
| 112 | 
            +
                end
         | 
| 113 113 | 
             
              end
         | 
| 114 114 | 
             
            end
         | 
| @@ -1,11 +1,9 @@ | |
| 1 1 | 
             
            require "socket"
         | 
| 2 | 
            +
            require "thread"
         | 
| 2 3 | 
             
            require "spring/application"
         | 
| 3 | 
            -
            require "mutex_m"
         | 
| 4 4 |  | 
| 5 5 | 
             
            module Spring
         | 
| 6 6 | 
             
              class ApplicationManager
         | 
| 7 | 
            -
                include Mutex_m
         | 
| 8 | 
            -
             | 
| 9 7 | 
             
                attr_reader :pid, :child, :app_env, :spring_env
         | 
| 10 8 |  | 
| 11 9 | 
             
                def initialize(app_env)
         | 
| @@ -13,6 +11,16 @@ module Spring | |
| 13 11 |  | 
| 14 12 | 
             
                  @app_env    = app_env
         | 
| 15 13 | 
             
                  @spring_env = Env.new
         | 
| 14 | 
            +
                  @mutex      = Mutex.new
         | 
| 15 | 
            +
                end
         | 
| 16 | 
            +
             | 
| 17 | 
            +
                # We're not using @mutex.synchronize to avoid the weird "<internal:prelude>:10"
         | 
| 18 | 
            +
                # line which messes with backtraces in e.g. rspec
         | 
| 19 | 
            +
                def synchronize
         | 
| 20 | 
            +
                  @mutex.lock
         | 
| 21 | 
            +
                  yield
         | 
| 22 | 
            +
                ensure
         | 
| 23 | 
            +
                  @mutex.unlock
         | 
| 16 24 | 
             
                end
         | 
| 17 25 |  | 
| 18 26 | 
             
                def start
         | 
| @@ -31,31 +39,36 @@ module Spring | |
| 31 39 | 
             
                  @pid
         | 
| 32 40 | 
             
                end
         | 
| 33 41 |  | 
| 34 | 
            -
                 | 
| 35 | 
            -
                def run(client)
         | 
| 36 | 
            -
                  @client = client
         | 
| 37 | 
            -
             | 
| 42 | 
            +
                def with_child
         | 
| 38 43 | 
             
                  synchronize do
         | 
| 39 44 | 
             
                    if alive?
         | 
| 40 45 | 
             
                      begin
         | 
| 41 | 
            -
                         | 
| 42 | 
            -
                      rescue Errno::EPIPE
         | 
| 43 | 
            -
                        #  | 
| 46 | 
            +
                        yield
         | 
| 47 | 
            +
                      rescue Errno::ECONNRESET, Errno::EPIPE
         | 
| 48 | 
            +
                        # The child has died but has not been collected by the wait thread yet,
         | 
| 49 | 
            +
                        # so start a new child and try again.
         | 
| 44 50 | 
             
                        start
         | 
| 45 | 
            -
                         | 
| 51 | 
            +
                        yield
         | 
| 46 52 | 
             
                      end
         | 
| 47 53 | 
             
                    else
         | 
| 48 54 | 
             
                      start
         | 
| 49 | 
            -
                       | 
| 55 | 
            +
                      yield
         | 
| 50 56 | 
             
                    end
         | 
| 51 57 | 
             
                  end
         | 
| 58 | 
            +
                end
         | 
| 59 | 
            +
             | 
| 60 | 
            +
                # Returns the pid of the process running the command, or nil if the application process died.
         | 
| 61 | 
            +
                def run(client)
         | 
| 62 | 
            +
                  with_child do
         | 
| 63 | 
            +
                    child.send_io client
         | 
| 64 | 
            +
                    child.gets
         | 
| 65 | 
            +
                  end
         | 
| 52 66 |  | 
| 53 67 | 
             
                  child.gets.chomp.to_i # get the pid
         | 
| 54 68 | 
             
                rescue Errno::ECONNRESET, Errno::EPIPE
         | 
| 55 69 | 
             
                  nil
         | 
| 56 70 | 
             
                ensure
         | 
| 57 | 
            -
                   | 
| 58 | 
            -
                  @client = nil
         | 
| 71 | 
            +
                  client.close
         | 
| 59 72 | 
             
                end
         | 
| 60 73 |  | 
| 61 74 | 
             
                def stop
         | 
| @@ -68,11 +81,17 @@ module Spring | |
| 68 81 | 
             
                  @child, child_socket = UNIXSocket.pair
         | 
| 69 82 | 
             
                  @pid = fork {
         | 
| 70 83 | 
             
                    [STDOUT, STDERR].each { |s| s.reopen('/dev/null', 'w') } if silence
         | 
| 71 | 
            -
             | 
| 84 | 
            +
             | 
| 85 | 
            +
                    (ObjectSpace.each_object(IO).to_a - [STDOUT, STDERR, STDIN, child_socket])
         | 
| 86 | 
            +
                      .reject(&:closed?)
         | 
| 87 | 
            +
                      .each(&:close)
         | 
| 88 | 
            +
             | 
| 72 89 | 
             
                    ENV['RAILS_ENV'] = ENV['RACK_ENV'] = app_env
         | 
| 90 | 
            +
             | 
| 73 91 | 
             
                    ProcessTitleUpdater.run { |distance|
         | 
| 74 92 | 
             
                      "spring app    | #{spring_env.app_name} | started #{distance} ago | #{app_env} mode"
         | 
| 75 93 | 
             
                    }
         | 
| 94 | 
            +
             | 
| 76 95 | 
             
                    Application.new(child_socket).start
         | 
| 77 96 | 
             
                  }
         | 
| 78 97 | 
             
                  child_socket.close
         | 
    
        data/lib/spring/client.rb
    CHANGED
    
    | @@ -3,31 +3,33 @@ require "spring/client/command" | |
| 3 3 | 
             
            require "spring/client/run"
         | 
| 4 4 | 
             
            require "spring/client/help"
         | 
| 5 5 | 
             
            require "spring/client/binstub"
         | 
| 6 | 
            +
            require "spring/client/start"
         | 
| 6 7 | 
             
            require "spring/client/stop"
         | 
| 7 8 | 
             
            require "spring/client/status"
         | 
| 9 | 
            +
            require "spring/client/rails"
         | 
| 8 10 |  | 
| 9 11 | 
             
            module Spring
         | 
| 10 12 | 
             
              module Client
         | 
| 11 13 | 
             
                COMMANDS = {
         | 
| 12 14 | 
             
                  "help"    => Client::Help,
         | 
| 13 15 | 
             
                  "binstub" => Client::Binstub,
         | 
| 16 | 
            +
                  "start"   => Client::Start,
         | 
| 14 17 | 
             
                  "stop"    => Client::Stop,
         | 
| 15 | 
            -
                  "status"  => Client::Status
         | 
| 18 | 
            +
                  "status"  => Client::Status,
         | 
| 19 | 
            +
                  "rails"   => Client::Rails
         | 
| 16 20 | 
             
                }
         | 
| 17 21 |  | 
| 18 22 | 
             
                def self.run(args)
         | 
| 19 23 | 
             
                  command_for(args.first).call(args)
         | 
| 24 | 
            +
                rescue CommandNotFound
         | 
| 25 | 
            +
                  Client::Help.call(args)
         | 
| 20 26 | 
             
                rescue ClientError => e
         | 
| 21 | 
            -
                   | 
| 27 | 
            +
                  $stderr.puts e.message
         | 
| 22 28 | 
             
                  exit 1
         | 
| 23 29 | 
             
                end
         | 
| 24 30 |  | 
| 25 31 | 
             
                def self.command_for(name)
         | 
| 26 | 
            -
                   | 
| 27 | 
            -
                    Client::Run
         | 
| 28 | 
            -
                  else
         | 
| 29 | 
            -
                    COMMANDS.fetch(name) { Client::Help }
         | 
| 30 | 
            -
                  end
         | 
| 32 | 
            +
                  COMMANDS[name] || Client::Run
         | 
| 31 33 | 
             
                end
         | 
| 32 34 | 
             
              end
         | 
| 33 35 | 
             
            end
         | 
| @@ -7,6 +7,11 @@ module Spring | |
| 7 7 | 
             
                    "Generate spring based binstubs."
         | 
| 8 8 | 
             
                  end
         | 
| 9 9 |  | 
| 10 | 
            +
                  def self.call(args)
         | 
| 11 | 
            +
                    require "spring/commands"
         | 
| 12 | 
            +
                    super
         | 
| 13 | 
            +
                  end
         | 
| 14 | 
            +
             | 
| 10 15 | 
             
                  def initialize(args)
         | 
| 11 16 | 
             
                    super
         | 
| 12 17 |  | 
| @@ -15,12 +20,12 @@ module Spring | |
| 15 20 | 
             
                  end
         | 
| 16 21 |  | 
| 17 22 | 
             
                  def call
         | 
| 18 | 
            -
                    if Spring.command?(name)
         | 
| 23 | 
            +
                    if Spring.command?(name) || name == "rails"
         | 
| 19 24 | 
             
                      bindir.mkdir unless bindir.exist?
         | 
| 20 25 | 
             
                      generate_spring_binstub
         | 
| 21 26 | 
             
                      generate_command_binstub
         | 
| 22 27 | 
             
                    else
         | 
| 23 | 
            -
                       | 
| 28 | 
            +
                      $stderr.puts "The '#{name}' command is not known to spring."
         | 
| 24 29 | 
             
                      exit 1
         | 
| 25 30 | 
             
                    end
         | 
| 26 31 | 
             
                  end
         | 
| @@ -50,7 +55,7 @@ if spec | |
| 50 55 | 
             
              spec.activate
         | 
| 51 56 | 
             
              load spec.bin_file("spring")
         | 
| 52 57 | 
             
            else
         | 
| 53 | 
            -
               | 
| 58 | 
            +
              $stderr.puts "Could not find spring gem in #{Gem::Specification.dirs.join(", ")}."
         | 
| 54 59 | 
             
              exit 1
         | 
| 55 60 | 
             
            end
         | 
| 56 61 | 
             
            CODE
         |