listen 0.1.0 → 0.2.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.
- data/CHANGELOG.md +10 -2
 - data/README.md +71 -35
 - data/lib/listen.rb +1 -1
 - data/lib/listen/adapter.rb +22 -1
 - data/lib/listen/adapters/darwin.rb +58 -0
 - data/lib/listen/adapters/linux.rb +85 -0
 - data/lib/listen/adapters/polling.rb +6 -5
 - data/lib/listen/adapters/windows.rb +75 -0
 - data/lib/listen/listener.rb +111 -35
 - data/lib/listen/version.rb +1 -1
 - metadata +25 -64
 
    
        data/CHANGELOG.md
    CHANGED
    
    | 
         @@ -1,7 +1,15 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            ## Master
         
     | 
| 
       2 
2 
     | 
    
         | 
| 
      
 3 
     | 
    
         
            +
            - Add checksum comparaison support for detecting consecutive file modifications made during the same second. ([@thibaudgg][])
         
     | 
| 
      
 4 
     | 
    
         
            +
            - Add rb-fchange support. ([@thibaudgg][])
         
     | 
| 
      
 5 
     | 
    
         
            +
            - Add rb-inotify support. ([@thibaudgg][] with [@Maher4Ever][] help)
         
     | 
| 
      
 6 
     | 
    
         
            +
            - Add rb-fsevent support. ([@thibaudgg][])
         
     | 
| 
      
 7 
     | 
    
         
            +
            - Add non-recursive diff with multiple directories support. ([@thibaudgg][])
         
     | 
| 
      
 8 
     | 
    
         
            +
            - Ignore .DS_Store by default. ([@thibaudgg][])
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
       3 
10 
     | 
    
         
             
            ## 0.1.0 - January 28, 2012
         
     | 
| 
       4 
11 
     | 
    
         | 
| 
       5 
     | 
    
         
            -
            - First version with only a polling adapter and basic features set. ([@thibaudgg][])
         
     | 
| 
      
 12 
     | 
    
         
            +
            - First version with only a polling adapter and basic features set (ignore & filter). ([@thibaudgg][])
         
     | 
| 
       6 
13 
     | 
    
         | 
| 
       7 
     | 
    
         
            -
            [@thibaudgg]: https://github.com/thibaudgg
         
     | 
| 
      
 14 
     | 
    
         
            +
            [@thibaudgg]: https://github.com/thibaudgg
         
     | 
| 
      
 15 
     | 
    
         
            +
            [@Maher4Ever]: https://github.com/Maher4Ever
         
     | 
    
        data/README.md
    CHANGED
    
    | 
         @@ -1,63 +1,99 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            # Listen [](http://travis-ci.org/guard/listen)
         
     | 
| 
       2 
2 
     | 
    
         | 
| 
       3 
     | 
    
         
            -
            Work in progress 
     | 
| 
      
 3 
     | 
    
         
            +
            **Work in progress...**
         
     | 
| 
       4 
4 
     | 
    
         | 
| 
       5 
5 
     | 
    
         
             
            The Listen gem listens to file modifications and notifies you about the changes.
         
     | 
| 
       6 
6 
     | 
    
         | 
| 
       7 
     | 
    
         
            -
             
     | 
| 
      
 7 
     | 
    
         
            +
            ## TODO
         
     | 
| 
       8 
8 
     | 
    
         | 
| 
       9 
     | 
    
         
            -
             
     | 
| 
      
 9 
     | 
    
         
            +
            - **DONE** Add polling support
         
     | 
| 
      
 10 
     | 
    
         
            +
            - **DONE** Add `rb-fsevent` support
         
     | 
| 
      
 11 
     | 
    
         
            +
            - **DONE** Add `rb-inotify` support
         
     | 
| 
      
 12 
     | 
    
         
            +
            - **DONE** Add `rb-fchange` support
         
     | 
| 
      
 13 
     | 
    
         
            +
            - **DONE** Add checksum comparaison support for detecting consecutive file modifications made during the same second. (like Guard)
         
     | 
| 
      
 14 
     | 
    
         
            +
            - Add latency option
         
     | 
| 
      
 15 
     | 
    
         
            +
            - Add polling option (true: polling forced, false: polling never used (to skip DropBox polling fallback))
         
     | 
| 
      
 16 
     | 
    
         
            +
            - Dropbox detection with polling fallback (if needed)
         
     | 
| 
      
 17 
     | 
    
         
            +
            - Improve API (if needed)
         
     | 
| 
       10 
18 
     | 
    
         | 
| 
       11 
     | 
    
         
            -
             
     | 
| 
      
 19 
     | 
    
         
            +
            ## Install
         
     | 
| 
       12 
20 
     | 
    
         | 
| 
       13 
     | 
    
         
            -
            ```  
     | 
| 
       14 
     | 
    
         
            -
             
     | 
| 
       15 
     | 
    
         
            -
              ...
         
     | 
| 
       16 
     | 
    
         
            -
            end
         
     | 
| 
      
 21 
     | 
    
         
            +
            ``` bash
         
     | 
| 
      
 22 
     | 
    
         
            +
            gem install listen
         
     | 
| 
       17 
23 
     | 
    
         
             
            ```
         
     | 
| 
       18 
24 
     | 
    
         | 
| 
       19 
     | 
    
         
            -
             
     | 
| 
      
 25 
     | 
    
         
            +
            ## Usage
         
     | 
| 
      
 26 
     | 
    
         
            +
             
     | 
| 
      
 27 
     | 
    
         
            +
            There are two ways you can use Listen.
         
     | 
| 
      
 28 
     | 
    
         
            +
             
     | 
| 
      
 29 
     | 
    
         
            +
            1. call `Listen.to` with a path params, and define callbacks in a block.
         
     | 
| 
      
 30 
     | 
    
         
            +
            3. create a `listener` object usable in an (ARel style) chainable way.
         
     | 
| 
      
 31 
     | 
    
         
            +
             
     | 
| 
      
 32 
     | 
    
         
            +
            Feel free to give your feeback via [Listen issues](https://github.com/guard/listener/issues)
         
     | 
| 
      
 33 
     | 
    
         
            +
             
     | 
| 
      
 34 
     | 
    
         
            +
            ### Block API
         
     | 
| 
      
 35 
     | 
    
         
            +
             
     | 
| 
      
 36 
     | 
    
         
            +
            #### One dir
         
     | 
| 
       20 
37 
     | 
    
         | 
| 
       21 
38 
     | 
    
         
             
            ``` ruby
         
     | 
| 
       22 
     | 
    
         
            -
            Listen.to do
         
     | 
| 
       23 
     | 
    
         
            -
               
     | 
| 
       24 
     | 
    
         
            -
                ...
         
     | 
| 
       25 
     | 
    
         
            -
              end
         
     | 
| 
       26 
     | 
    
         
            -
              path(dir2, filter: '**/*', ignore: paths) do |modified, added, removed|
         
     | 
| 
       27 
     | 
    
         
            -
                ...
         
     | 
| 
       28 
     | 
    
         
            -
              end
         
     | 
| 
       29 
     | 
    
         
            -
              ....
         
     | 
| 
      
 39 
     | 
    
         
            +
            Listen.to('dir/path/to/listen', filter: /.*\.rb/, ignore: '/ignored/path') do |modified, added, removed|
         
     | 
| 
      
 40 
     | 
    
         
            +
              # ...
         
     | 
| 
       30 
41 
     | 
    
         
             
            end
         
     | 
| 
       31 
42 
     | 
    
         
             
            ```
         
     | 
| 
       32 
43 
     | 
    
         | 
| 
       33 
     | 
    
         
            -
             
     | 
| 
       34 
     | 
    
         
            -
             
     | 
| 
       35 
     | 
    
         
            -
            ## "Object" API
         
     | 
| 
      
 44 
     | 
    
         
            +
            ### "Object" API
         
     | 
| 
       36 
45 
     | 
    
         | 
| 
       37 
46 
     | 
    
         
             
            ``` ruby
         
     | 
| 
       38 
     | 
    
         
            -
             
     | 
| 
       39 
     | 
    
         
            -
             
     | 
| 
       40 
     | 
    
         
            -
             
     | 
| 
       41 
     | 
    
         
            -
             
     | 
| 
       42 
     | 
    
         
            -
             
     | 
| 
       43 
     | 
    
         
            -
             
     | 
| 
       44 
     | 
    
         
            -
            listen.start # enter the run loop
         
     | 
| 
       45 
     | 
    
         
            -
            listen.stop
         
     | 
| 
      
 47 
     | 
    
         
            +
            listener = Listen.to('dir/path/to/listen')
         
     | 
| 
      
 48 
     | 
    
         
            +
            listener = listener.ignore('/ignored/path')
         
     | 
| 
      
 49 
     | 
    
         
            +
            listener = listener.filter(/.*\.rb/)
         
     | 
| 
      
 50 
     | 
    
         
            +
            listener = listener.change(&callback)
         
     | 
| 
      
 51 
     | 
    
         
            +
            listener.start # enter the run loop
         
     | 
| 
      
 52 
     | 
    
         
            +
            listener.stop
         
     | 
| 
       46 
53 
     | 
    
         
             
            ```
         
     | 
| 
       47 
54 
     | 
    
         | 
| 
       48 
     | 
    
         
            -
             
     | 
| 
      
 55 
     | 
    
         
            +
            #### Chainable
         
     | 
| 
       49 
56 
     | 
    
         | 
| 
       50 
57 
     | 
    
         
             
            ``` ruby
         
     | 
| 
       51 
     | 
    
         
            -
            Listen.to(dir).ignore(' 
     | 
| 
      
 58 
     | 
    
         
            +
            Listen.to('dir/path/to/listen').ignore('/ignored/path').filter(/.*\.rb/).change(&callback).start # enter the run loop
         
     | 
| 
       52 
59 
     | 
    
         
             
            ```
         
     | 
| 
       53 
60 
     | 
    
         | 
| 
       54 
     | 
    
         
            -
             
     | 
| 
      
 61 
     | 
    
         
            +
            #### Multiple listeners support available via Thread
         
     | 
| 
       55 
62 
     | 
    
         | 
| 
       56 
63 
     | 
    
         
             
            ``` ruby
         
     | 
| 
       57 
     | 
    
         
            -
             
     | 
| 
       58 
     | 
    
         
            -
            styles 
     | 
| 
       59 
     | 
    
         
            -
            scripts 
     | 
| 
      
 64 
     | 
    
         
            +
            listener = Listen.to(dir1).ignore('/ignored/path/')
         
     | 
| 
      
 65 
     | 
    
         
            +
            styles   = listener.filter(/.*\.css/).change(&style_callback)
         
     | 
| 
      
 66 
     | 
    
         
            +
            scripts  = listener.filter(/.*\.js/).change(&scripts_callback)
         
     | 
| 
       60 
67 
     | 
    
         | 
| 
       61 
68 
     | 
    
         
             
            Thread.new { styles.start } # enter the run loop
         
     | 
| 
       62 
69 
     | 
    
         
             
            Thread.new { scripts.start } # enter the run loop
         
     | 
| 
       63 
     | 
    
         
            -
            ```
         
     | 
| 
      
 70 
     | 
    
         
            +
            ```
         
     | 
| 
      
 71 
     | 
    
         
            +
             
     | 
| 
      
 72 
     | 
    
         
            +
            ### Options
         
     | 
| 
      
 73 
     | 
    
         
            +
             
     | 
| 
      
 74 
     | 
    
         
            +
            These options can be set through `Listen.to` params or via methods (see the "Object" API)
         
     | 
| 
      
 75 
     | 
    
         
            +
             
     | 
| 
      
 76 
     | 
    
         
            +
            ```ruby
         
     | 
| 
      
 77 
     | 
    
         
            +
            :filter => /.*\.rb/, /.*\.coffee/   # Filter files to listen to via a regexps list.
         
     | 
| 
      
 78 
     | 
    
         
            +
                                                # default: none
         
     | 
| 
      
 79 
     | 
    
         
            +
             
     | 
| 
      
 80 
     | 
    
         
            +
            :ignore => 'path1', 'path2'         # Ignore a list of paths (root directory or sub-dir)
         
     | 
| 
      
 81 
     | 
    
         
            +
                                                # default: '.bundle', '.git', '.DS_Store', 'log', 'tmp', 'vendor'
         
     | 
| 
      
 82 
     | 
    
         
            +
            ```
         
     | 
| 
      
 83 
     | 
    
         
            +
             
     | 
| 
      
 84 
     | 
    
         
            +
            ## Acknowledgment
         
     | 
| 
      
 85 
     | 
    
         
            +
             
     | 
| 
      
 86 
     | 
    
         
            +
            - [Travis Tilley (ttilley)][] for this awesome work on [fssm][] & [rb-fsevent][].
         
     | 
| 
      
 87 
     | 
    
         
            +
            - [Nathan Weizenbaum (nex3)][] for [rb-inotify][], a thorough inotify wrapper.
         
     | 
| 
      
 88 
     | 
    
         
            +
            - [stereobooster][] for [rb-fchange][], windows support wouldn't exist without him.
         
     | 
| 
      
 89 
     | 
    
         
            +
            - [Yehuda Katz (wycats)][] for [vigilo][], that has been a great source of inspiration.
         
     | 
| 
      
 90 
     | 
    
         
            +
             
     | 
| 
      
 91 
     | 
    
         
            +
            [Travis Tilley (ttilley)]: https://github.com/ttilley
         
     | 
| 
      
 92 
     | 
    
         
            +
            [fssm]: https://github.com/ttilley/fssm
         
     | 
| 
      
 93 
     | 
    
         
            +
            [rb-fsevent]: https://github.com/thibaudgg/rb-fsevent
         
     | 
| 
      
 94 
     | 
    
         
            +
            [Nathan Weizenbaum (nex3)]: https://github.com/nex3
         
     | 
| 
      
 95 
     | 
    
         
            +
            [rb-inotify]: https://github.com/nex3/rb-inotify
         
     | 
| 
      
 96 
     | 
    
         
            +
            [stereobooster]: https://github.com/stereobooster
         
     | 
| 
      
 97 
     | 
    
         
            +
            [rb-fchange]: https://github.com/stereobooster/rb-fchange
         
     | 
| 
      
 98 
     | 
    
         
            +
            [Yehuda Katz (wycats)]: https://github.com/wycats
         
     | 
| 
      
 99 
     | 
    
         
            +
            [vigilo]: https://github.com/wycats/vigilo
         
     | 
    
        data/lib/listen.rb
    CHANGED
    
    
    
        data/lib/listen/adapter.rb
    CHANGED
    
    | 
         @@ -1,5 +1,8 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'rbconfig'
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
       1 
3 
     | 
    
         
             
            module Listen
         
     | 
| 
       2 
4 
     | 
    
         
             
              class Adapter
         
     | 
| 
      
 5 
     | 
    
         
            +
                attr_accessor :latency
         
     | 
| 
       3 
6 
     | 
    
         | 
| 
       4 
7 
     | 
    
         
             
                # Select the appropriate adapter implementation for the
         
     | 
| 
       5 
8 
     | 
    
         
             
                # current OS and initializes it.
         
     | 
| 
         @@ -7,12 +10,30 @@ module Listen 
     | 
|
| 
       7 
10 
     | 
    
         
             
                # @return [Listen::Adapter] the chosen adapter
         
     | 
| 
       8 
11 
     | 
    
         
             
                #
         
     | 
| 
       9 
12 
     | 
    
         
             
                def self.select_and_initialize(listener)
         
     | 
| 
       10 
     | 
    
         
            -
                  Adapters:: 
     | 
| 
      
 13 
     | 
    
         
            +
                  if Adapters::Darwin.usable?
         
     | 
| 
      
 14 
     | 
    
         
            +
                    Adapters::Darwin.new(listener)
         
     | 
| 
      
 15 
     | 
    
         
            +
                  elsif Adapters::Linux.usable?
         
     | 
| 
      
 16 
     | 
    
         
            +
                    Adapters::Linux.new(listener)
         
     | 
| 
      
 17 
     | 
    
         
            +
                  elsif Adapters::Windows.usable?
         
     | 
| 
      
 18 
     | 
    
         
            +
                    Adapters::Windows.new(listener)
         
     | 
| 
      
 19 
     | 
    
         
            +
                  else
         
     | 
| 
      
 20 
     | 
    
         
            +
                    Adapters::Polling.new(listener)
         
     | 
| 
      
 21 
     | 
    
         
            +
                  end
         
     | 
| 
       11 
22 
     | 
    
         
             
                end
         
     | 
| 
       12 
23 
     | 
    
         | 
| 
       13 
24 
     | 
    
         
             
                def initialize(listener)
         
     | 
| 
       14 
25 
     | 
    
         
             
                  @listener = listener
         
     | 
| 
       15 
26 
     | 
    
         
             
                end
         
     | 
| 
       16 
27 
     | 
    
         | 
| 
      
 28 
     | 
    
         
            +
                # Start the adapter.
         
     | 
| 
      
 29 
     | 
    
         
            +
                #
         
     | 
| 
      
 30 
     | 
    
         
            +
                def start
         
     | 
| 
      
 31 
     | 
    
         
            +
                end
         
     | 
| 
      
 32 
     | 
    
         
            +
             
     | 
| 
      
 33 
     | 
    
         
            +
                # Stop the adapter.
         
     | 
| 
      
 34 
     | 
    
         
            +
                #
         
     | 
| 
      
 35 
     | 
    
         
            +
                def stop
         
     | 
| 
      
 36 
     | 
    
         
            +
                end
         
     | 
| 
      
 37 
     | 
    
         
            +
             
     | 
| 
       17 
38 
     | 
    
         
             
              end
         
     | 
| 
       18 
39 
     | 
    
         
             
            end
         
     | 
| 
         @@ -0,0 +1,58 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module Listen
         
     | 
| 
      
 2 
     | 
    
         
            +
              module Adapters
         
     | 
| 
      
 3 
     | 
    
         
            +
             
     | 
| 
      
 4 
     | 
    
         
            +
                # Adapter implementation for Mac OS X `FSEvents`.
         
     | 
| 
      
 5 
     | 
    
         
            +
                #
         
     | 
| 
      
 6 
     | 
    
         
            +
                class Darwin < Adapter
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
                  # Initialize the Adapter.
         
     | 
| 
      
 9 
     | 
    
         
            +
                  #
         
     | 
| 
      
 10 
     | 
    
         
            +
                  def initialize(*)
         
     | 
| 
      
 11 
     | 
    
         
            +
                    super
         
     | 
| 
      
 12 
     | 
    
         
            +
                    @latency ||= 0.1
         
     | 
| 
      
 13 
     | 
    
         
            +
                    init_worker
         
     | 
| 
      
 14 
     | 
    
         
            +
                  end
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
                  # Start the adapter.
         
     | 
| 
      
 17 
     | 
    
         
            +
                  #
         
     | 
| 
      
 18 
     | 
    
         
            +
                  def start
         
     | 
| 
      
 19 
     | 
    
         
            +
                    super
         
     | 
| 
      
 20 
     | 
    
         
            +
                    @worker.run
         
     | 
| 
      
 21 
     | 
    
         
            +
                  end
         
     | 
| 
      
 22 
     | 
    
         
            +
             
     | 
| 
      
 23 
     | 
    
         
            +
                  # Stop the adapter.
         
     | 
| 
      
 24 
     | 
    
         
            +
                  #
         
     | 
| 
      
 25 
     | 
    
         
            +
                  def stop
         
     | 
| 
      
 26 
     | 
    
         
            +
                    super
         
     | 
| 
      
 27 
     | 
    
         
            +
                    @worker.stop
         
     | 
| 
      
 28 
     | 
    
         
            +
                  end
         
     | 
| 
      
 29 
     | 
    
         
            +
             
     | 
| 
      
 30 
     | 
    
         
            +
                  # Check if the adapter is usable on the current OS.
         
     | 
| 
      
 31 
     | 
    
         
            +
                  #
         
     | 
| 
      
 32 
     | 
    
         
            +
                  # @return [Boolean] whether usable or not
         
     | 
| 
      
 33 
     | 
    
         
            +
                  #
         
     | 
| 
      
 34 
     | 
    
         
            +
                  def self.usable?
         
     | 
| 
      
 35 
     | 
    
         
            +
                    return false unless RbConfig::CONFIG['target_os'] =~ /darwin(1.+)?$/i
         
     | 
| 
      
 36 
     | 
    
         
            +
             
     | 
| 
      
 37 
     | 
    
         
            +
                    require 'rb-fsevent'
         
     | 
| 
      
 38 
     | 
    
         
            +
                    true
         
     | 
| 
      
 39 
     | 
    
         
            +
                  rescue LoadError
         
     | 
| 
      
 40 
     | 
    
         
            +
                    false
         
     | 
| 
      
 41 
     | 
    
         
            +
                  end
         
     | 
| 
      
 42 
     | 
    
         
            +
             
     | 
| 
      
 43 
     | 
    
         
            +
                private
         
     | 
| 
      
 44 
     | 
    
         
            +
             
     | 
| 
      
 45 
     | 
    
         
            +
                  # Initialiaze FSEvent worker and set watch callback block
         
     | 
| 
      
 46 
     | 
    
         
            +
                  #
         
     | 
| 
      
 47 
     | 
    
         
            +
                  def init_worker
         
     | 
| 
      
 48 
     | 
    
         
            +
                    @worker = FSEvent.new
         
     | 
| 
      
 49 
     | 
    
         
            +
                    @worker.watch(@listener.directory, :latency => @latency) do |changed_dirs|
         
     | 
| 
      
 50 
     | 
    
         
            +
                      changed_dirs.map! { |path| path.sub /\/$/, '' }
         
     | 
| 
      
 51 
     | 
    
         
            +
                      @listener.on_change(changed_dirs)
         
     | 
| 
      
 52 
     | 
    
         
            +
                    end
         
     | 
| 
      
 53 
     | 
    
         
            +
                  end
         
     | 
| 
      
 54 
     | 
    
         
            +
             
     | 
| 
      
 55 
     | 
    
         
            +
                end
         
     | 
| 
      
 56 
     | 
    
         
            +
             
     | 
| 
      
 57 
     | 
    
         
            +
              end
         
     | 
| 
      
 58 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,85 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'set'
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module Listen
         
     | 
| 
      
 4 
     | 
    
         
            +
              module Adapters
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
                # Watched INotify EVENTS
         
     | 
| 
      
 7 
     | 
    
         
            +
                #
         
     | 
| 
      
 8 
     | 
    
         
            +
                # @see http://www.tin.org/bin/man.cgi?section=7&topic=inotify
         
     | 
| 
      
 9 
     | 
    
         
            +
                # @see https://github.com/nex3/rb-inotify/blob/master/lib/rb-inotify/notifier.rb#L99-L177
         
     | 
| 
      
 10 
     | 
    
         
            +
                #
         
     | 
| 
      
 11 
     | 
    
         
            +
                EVENTS = %w[recursive attrib close modify move create delete delete_self move_self]
         
     | 
| 
      
 12 
     | 
    
         
            +
                
         
     | 
| 
      
 13 
     | 
    
         
            +
                # Listener implementation for Linux `inotify`.
         
     | 
| 
      
 14 
     | 
    
         
            +
                #
         
     | 
| 
      
 15 
     | 
    
         
            +
                class Linux < Adapter
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
                  # Initialize the Adapter.
         
     | 
| 
      
 18 
     | 
    
         
            +
                  #
         
     | 
| 
      
 19 
     | 
    
         
            +
                  def initialize(*)
         
     | 
| 
      
 20 
     | 
    
         
            +
                    super
         
     | 
| 
      
 21 
     | 
    
         
            +
                    @latency    ||= 0.1
         
     | 
| 
      
 22 
     | 
    
         
            +
                    @changed_dirs = Set.new
         
     | 
| 
      
 23 
     | 
    
         
            +
                    init_worker
         
     | 
| 
      
 24 
     | 
    
         
            +
                  end
         
     | 
| 
      
 25 
     | 
    
         
            +
             
     | 
| 
      
 26 
     | 
    
         
            +
                  # Start the adapter.
         
     | 
| 
      
 27 
     | 
    
         
            +
                  #
         
     | 
| 
      
 28 
     | 
    
         
            +
                  def start
         
     | 
| 
      
 29 
     | 
    
         
            +
                    super
         
     | 
| 
      
 30 
     | 
    
         
            +
                    Thread.new { @worker.run }
         
     | 
| 
      
 31 
     | 
    
         
            +
                    @stop = false
         
     | 
| 
      
 32 
     | 
    
         
            +
                    poll_changed_dirs
         
     | 
| 
      
 33 
     | 
    
         
            +
                  end
         
     | 
| 
      
 34 
     | 
    
         
            +
             
     | 
| 
      
 35 
     | 
    
         
            +
                  # Stop the adapter.
         
     | 
| 
      
 36 
     | 
    
         
            +
                  #
         
     | 
| 
      
 37 
     | 
    
         
            +
                  def stop
         
     | 
| 
      
 38 
     | 
    
         
            +
                    super
         
     | 
| 
      
 39 
     | 
    
         
            +
                    @stop = true
         
     | 
| 
      
 40 
     | 
    
         
            +
                    @worker.stop
         
     | 
| 
      
 41 
     | 
    
         
            +
                  end
         
     | 
| 
      
 42 
     | 
    
         
            +
             
     | 
| 
      
 43 
     | 
    
         
            +
                  # Check if the adapter is usable on the current OS.
         
     | 
| 
      
 44 
     | 
    
         
            +
                  #
         
     | 
| 
      
 45 
     | 
    
         
            +
                  # @return [Boolean] whether usable or not
         
     | 
| 
      
 46 
     | 
    
         
            +
                  #
         
     | 
| 
      
 47 
     | 
    
         
            +
                  def self.usable?
         
     | 
| 
      
 48 
     | 
    
         
            +
                    return false unless RbConfig::CONFIG['target_os'] =~ /linux/i
         
     | 
| 
      
 49 
     | 
    
         
            +
             
     | 
| 
      
 50 
     | 
    
         
            +
                    require 'rb-inotify'
         
     | 
| 
      
 51 
     | 
    
         
            +
                    true
         
     | 
| 
      
 52 
     | 
    
         
            +
                  rescue LoadError
         
     | 
| 
      
 53 
     | 
    
         
            +
                    false
         
     | 
| 
      
 54 
     | 
    
         
            +
                  end
         
     | 
| 
      
 55 
     | 
    
         
            +
             
     | 
| 
      
 56 
     | 
    
         
            +
                private
         
     | 
| 
      
 57 
     | 
    
         
            +
                  
         
     | 
| 
      
 58 
     | 
    
         
            +
                  # Initialiaze INotify worker and set watch callback block.
         
     | 
| 
      
 59 
     | 
    
         
            +
                  #
         
     | 
| 
      
 60 
     | 
    
         
            +
                  def init_worker
         
     | 
| 
      
 61 
     | 
    
         
            +
                    @worker = INotify::Notifier.new
         
     | 
| 
      
 62 
     | 
    
         
            +
                    @worker.watch(@listener.directory, *EVENTS.map(&:to_sym)) do |event|
         
     | 
| 
      
 63 
     | 
    
         
            +
                      unless event.name == "" # Event on root directory
         
     | 
| 
      
 64 
     | 
    
         
            +
                        @changed_dirs << File.dirname(event.absolute_name)
         
     | 
| 
      
 65 
     | 
    
         
            +
                      end
         
     | 
| 
      
 66 
     | 
    
         
            +
                    end
         
     | 
| 
      
 67 
     | 
    
         
            +
                  end
         
     | 
| 
      
 68 
     | 
    
         
            +
                  
         
     | 
| 
      
 69 
     | 
    
         
            +
                  # Polling around @changed_dirs presence.
         
     | 
| 
      
 70 
     | 
    
         
            +
                  #
         
     | 
| 
      
 71 
     | 
    
         
            +
                  def poll_changed_dirs
         
     | 
| 
      
 72 
     | 
    
         
            +
                    until @stop
         
     | 
| 
      
 73 
     | 
    
         
            +
                      sleep(@latency)
         
     | 
| 
      
 74 
     | 
    
         
            +
                      
         
     | 
| 
      
 75 
     | 
    
         
            +
                      next if @changed_dirs.empty?
         
     | 
| 
      
 76 
     | 
    
         
            +
                      changed_dirs = @changed_dirs.to_a
         
     | 
| 
      
 77 
     | 
    
         
            +
                      @changed_dirs.clear          
         
     | 
| 
      
 78 
     | 
    
         
            +
                      @listener.on_change(changed_dirs)
         
     | 
| 
      
 79 
     | 
    
         
            +
                    end
         
     | 
| 
      
 80 
     | 
    
         
            +
                  end
         
     | 
| 
      
 81 
     | 
    
         
            +
             
     | 
| 
      
 82 
     | 
    
         
            +
                end
         
     | 
| 
      
 83 
     | 
    
         
            +
             
     | 
| 
      
 84 
     | 
    
         
            +
              end
         
     | 
| 
      
 85 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -7,18 +7,18 @@ module Listen 
     | 
|
| 
       7 
7 
     | 
    
         
             
                # file IO that the other implementations.
         
     | 
| 
       8 
8 
     | 
    
         
             
                #
         
     | 
| 
       9 
9 
     | 
    
         
             
                class Polling < Adapter
         
     | 
| 
       10 
     | 
    
         
            -
             
     | 
| 
       11 
     | 
    
         
            -
                  
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
       12 
11 
     | 
    
         
             
                  # Initialize the Adapter.
         
     | 
| 
       13 
12 
     | 
    
         
             
                  #
         
     | 
| 
       14 
13 
     | 
    
         
             
                  def initialize(*)
         
     | 
| 
       15 
14 
     | 
    
         
             
                    super
         
     | 
| 
       16 
     | 
    
         
            -
                    @latency  
     | 
| 
      
 15 
     | 
    
         
            +
                    @latency ||= 1.0
         
     | 
| 
       17 
16 
     | 
    
         
             
                  end
         
     | 
| 
       18 
17 
     | 
    
         | 
| 
       19 
18 
     | 
    
         
             
                  # Start the adapter.
         
     | 
| 
       20 
19 
     | 
    
         
             
                  #
         
     | 
| 
       21 
20 
     | 
    
         
             
                  def start
         
     | 
| 
      
 21 
     | 
    
         
            +
                    super
         
     | 
| 
       22 
22 
     | 
    
         
             
                    @stop = false
         
     | 
| 
       23 
23 
     | 
    
         
             
                    poll
         
     | 
| 
       24 
24 
     | 
    
         
             
                  end
         
     | 
| 
         @@ -26,17 +26,18 @@ module Listen 
     | 
|
| 
       26 
26 
     | 
    
         
             
                  # Stop the adapter.
         
     | 
| 
       27 
27 
     | 
    
         
             
                  #
         
     | 
| 
       28 
28 
     | 
    
         
             
                  def stop
         
     | 
| 
      
 29 
     | 
    
         
            +
                    super
         
     | 
| 
       29 
30 
     | 
    
         
             
                    @stop = true
         
     | 
| 
       30 
31 
     | 
    
         
             
                  end
         
     | 
| 
       31 
32 
     | 
    
         | 
| 
       32 
     | 
    
         
            -
             
     | 
| 
      
 33 
     | 
    
         
            +
                private
         
     | 
| 
       33 
34 
     | 
    
         | 
| 
       34 
35 
     | 
    
         
             
                  # Poll listener directory for file system changes.
         
     | 
| 
       35 
36 
     | 
    
         
             
                  #
         
     | 
| 
       36 
37 
     | 
    
         
             
                  def poll
         
     | 
| 
       37 
38 
     | 
    
         
             
                    until @stop
         
     | 
| 
       38 
39 
     | 
    
         
             
                      start = Time.now.to_f
         
     | 
| 
       39 
     | 
    
         
            -
                      @listener.on_change(@listener.directory)
         
     | 
| 
      
 40 
     | 
    
         
            +
                      @listener.on_change([@listener.directory], :recursive => true)
         
     | 
| 
       40 
41 
     | 
    
         
             
                      nap_time = @latency - (Time.now.to_f - start)
         
     | 
| 
       41 
42 
     | 
    
         
             
                      sleep(nap_time) if nap_time > 0
         
     | 
| 
       42 
43 
     | 
    
         
             
                    end
         
     | 
| 
         @@ -0,0 +1,75 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'set'
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module Listen
         
     | 
| 
      
 4 
     | 
    
         
            +
              module Adapters
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
                # Adapter implementation for Windows `fchange`.
         
     | 
| 
      
 7 
     | 
    
         
            +
                #
         
     | 
| 
      
 8 
     | 
    
         
            +
                class Windows < Adapter
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
                  # Initialize the Adapter.
         
     | 
| 
      
 11 
     | 
    
         
            +
                  #
         
     | 
| 
      
 12 
     | 
    
         
            +
                  def initialize(*)
         
     | 
| 
      
 13 
     | 
    
         
            +
                    super
         
     | 
| 
      
 14 
     | 
    
         
            +
                    @latency ||= 0.1
         
     | 
| 
      
 15 
     | 
    
         
            +
                    @changed_dirs = Set.new
         
     | 
| 
      
 16 
     | 
    
         
            +
                    init_worker
         
     | 
| 
      
 17 
     | 
    
         
            +
                  end
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
                  # Start the adapter.
         
     | 
| 
      
 20 
     | 
    
         
            +
                  #
         
     | 
| 
      
 21 
     | 
    
         
            +
                  def start
         
     | 
| 
      
 22 
     | 
    
         
            +
                    super
         
     | 
| 
      
 23 
     | 
    
         
            +
                    Thread.new { @worker.run }
         
     | 
| 
      
 24 
     | 
    
         
            +
                    @stop = false
         
     | 
| 
      
 25 
     | 
    
         
            +
                    poll_changed_dirs
         
     | 
| 
      
 26 
     | 
    
         
            +
                  end
         
     | 
| 
      
 27 
     | 
    
         
            +
             
     | 
| 
      
 28 
     | 
    
         
            +
                  # Stop the adapter.
         
     | 
| 
      
 29 
     | 
    
         
            +
                  #
         
     | 
| 
      
 30 
     | 
    
         
            +
                  def stop
         
     | 
| 
      
 31 
     | 
    
         
            +
                    super
         
     | 
| 
      
 32 
     | 
    
         
            +
                    @worker.stop
         
     | 
| 
      
 33 
     | 
    
         
            +
                  end
         
     | 
| 
      
 34 
     | 
    
         
            +
             
     | 
| 
      
 35 
     | 
    
         
            +
                  # Check if the adapter is usable on the current OS.
         
     | 
| 
      
 36 
     | 
    
         
            +
                  #
         
     | 
| 
      
 37 
     | 
    
         
            +
                  # @return [Boolean] whether usable or not
         
     | 
| 
      
 38 
     | 
    
         
            +
                  #
         
     | 
| 
      
 39 
     | 
    
         
            +
                  def self.usable?
         
     | 
| 
      
 40 
     | 
    
         
            +
                    return false unless RbConfig::CONFIG['target_os'] =~ /mswin|mingw/i
         
     | 
| 
      
 41 
     | 
    
         
            +
             
     | 
| 
      
 42 
     | 
    
         
            +
                    require 'rb-fchange'
         
     | 
| 
      
 43 
     | 
    
         
            +
                    true
         
     | 
| 
      
 44 
     | 
    
         
            +
                  rescue LoadError
         
     | 
| 
      
 45 
     | 
    
         
            +
                    false
         
     | 
| 
      
 46 
     | 
    
         
            +
                  end
         
     | 
| 
      
 47 
     | 
    
         
            +
             
     | 
| 
      
 48 
     | 
    
         
            +
                private
         
     | 
| 
      
 49 
     | 
    
         
            +
             
     | 
| 
      
 50 
     | 
    
         
            +
                  # Initialiaze FSEvent worker and set watch callback block
         
     | 
| 
      
 51 
     | 
    
         
            +
                  #
         
     | 
| 
      
 52 
     | 
    
         
            +
                  def init_worker
         
     | 
| 
      
 53 
     | 
    
         
            +
                    @worker = FChange::Notifier.new
         
     | 
| 
      
 54 
     | 
    
         
            +
                    @worker.watch(@listener.directory, :all_events, :recursive) do |event|
         
     | 
| 
      
 55 
     | 
    
         
            +
                      @changed_dirs << File.expand_path(event.watcher.path)
         
     | 
| 
      
 56 
     | 
    
         
            +
                    end
         
     | 
| 
      
 57 
     | 
    
         
            +
                  end
         
     | 
| 
      
 58 
     | 
    
         
            +
                  
         
     | 
| 
      
 59 
     | 
    
         
            +
                  # Polling around @changed_dirs presence.
         
     | 
| 
      
 60 
     | 
    
         
            +
                  #
         
     | 
| 
      
 61 
     | 
    
         
            +
                  def poll_changed_dirs
         
     | 
| 
      
 62 
     | 
    
         
            +
                    until @stop
         
     | 
| 
      
 63 
     | 
    
         
            +
                      sleep(@latency)
         
     | 
| 
      
 64 
     | 
    
         
            +
                      
         
     | 
| 
      
 65 
     | 
    
         
            +
                      next if @changed_dirs.empty?
         
     | 
| 
      
 66 
     | 
    
         
            +
                      changed_dirs = @changed_dirs.to_a
         
     | 
| 
      
 67 
     | 
    
         
            +
                      @changed_dirs.clear          
         
     | 
| 
      
 68 
     | 
    
         
            +
                      @listener.on_change(changed_dirs, :recursive => true)
         
     | 
| 
      
 69 
     | 
    
         
            +
                    end
         
     | 
| 
      
 70 
     | 
    
         
            +
                  end
         
     | 
| 
      
 71 
     | 
    
         
            +
             
     | 
| 
      
 72 
     | 
    
         
            +
                end
         
     | 
| 
      
 73 
     | 
    
         
            +
             
     | 
| 
      
 74 
     | 
    
         
            +
              end
         
     | 
| 
      
 75 
     | 
    
         
            +
            end
         
     | 
    
        data/lib/listen/listener.rb
    CHANGED
    
    | 
         @@ -1,13 +1,18 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            require 'find'
         
     | 
| 
      
 2 
     | 
    
         
            +
            require 'digest/sha1'
         
     | 
| 
      
 3 
     | 
    
         
            +
             
     | 
| 
       2 
4 
     | 
    
         
             
            require 'listen/adapter'
         
     | 
| 
      
 5 
     | 
    
         
            +
            require 'listen/adapters/darwin'
         
     | 
| 
      
 6 
     | 
    
         
            +
            require 'listen/adapters/linux'
         
     | 
| 
       3 
7 
     | 
    
         
             
            require 'listen/adapters/polling'
         
     | 
| 
      
 8 
     | 
    
         
            +
            require 'listen/adapters/windows'
         
     | 
| 
       4 
9 
     | 
    
         | 
| 
       5 
10 
     | 
    
         
             
            module Listen
         
     | 
| 
       6 
11 
     | 
    
         
             
              class Listener
         
     | 
| 
       7 
     | 
    
         
            -
                attr_accessor :directory, :ignored_paths, :file_filters, :paths
         
     | 
| 
      
 12 
     | 
    
         
            +
                attr_accessor :directory, :ignored_paths, :file_filters, :sha1_checksums, :paths, :adapter
         
     | 
| 
       8 
13 
     | 
    
         | 
| 
       9 
14 
     | 
    
         
             
                # Default paths that gets ignored by the listener
         
     | 
| 
       10 
     | 
    
         
            -
                DEFAULT_IGNORED_PATHS = %w[.bundle .git log tmp vendor]
         
     | 
| 
      
 15 
     | 
    
         
            +
                DEFAULT_IGNORED_PATHS = %w[.bundle .git .DS_Store log tmp vendor]
         
     | 
| 
       11 
16 
     | 
    
         | 
| 
       12 
17 
     | 
    
         
             
                # Initialize the file listener.
         
     | 
| 
       13 
18 
     | 
    
         
             
                #
         
     | 
| 
         @@ -24,10 +29,11 @@ module Listen 
     | 
|
| 
       24 
29 
     | 
    
         
             
                # @return [Listen::Listener] the file listener
         
     | 
| 
       25 
30 
     | 
    
         
             
                #
         
     | 
| 
       26 
31 
     | 
    
         
             
                def initialize(*args, &block)
         
     | 
| 
       27 
     | 
    
         
            -
                  @directory 
     | 
| 
       28 
     | 
    
         
            -
                  @ignored_paths 
     | 
| 
       29 
     | 
    
         
            -
                  @file_filters 
     | 
| 
       30 
     | 
    
         
            -
                  @ 
     | 
| 
      
 32 
     | 
    
         
            +
                  @directory      = args.first
         
     | 
| 
      
 33 
     | 
    
         
            +
                  @ignored_paths  = DEFAULT_IGNORED_PATHS
         
     | 
| 
      
 34 
     | 
    
         
            +
                  @file_filters   = []
         
     | 
| 
      
 35 
     | 
    
         
            +
                  @sha1_checksums = {}
         
     | 
| 
      
 36 
     | 
    
         
            +
                  @block          = block
         
     | 
| 
       31 
37 
     | 
    
         
             
                  if args[1]
         
     | 
| 
       32 
38 
     | 
    
         
             
                    @ignored_paths += Array(args[1][:ignore]) if args[1][:ignore]
         
     | 
| 
       33 
39 
     | 
    
         
             
                    @file_filters  += Array(args[1][:filter]) if args[1][:filter]
         
     | 
| 
         @@ -93,31 +99,38 @@ module Listen 
     | 
|
| 
       93 
99 
     | 
    
         | 
| 
       94 
100 
     | 
    
         
             
                # Call @block callback when there is a diff in the passed directory.
         
     | 
| 
       95 
101 
     | 
    
         
             
                #
         
     | 
| 
       96 
     | 
    
         
            -
                # @param [ 
     | 
| 
      
 102 
     | 
    
         
            +
                # @param [Array] directories the list of directories to diff
         
     | 
| 
       97 
103 
     | 
    
         
             
                #
         
     | 
| 
       98 
     | 
    
         
            -
                def on_change( 
     | 
| 
       99 
     | 
    
         
            -
                  changes = diff( 
     | 
| 
       100 
     | 
    
         
            -
                  unless changes  
     | 
| 
      
 104 
     | 
    
         
            +
                def on_change(directories, diff_options = {})
         
     | 
| 
      
 105 
     | 
    
         
            +
                  changes = diff(directories, diff_options)
         
     | 
| 
      
 106 
     | 
    
         
            +
                  unless changes.values.all? { |paths| paths.empty? }
         
     | 
| 
       101 
107 
     | 
    
         
             
                    @block.call(changes[:modified],changes[:added],changes[:removed])
         
     | 
| 
       102 
108 
     | 
    
         
             
                  end
         
     | 
| 
       103 
109 
     | 
    
         
             
                end
         
     | 
| 
       104 
110 
     | 
    
         | 
| 
       105 
     | 
    
         
            -
                # Initialize the @paths double levels Hash with all existing paths.
         
     | 
| 
      
 111 
     | 
    
         
            +
                # Initialize the @paths double levels Hash with all existing paths and set diffed_at.
         
     | 
| 
       106 
112 
     | 
    
         
             
                #
         
     | 
| 
       107 
113 
     | 
    
         
             
                def init_paths
         
     | 
| 
       108 
114 
     | 
    
         
             
                  @paths = Hash.new { |h,k| h[k] = {} }
         
     | 
| 
       109 
115 
     | 
    
         
             
                  all_existing_paths { |path| insert_path(path) }
         
     | 
| 
      
 116 
     | 
    
         
            +
                  @diffed_at = Time.now.to_i
         
     | 
| 
       110 
117 
     | 
    
         
             
                end
         
     | 
| 
       111 
118 
     | 
    
         | 
| 
       112 
119 
     | 
    
         
             
                # Detect changes diff in a directory.
         
     | 
| 
       113 
120 
     | 
    
         
             
                #
         
     | 
| 
       114 
     | 
    
         
            -
                # @param [ 
     | 
| 
      
 121 
     | 
    
         
            +
                # @param [Array] directories the list of directories to diff
         
     | 
| 
      
 122 
     | 
    
         
            +
                # @param [Hash] options
         
     | 
| 
      
 123 
     | 
    
         
            +
                # @option options [Boolean] recursive scan all sub-direcoties recursively (true when polling)
         
     | 
| 
       115 
124 
     | 
    
         
             
                # @return [Hash<Array>] the file changes
         
     | 
| 
       116 
125 
     | 
    
         
             
                #
         
     | 
| 
       117 
     | 
    
         
            -
                def diff( 
     | 
| 
       118 
     | 
    
         
            -
                  @changes 
     | 
| 
       119 
     | 
    
         
            -
                   
     | 
| 
       120 
     | 
    
         
            -
                   
     | 
| 
      
 126 
     | 
    
         
            +
                def diff(directories, options = {})
         
     | 
| 
      
 127 
     | 
    
         
            +
                  @changes    = { :modified => [], :added => [], :removed => [] }
         
     | 
| 
      
 128 
     | 
    
         
            +
                  directories = directories.sort_by { |el| el.length }.reverse # diff sub-dir first
         
     | 
| 
      
 129 
     | 
    
         
            +
                  directories.each do |directory|
         
     | 
| 
      
 130 
     | 
    
         
            +
                    detect_modifications_and_removals(directory, options)
         
     | 
| 
      
 131 
     | 
    
         
            +
                    detect_additions(directory, options)
         
     | 
| 
      
 132 
     | 
    
         
            +
                  end
         
     | 
| 
      
 133 
     | 
    
         
            +
                  @diffed_at = Time.now.to_i
         
     | 
| 
       121 
134 
     | 
    
         
             
                  @changes
         
     | 
| 
       122 
135 
     | 
    
         
             
                end
         
     | 
| 
       123 
136 
     | 
    
         | 
| 
         @@ -129,62 +142,107 @@ module Listen 
     | 
|
| 
       129 
142 
     | 
    
         
             
                #
         
     | 
| 
       130 
143 
     | 
    
         
             
                def all_existing_paths
         
     | 
| 
       131 
144 
     | 
    
         
             
                  Find.find(@directory) do |path|
         
     | 
| 
      
 145 
     | 
    
         
            +
                    next if @directory == path
         
     | 
| 
      
 146 
     | 
    
         
            +
             
     | 
| 
       132 
147 
     | 
    
         
             
                    if File.directory?(path)
         
     | 
| 
       133 
     | 
    
         
            -
                      if  
     | 
| 
      
 148 
     | 
    
         
            +
                      if ignored_path?(path)
         
     | 
| 
       134 
149 
     | 
    
         
             
                        Find.prune # Don't look any further into this directory.
         
     | 
| 
       135 
150 
     | 
    
         
             
                      else
         
     | 
| 
       136 
151 
     | 
    
         
             
                        yield(path)
         
     | 
| 
       137 
152 
     | 
    
         
             
                      end
         
     | 
| 
       138 
     | 
    
         
            -
                    elsif  
     | 
| 
      
 153 
     | 
    
         
            +
                    elsif !ignored_path?(path) && filtered_file?(path)
         
     | 
| 
       139 
154 
     | 
    
         
             
                      yield(path)
         
     | 
| 
       140 
155 
     | 
    
         
             
                    end
         
     | 
| 
       141 
156 
     | 
    
         
             
                  end
         
     | 
| 
       142 
157 
     | 
    
         
             
                end
         
     | 
| 
       143 
158 
     | 
    
         | 
| 
       144 
     | 
    
         
            -
                # Insert a path with its File 
     | 
| 
      
 159 
     | 
    
         
            +
                # Insert a path with its type (Dir or File) in @paths.
         
     | 
| 
       145 
160 
     | 
    
         
             
                #
         
     | 
| 
       146 
161 
     | 
    
         
             
                # @param [String] path the path to insert in @paths.
         
     | 
| 
       147 
162 
     | 
    
         
             
                #
         
     | 
| 
       148 
163 
     | 
    
         
             
                def insert_path(path)
         
     | 
| 
       149 
     | 
    
         
            -
                  @paths[File.dirname(path)][File.basename(path)] = File. 
     | 
| 
      
 164 
     | 
    
         
            +
                  @paths[File.dirname(path)][File.basename(path)] = File.directory?(path) ? 'Dir' : 'File'
         
     | 
| 
      
 165 
     | 
    
         
            +
                end
         
     | 
| 
      
 166 
     | 
    
         
            +
             
     | 
| 
      
 167 
     | 
    
         
            +
                # Find is a path exists in @paths.
         
     | 
| 
      
 168 
     | 
    
         
            +
                #
         
     | 
| 
      
 169 
     | 
    
         
            +
                # @param [String] path the path to find in @paths.
         
     | 
| 
      
 170 
     | 
    
         
            +
                # @return [Boolean]
         
     | 
| 
      
 171 
     | 
    
         
            +
                #
         
     | 
| 
      
 172 
     | 
    
         
            +
                def existing_path?(path)
         
     | 
| 
      
 173 
     | 
    
         
            +
                  @paths[File.dirname(path)][File.basename(path)] != nil
         
     | 
| 
       150 
174 
     | 
    
         
             
                end
         
     | 
| 
       151 
175 
     | 
    
         | 
| 
       152 
176 
     | 
    
         
             
                # Detect modifications and removals recursivly in a directory.
         
     | 
| 
      
 177 
     | 
    
         
            +
                # Modifications detection are based on mtime first and on checksum when mtime == last diffed_at
         
     | 
| 
       153 
178 
     | 
    
         
             
                #
         
     | 
| 
       154 
179 
     | 
    
         
             
                # @param [String] directory the path to analyze
         
     | 
| 
      
 180 
     | 
    
         
            +
                # @param [Hash] options
         
     | 
| 
      
 181 
     | 
    
         
            +
                # @option options [Boolean] recursive scan all sub-direcoties recursively (when polling)
         
     | 
| 
       155 
182 
     | 
    
         
             
                #
         
     | 
| 
       156 
     | 
    
         
            -
                def detect_modifications_and_removals(directory)
         
     | 
| 
       157 
     | 
    
         
            -
                  @paths[directory].each do |basename,  
     | 
| 
      
 183 
     | 
    
         
            +
                def detect_modifications_and_removals(directory, options = {})
         
     | 
| 
      
 184 
     | 
    
         
            +
                  @paths[directory].each do |basename, type|
         
     | 
| 
       158 
185 
     | 
    
         
             
                    path = File.join(directory, basename)
         
     | 
| 
       159 
     | 
    
         
            -
             
     | 
| 
       160 
     | 
    
         
            -
                     
     | 
| 
       161 
     | 
    
         
            -
             
     | 
| 
       162 
     | 
    
         
            -
                       
     | 
| 
       163 
     | 
    
         
            -
             
     | 
| 
      
 186 
     | 
    
         
            +
                    
         
     | 
| 
      
 187 
     | 
    
         
            +
                    case type
         
     | 
| 
      
 188 
     | 
    
         
            +
                    when 'Dir'
         
     | 
| 
      
 189 
     | 
    
         
            +
                      if File.directory?(path)
         
     | 
| 
      
 190 
     | 
    
         
            +
                        detect_modifications_and_removals(path, options) if options[:recursive]
         
     | 
| 
      
 191 
     | 
    
         
            +
                      else
         
     | 
| 
      
 192 
     | 
    
         
            +
                        detect_modifications_and_removals(path, :recursive => true)
         
     | 
| 
      
 193 
     | 
    
         
            +
                        @paths[directory].delete(basename)
         
     | 
| 
      
 194 
     | 
    
         
            +
                        @paths.delete("#{directory}/#{basename}")
         
     | 
| 
      
 195 
     | 
    
         
            +
                      end
         
     | 
| 
      
 196 
     | 
    
         
            +
                    when 'File'
         
     | 
| 
       164 
197 
     | 
    
         
             
                      if File.exist?(path)
         
     | 
| 
       165 
     | 
    
         
            -
                         
     | 
| 
       166 
     | 
    
         
            -
                        if  
     | 
| 
      
 198 
     | 
    
         
            +
                        new_mtime = File.mtime(path).to_i
         
     | 
| 
      
 199 
     | 
    
         
            +
                        if @diffed_at < new_mtime || (@diffed_at == new_mtime && content_modified?(path))
         
     | 
| 
       167 
200 
     | 
    
         
             
                          @changes[:modified] << relative_path(path)
         
     | 
| 
       168 
     | 
    
         
            -
                          @paths[directory][basename] = new_stat
         
     | 
| 
       169 
201 
     | 
    
         
             
                        end
         
     | 
| 
       170 
202 
     | 
    
         
             
                      else
         
     | 
| 
       171 
203 
     | 
    
         
             
                        @paths[directory].delete(basename)
         
     | 
| 
      
 204 
     | 
    
         
            +
                        @sha1_checksums.delete(path)
         
     | 
| 
       172 
205 
     | 
    
         
             
                        @changes[:removed] << relative_path(path)
         
     | 
| 
       173 
206 
     | 
    
         
             
                      end
         
     | 
| 
       174 
207 
     | 
    
         
             
                    end
         
     | 
| 
       175 
208 
     | 
    
         
             
                  end
         
     | 
| 
       176 
209 
     | 
    
         
             
                end
         
     | 
| 
       177 
210 
     | 
    
         | 
| 
      
 211 
     | 
    
         
            +
                # Tests if the file content has been modified by
         
     | 
| 
      
 212 
     | 
    
         
            +
                # comparing the SHA1 checksum.
         
     | 
| 
      
 213 
     | 
    
         
            +
                #
         
     | 
| 
      
 214 
     | 
    
         
            +
                # @param [String] path the file path
         
     | 
| 
      
 215 
     | 
    
         
            +
                #
         
     | 
| 
      
 216 
     | 
    
         
            +
                def content_modified?(path)
         
     | 
| 
      
 217 
     | 
    
         
            +
                  sha1_checksum = Digest::SHA1.file(path).to_s
         
     | 
| 
      
 218 
     | 
    
         
            +
                  if @sha1_checksums[path] != sha1_checksum
         
     | 
| 
      
 219 
     | 
    
         
            +
                    @sha1_checksums[path] = sha1_checksum
         
     | 
| 
      
 220 
     | 
    
         
            +
                    true
         
     | 
| 
      
 221 
     | 
    
         
            +
                  else
         
     | 
| 
      
 222 
     | 
    
         
            +
                    false
         
     | 
| 
      
 223 
     | 
    
         
            +
                  end
         
     | 
| 
      
 224 
     | 
    
         
            +
                end
         
     | 
| 
      
 225 
     | 
    
         
            +
             
     | 
| 
       178 
226 
     | 
    
         
             
                # Detect additions in a directory.
         
     | 
| 
       179 
227 
     | 
    
         
             
                #
         
     | 
| 
       180 
228 
     | 
    
         
             
                # @param [String] directory the path to analyze
         
     | 
| 
      
 229 
     | 
    
         
            +
                # @param [Hash] options
         
     | 
| 
      
 230 
     | 
    
         
            +
                # @option options [Boolean] recursive scan all sub-direcoties recursively (when polling)
         
     | 
| 
       181 
231 
     | 
    
         
             
                #
         
     | 
| 
       182 
     | 
    
         
            -
                def detect_additions(directory)
         
     | 
| 
       183 
     | 
    
         
            -
                   
     | 
| 
       184 
     | 
    
         
            -
                    next if @ 
     | 
| 
      
 232 
     | 
    
         
            +
                def detect_additions(directory, options = {})
         
     | 
| 
      
 233 
     | 
    
         
            +
                  Find.find(directory) do |path|
         
     | 
| 
      
 234 
     | 
    
         
            +
                    next if @directory == path
         
     | 
| 
       185 
235 
     | 
    
         | 
| 
       186 
     | 
    
         
            -
                     
     | 
| 
       187 
     | 
    
         
            -
             
     | 
| 
      
 236 
     | 
    
         
            +
                    if File.directory?(path)
         
     | 
| 
      
 237 
     | 
    
         
            +
                      if directory != path && (ignored_path?(path) || (!options[:recursive] && existing_path?(path)))
         
     | 
| 
      
 238 
     | 
    
         
            +
                        Find.prune # Don't look any further into this directory.
         
     | 
| 
      
 239 
     | 
    
         
            +
                      else
         
     | 
| 
      
 240 
     | 
    
         
            +
                        insert_path(path)
         
     | 
| 
      
 241 
     | 
    
         
            +
                      end
         
     | 
| 
      
 242 
     | 
    
         
            +
                    elsif !existing_path?(path) && !ignored_path?(path) && filtered_file?(path)
         
     | 
| 
      
 243 
     | 
    
         
            +
                      @changes[:added] << relative_path(path) if File.file?(path)
         
     | 
| 
      
 244 
     | 
    
         
            +
                      insert_path(path)
         
     | 
| 
      
 245 
     | 
    
         
            +
                    end
         
     | 
| 
       188 
246 
     | 
    
         
             
                  end
         
     | 
| 
       189 
247 
     | 
    
         
             
                end
         
     | 
| 
       190 
248 
     | 
    
         | 
| 
         @@ -199,5 +257,23 @@ module Listen 
     | 
|
| 
       199 
257 
     | 
    
         
             
                  path.sub(%r(^#{base_dir}/), '')
         
     | 
| 
       200 
258 
     | 
    
         
             
                end
         
     | 
| 
       201 
259 
     | 
    
         | 
| 
      
 260 
     | 
    
         
            +
                # Test if a path should be ignored or not.
         
     | 
| 
      
 261 
     | 
    
         
            +
                #
         
     | 
| 
      
 262 
     | 
    
         
            +
                # @param [String] path the path to test.
         
     | 
| 
      
 263 
     | 
    
         
            +
                # @return [Boolean]
         
     | 
| 
      
 264 
     | 
    
         
            +
                #
         
     | 
| 
      
 265 
     | 
    
         
            +
                def ignored_path?(path)
         
     | 
| 
      
 266 
     | 
    
         
            +
                  @ignored_paths.any? { |ignored_path| path =~ /#{ignored_path}$/ }
         
     | 
| 
      
 267 
     | 
    
         
            +
                end
         
     | 
| 
      
 268 
     | 
    
         
            +
             
     | 
| 
      
 269 
     | 
    
         
            +
                # Test if a file path should be filtered or not.
         
     | 
| 
      
 270 
     | 
    
         
            +
                #
         
     | 
| 
      
 271 
     | 
    
         
            +
                # @param [String] path the file path to test.
         
     | 
| 
      
 272 
     | 
    
         
            +
                # @return [Boolean]
         
     | 
| 
      
 273 
     | 
    
         
            +
                #
         
     | 
| 
      
 274 
     | 
    
         
            +
                def filtered_file?(path)
         
     | 
| 
      
 275 
     | 
    
         
            +
                  @file_filters.empty? || @file_filters.any? { |file_filter| path =~ file_filter }
         
     | 
| 
      
 276 
     | 
    
         
            +
                end
         
     | 
| 
      
 277 
     | 
    
         
            +
             
     | 
| 
       202 
278 
     | 
    
         
             
              end
         
     | 
| 
       203 
279 
     | 
    
         
             
            end
         
     | 
    
        data/lib/listen/version.rb
    CHANGED
    
    
    
        metadata
    CHANGED
    
    | 
         @@ -1,89 +1,53 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            --- !ruby/object:Gem::Specification
         
     | 
| 
       2 
2 
     | 
    
         
             
            name: listen
         
     | 
| 
       3 
3 
     | 
    
         
             
            version: !ruby/object:Gem::Version
         
     | 
| 
       4 
     | 
    
         
            -
              version: 0. 
     | 
| 
      
 4 
     | 
    
         
            +
              version: 0.2.0
         
     | 
| 
       5 
5 
     | 
    
         
             
              prerelease: 
         
     | 
| 
       6 
6 
     | 
    
         
             
            platform: ruby
         
     | 
| 
       7 
7 
     | 
    
         
             
            authors:
         
     | 
| 
       8 
     | 
    
         
            -
            - Travis Tilley
         
     | 
| 
       9 
     | 
    
         
            -
            - Yehuda Katz
         
     | 
| 
       10 
8 
     | 
    
         
             
            - Thibaud Guillaume-Gentil
         
     | 
| 
       11 
     | 
    
         
            -
            - Rémy Coutable
         
     | 
| 
       12 
9 
     | 
    
         
             
            - Michael Kessler
         
     | 
| 
       13 
10 
     | 
    
         
             
            autorequire: 
         
     | 
| 
       14 
11 
     | 
    
         
             
            bindir: bin
         
     | 
| 
       15 
12 
     | 
    
         
             
            cert_chain: []
         
     | 
| 
       16 
     | 
    
         
            -
            date: 2012- 
     | 
| 
      
 13 
     | 
    
         
            +
            date: 2012-02-12 00:00:00.000000000 Z
         
     | 
| 
       17 
14 
     | 
    
         
             
            dependencies:
         
     | 
| 
       18 
15 
     | 
    
         
             
            - !ruby/object:Gem::Dependency
         
     | 
| 
       19 
     | 
    
         
            -
              name:  
     | 
| 
       20 
     | 
    
         
            -
              requirement: & 
     | 
| 
       21 
     | 
    
         
            -
                none: false
         
     | 
| 
       22 
     | 
    
         
            -
                requirements:
         
     | 
| 
       23 
     | 
    
         
            -
                - - ! '>='
         
     | 
| 
       24 
     | 
    
         
            -
                  - !ruby/object:Gem::Version
         
     | 
| 
       25 
     | 
    
         
            -
                    version: '0'
         
     | 
| 
       26 
     | 
    
         
            -
              type: :development
         
     | 
| 
       27 
     | 
    
         
            -
              prerelease: false
         
     | 
| 
       28 
     | 
    
         
            -
              version_requirements: *70178027214260
         
     | 
| 
       29 
     | 
    
         
            -
            - !ruby/object:Gem::Dependency
         
     | 
| 
       30 
     | 
    
         
            -
              name: guard
         
     | 
| 
       31 
     | 
    
         
            -
              requirement: &70178027229800 !ruby/object:Gem::Requirement
         
     | 
| 
      
 16 
     | 
    
         
            +
              name: rb-fsevent
         
     | 
| 
      
 17 
     | 
    
         
            +
              requirement: &70294412755220 !ruby/object:Gem::Requirement
         
     | 
| 
       32 
18 
     | 
    
         
             
                none: false
         
     | 
| 
       33 
19 
     | 
    
         
             
                requirements:
         
     | 
| 
       34 
20 
     | 
    
         
             
                - - ~>
         
     | 
| 
       35 
21 
     | 
    
         
             
                  - !ruby/object:Gem::Version
         
     | 
| 
       36 
     | 
    
         
            -
                    version:  
     | 
| 
       37 
     | 
    
         
            -
              type: : 
     | 
| 
      
 22 
     | 
    
         
            +
                    version: 0.9.0
         
     | 
| 
      
 23 
     | 
    
         
            +
              type: :runtime
         
     | 
| 
       38 
24 
     | 
    
         
             
              prerelease: false
         
     | 
| 
       39 
     | 
    
         
            -
              version_requirements: * 
     | 
| 
      
 25 
     | 
    
         
            +
              version_requirements: *70294412755220
         
     | 
| 
       40 
26 
     | 
    
         
             
            - !ruby/object:Gem::Dependency
         
     | 
| 
       41 
     | 
    
         
            -
              name:  
     | 
| 
       42 
     | 
    
         
            -
              requirement: & 
     | 
| 
      
 27 
     | 
    
         
            +
              name: rb-inotify
         
     | 
| 
      
 28 
     | 
    
         
            +
              requirement: &70294412770880 !ruby/object:Gem::Requirement
         
     | 
| 
       43 
29 
     | 
    
         
             
                none: false
         
     | 
| 
       44 
30 
     | 
    
         
             
                requirements:
         
     | 
| 
       45 
31 
     | 
    
         
             
                - - ~>
         
     | 
| 
       46 
32 
     | 
    
         
             
                  - !ruby/object:Gem::Version
         
     | 
| 
       47 
     | 
    
         
            -
                    version:  
     | 
| 
       48 
     | 
    
         
            -
              type: : 
     | 
| 
      
 33 
     | 
    
         
            +
                    version: 0.8.8
         
     | 
| 
      
 34 
     | 
    
         
            +
              type: :runtime
         
     | 
| 
       49 
35 
     | 
    
         
             
              prerelease: false
         
     | 
| 
       50 
     | 
    
         
            -
              version_requirements: * 
     | 
| 
      
 36 
     | 
    
         
            +
              version_requirements: *70294412770880
         
     | 
| 
       51 
37 
     | 
    
         
             
            - !ruby/object:Gem::Dependency
         
     | 
| 
       52 
     | 
    
         
            -
              name:  
     | 
| 
       53 
     | 
    
         
            -
              requirement: & 
     | 
| 
      
 38 
     | 
    
         
            +
              name: rb-fchange
         
     | 
| 
      
 39 
     | 
    
         
            +
              requirement: &70294412770160 !ruby/object:Gem::Requirement
         
     | 
| 
       54 
40 
     | 
    
         
             
                none: false
         
     | 
| 
       55 
41 
     | 
    
         
             
                requirements:
         
     | 
| 
       56 
42 
     | 
    
         
             
                - - ~>
         
     | 
| 
       57 
43 
     | 
    
         
             
                  - !ruby/object:Gem::Version
         
     | 
| 
       58 
     | 
    
         
            -
                    version: 0. 
     | 
| 
       59 
     | 
    
         
            -
              type: : 
     | 
| 
      
 44 
     | 
    
         
            +
                    version: 0.0.5
         
     | 
| 
      
 45 
     | 
    
         
            +
              type: :runtime
         
     | 
| 
       60 
46 
     | 
    
         
             
              prerelease: false
         
     | 
| 
       61 
     | 
    
         
            -
              version_requirements: * 
     | 
| 
      
 47 
     | 
    
         
            +
              version_requirements: *70294412770160
         
     | 
| 
       62 
48 
     | 
    
         
             
            - !ruby/object:Gem::Dependency
         
     | 
| 
       63 
     | 
    
         
            -
              name:  
     | 
| 
       64 
     | 
    
         
            -
              requirement: & 
     | 
| 
       65 
     | 
    
         
            -
                none: false
         
     | 
| 
       66 
     | 
    
         
            -
                requirements:
         
     | 
| 
       67 
     | 
    
         
            -
                - - ! '>='
         
     | 
| 
       68 
     | 
    
         
            -
                  - !ruby/object:Gem::Version
         
     | 
| 
       69 
     | 
    
         
            -
                    version: '0'
         
     | 
| 
       70 
     | 
    
         
            -
              type: :development
         
     | 
| 
       71 
     | 
    
         
            -
              prerelease: false
         
     | 
| 
       72 
     | 
    
         
            -
              version_requirements: *70178027227420
         
     | 
| 
       73 
     | 
    
         
            -
            - !ruby/object:Gem::Dependency
         
     | 
| 
       74 
     | 
    
         
            -
              name: redcarpet
         
     | 
| 
       75 
     | 
    
         
            -
              requirement: &70178027226740 !ruby/object:Gem::Requirement
         
     | 
| 
       76 
     | 
    
         
            -
                none: false
         
     | 
| 
       77 
     | 
    
         
            -
                requirements:
         
     | 
| 
       78 
     | 
    
         
            -
                - - ! '>='
         
     | 
| 
       79 
     | 
    
         
            -
                  - !ruby/object:Gem::Version
         
     | 
| 
       80 
     | 
    
         
            -
                    version: '0'
         
     | 
| 
       81 
     | 
    
         
            -
              type: :development
         
     | 
| 
       82 
     | 
    
         
            -
              prerelease: false
         
     | 
| 
       83 
     | 
    
         
            -
              version_requirements: *70178027226740
         
     | 
| 
       84 
     | 
    
         
            -
            - !ruby/object:Gem::Dependency
         
     | 
| 
       85 
     | 
    
         
            -
              name: pry
         
     | 
| 
       86 
     | 
    
         
            -
              requirement: &70178027226280 !ruby/object:Gem::Requirement
         
     | 
| 
      
 49 
     | 
    
         
            +
              name: bundler
         
     | 
| 
      
 50 
     | 
    
         
            +
              requirement: &70294412769580 !ruby/object:Gem::Requirement
         
     | 
| 
       87 
51 
     | 
    
         
             
                none: false
         
     | 
| 
       88 
52 
     | 
    
         
             
                requirements:
         
     | 
| 
       89 
53 
     | 
    
         
             
                - - ! '>='
         
     | 
| 
         @@ -91,21 +55,21 @@ dependencies: 
     | 
|
| 
       91 
55 
     | 
    
         
             
                    version: '0'
         
     | 
| 
       92 
56 
     | 
    
         
             
              type: :development
         
     | 
| 
       93 
57 
     | 
    
         
             
              prerelease: false
         
     | 
| 
       94 
     | 
    
         
            -
              version_requirements: * 
     | 
| 
      
 58 
     | 
    
         
            +
              version_requirements: *70294412769580
         
     | 
| 
       95 
59 
     | 
    
         
             
            description: The Listen gem listens to file modifications and notifies you about the
         
     | 
| 
       96 
     | 
    
         
            -
              changes.
         
     | 
| 
      
 60 
     | 
    
         
            +
              changes. Works everywhere!
         
     | 
| 
       97 
61 
     | 
    
         
             
            email:
         
     | 
| 
       98 
     | 
    
         
            -
            - ttilley@gmail.com
         
     | 
| 
       99 
     | 
    
         
            -
            - wycats@gmail.com
         
     | 
| 
       100 
62 
     | 
    
         
             
            - thibaud@thibaud.me
         
     | 
| 
       101 
     | 
    
         
            -
            - rymai@rymai.me
         
     | 
| 
       102 
63 
     | 
    
         
             
            - michi@netzpiraten.ch
         
     | 
| 
       103 
64 
     | 
    
         
             
            executables: []
         
     | 
| 
       104 
65 
     | 
    
         
             
            extensions: []
         
     | 
| 
       105 
66 
     | 
    
         
             
            extra_rdoc_files: []
         
     | 
| 
       106 
67 
     | 
    
         
             
            files:
         
     | 
| 
       107 
68 
     | 
    
         
             
            - lib/listen/adapter.rb
         
     | 
| 
      
 69 
     | 
    
         
            +
            - lib/listen/adapters/darwin.rb
         
     | 
| 
      
 70 
     | 
    
         
            +
            - lib/listen/adapters/linux.rb
         
     | 
| 
       108 
71 
     | 
    
         
             
            - lib/listen/adapters/polling.rb
         
     | 
| 
      
 72 
     | 
    
         
            +
            - lib/listen/adapters/windows.rb
         
     | 
| 
       109 
73 
     | 
    
         
             
            - lib/listen/listener.rb
         
     | 
| 
       110 
74 
     | 
    
         
             
            - lib/listen/version.rb
         
     | 
| 
       111 
75 
     | 
    
         
             
            - lib/listen.rb
         
     | 
| 
         @@ -124,9 +88,6 @@ required_ruby_version: !ruby/object:Gem::Requirement 
     | 
|
| 
       124 
88 
     | 
    
         
             
              - - ! '>='
         
     | 
| 
       125 
89 
     | 
    
         
             
                - !ruby/object:Gem::Version
         
     | 
| 
       126 
90 
     | 
    
         
             
                  version: '0'
         
     | 
| 
       127 
     | 
    
         
            -
                  segments:
         
     | 
| 
       128 
     | 
    
         
            -
                  - 0
         
     | 
| 
       129 
     | 
    
         
            -
                  hash: -4340389000594607932
         
     | 
| 
       130 
91 
     | 
    
         
             
            required_rubygems_version: !ruby/object:Gem::Requirement
         
     | 
| 
       131 
92 
     | 
    
         
             
              none: false
         
     | 
| 
       132 
93 
     | 
    
         
             
              requirements:
         
     | 
| 
         @@ -135,7 +96,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement 
     | 
|
| 
       135 
96 
     | 
    
         
             
                  version: 1.3.6
         
     | 
| 
       136 
97 
     | 
    
         
             
            requirements: []
         
     | 
| 
       137 
98 
     | 
    
         
             
            rubyforge_project: listen
         
     | 
| 
       138 
     | 
    
         
            -
            rubygems_version: 1.8. 
     | 
| 
      
 99 
     | 
    
         
            +
            rubygems_version: 1.8.15
         
     | 
| 
       139 
100 
     | 
    
         
             
            signing_key: 
         
     | 
| 
       140 
101 
     | 
    
         
             
            specification_version: 3
         
     | 
| 
       141 
102 
     | 
    
         
             
            summary: Listen to file modifications
         
     |