watchr 0.5.9 → 0.6

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.
@@ -2,55 +2,58 @@ module Watchr
2
2
 
3
3
  # The controller contains the app's core logic.
4
4
  #
5
- # ===== Examples
5
+ # @example
6
6
  #
7
- # script = Watchr::Script.new(file)
8
- # contrl = Watchr::Controller.new(script)
9
- # contrl.run
7
+ # script = Watchr::Script.new(file)
8
+ # contrl = Watchr::Controller.new(script, Watchr.handler.new)
9
+ # contrl.run
10
10
  #
11
- # Calling <tt>#run</tt> will enter the listening loop, and from then on every
12
- # file event will trigger its corresponding action defined in <tt>script</tt>
11
+ # # Calling `run` will enter the listening loop, and from then on every
12
+ # # file event will trigger its corresponding action defined in `script`
13
13
  #
14
- # The controller also automatically adds the script's file itself to its list
15
- # of monitored files and will detect any changes to it, providing on the fly
16
- # updates of defined rules.
14
+ # # The controller also automatically adds the script's file to its list of
15
+ # # monitored files and will detect any changes to it, providing on the fly
16
+ # # updates of defined rules.
17
17
  #
18
18
  class Controller
19
19
 
20
- # Creates a controller object around given <tt>script</tt>
20
+ # Create a controller object around given `script`
21
21
  #
22
- # ===== Parameters
23
- # script<Script>:: The script object
24
- # handler<EventHanlder::Base>:: The filesystem event handler
22
+ # @param [Script] script
23
+ # The script object
24
+ #
25
+ # @param [EventHandler::Base] handler
26
+ # The filesystem event handler
27
+ #
28
+ # @see Watchr::Script
29
+ # @see Watchr.handler
25
30
  #
26
31
  def initialize(script, handler)
27
- @script = script
28
- @handler = handler
29
-
32
+ @script, @handler = script, handler
30
33
  @handler.add_observer(self)
31
34
 
32
35
  Watchr.debug "using %s handler" % handler.class.name
33
36
  end
34
37
 
35
- # Enters listening loop.
36
- #
37
- # Will block control flow until application is explicitly stopped/killed.
38
- #
38
+ # Enter listening loop. Will block control flow until application is
39
+ # explicitly stopped/killed.
39
40
  def run
40
41
  @script.parse!
41
42
  @handler.listen(monitored_paths)
42
43
  rescue Interrupt
43
44
  end
44
45
 
45
- # Callback for file events.
46
+ # Callback for file events
46
47
  #
47
48
  # Called while control flow is in listening loop. It will execute the
48
49
  # file's corresponding action as defined in the script. If the file is the
49
50
  # script itself, it will refresh its state to account for potential changes.
50
51
  #
51
- # ===== Parameters
52
- # path<Pathname, String>:: path that triggered event
53
- # event_type<Symbol>:: event type
52
+ # @param [Pathname, String] path
53
+ # path that triggered the event
54
+ #
55
+ # @param [Symbol] event
56
+ # event type
54
57
  #
55
58
  def update(path, event_type = nil)
56
59
  path = Pathname(path).expand_path
@@ -68,8 +71,8 @@ module Watchr
68
71
  # Basically this means all paths below current directoly recursivelly that
69
72
  # match any of the rules' patterns, plus the script file.
70
73
  #
71
- # ===== Returns
72
- # paths<Array[Pathname]>:: List of monitored paths
74
+ # @return [Array<Pathname>]
75
+ # list of all monitored paths
73
76
  #
74
77
  def monitored_paths
75
78
  paths = Dir['**/*'].select do |path|
@@ -2,32 +2,40 @@ require 'observer'
2
2
 
3
3
  module Watchr
4
4
  module EventHandler
5
- class AbstractMethod < Exception #:nodoc:
6
- end
7
5
 
8
- # Base functionality mixin meant to be included in specific event handlers.
6
+ # @private
7
+ class AbstractMethod < Exception; end
8
+
9
+ # Base functionality mixin, meant to be included in specific event handlers.
10
+ #
11
+ # @abstract
9
12
  module Base
10
13
  include Observable
11
14
 
12
15
  # Notify that a file was modified.
13
16
  #
14
- # ===== Parameters
15
- # path<Pathname, String>:: full path or path relative to current working directory
16
- # event_type<Symbol>:: event type.
17
- #--
18
- # #changed and #notify_observers are Observable methods
17
+ # @param [Pathname, String] path
18
+ # full path or path relative to current working directory
19
+ #
20
+ # @param [Symbol] event
21
+ # event type.
22
+ #
23
+ # @return [undefined]
24
+ #
19
25
  def notify(path, event_type = nil)
20
26
  changed(true)
21
27
  notify_observers(path, event_type)
22
28
  end
23
29
 
24
- # Begin watching given paths and enter listening loop. Called by the controller.
30
+ # Begin watching given paths and enter listening loop. Called by the
31
+ # controller.
25
32
  #
26
- # Abstract method
33
+ # @param [Array<Pathname>] monitored_paths
34
+ # list of paths the application is currently monitoring.
27
35
  #
28
- # ===== Parameters
29
- # monitored_paths<Array(Pathname)>:: list of paths the application is currently monitoring.
36
+ # @return [undefined]
30
37
  #
38
+ # @abstract
31
39
  def listen(monitored_paths)
32
40
  raise AbstractMethod
33
41
  end
@@ -35,11 +43,12 @@ module Watchr
35
43
  # Called by the controller when the list of paths monitored by wantchr
36
44
  # has changed. It should refresh the list of paths being watched.
37
45
  #
38
- # Abstract method
46
+ # @param [Array<Pathname>] monitored_paths
47
+ # list of paths the application is currently monitoring.
39
48
  #
40
- # ===== Parameters
41
- # monitored_paths<Array(Pathname)>:: list of paths the application is currently monitoring.
49
+ # @return [undefined]
42
50
  #
51
+ # @abstract
43
52
  def refresh(monitored_paths)
44
53
  raise AbstractMethod
45
54
  end
@@ -11,18 +11,33 @@ module Watchr
11
11
  #
12
12
  # Will block control flow until application is explicitly stopped/killed.
13
13
  #
14
+ # @param [Array<Pathname>] monitored_paths
15
+ # list of paths the application is currently monitoring.
16
+ #
17
+ # @return [undefined]
18
+ #
14
19
  def listen(monitored_paths)
15
20
  @monitored_paths = monitored_paths
16
21
  loop { trigger; sleep(1) }
17
22
  end
18
23
 
19
24
  # See if an event occured, and if so notify observers.
20
- def trigger #:nodoc:
25
+ #
26
+ # @return [undefined]
27
+ #
28
+ # @private
29
+ def trigger
21
30
  path, type = detect_event
22
31
  notify(path, type) unless path.nil?
23
32
  end
24
33
 
25
34
  # Update list of monitored paths.
35
+ #
36
+ # @param [Array<Pathname>] monitored_paths
37
+ # list of paths the application is currently monitoring.
38
+ #
39
+ # @return [undefined]
40
+ #
26
41
  def refresh(monitored_paths)
27
42
  @monitored_paths = monitored_paths
28
43
  end
@@ -34,13 +49,12 @@ module Watchr
34
49
  # If the latest mtime is more recent than the reference mtime, return
35
50
  # that file's path.
36
51
  #
37
- # ===== Returns
38
- # path and type of event if event occured, nil otherwise
52
+ # @return [[Pathname, Symbol]]
53
+ # path and type of event if event occured, nil otherwise
54
+ #
55
+ # @todo improve ENOENT error handling
39
56
  #
40
- #--
41
- # OPTIMIZE, REFACTOR
42
- # TODO fix/figure out ENOENT error
43
- def detect_event
57
+ def detect_event # OPTIMIZE, REFACTOR
44
58
  @monitored_paths.each do |path|
45
59
  return [path, :deleted] unless path.exist?
46
60
  end
@@ -3,27 +3,41 @@ module Watchr
3
3
  class Unix
4
4
  include Base
5
5
 
6
- # Used by Rev. Wraps a monitored path, and Rev::Loop will call its
6
+ # Used by Rev. Wraps a monitored path, and `Rev::Loop` will call its
7
7
  # callback on file events.
8
- class SingleFileWatcher < Rev::StatWatcher #:nodoc:
8
+ #
9
+ # @private
10
+ class SingleFileWatcher < Rev::StatWatcher
9
11
  class << self
10
- # Stores a reference back to handler so we can call its #nofity
12
+ # Stores a reference back to handler so we can call its {Base#notify notify}
11
13
  # method with file event info
14
+ #
15
+ # @return [EventHandler::Base]
16
+ #
12
17
  attr_accessor :handler
13
18
  end
14
19
 
20
+ # @param [String] path
21
+ # single file to monitor
22
+ #
15
23
  def initialize(path)
16
24
  super
17
25
  update_reference_times
18
26
  end
19
27
 
20
28
  # File's path as a Pathname
29
+ #
30
+ # @return [Pathname]
31
+ #
21
32
  def pathname
22
33
  @pathname ||= Pathname(@path)
23
34
  end
24
35
 
25
- # Callback. Called on file change event
26
- # Delegates to Controller#update, passing in path and event type
36
+ # Callback. Called on file change event. Delegates to
37
+ # {Controller#update}, passing in path and event type
38
+ #
39
+ # @return [undefined]
40
+ #
27
41
  def on_change
28
42
  self.class.handler.notify(path, type)
29
43
  update_reference_times unless type == :deleted
@@ -31,8 +45,7 @@ module Watchr
31
45
 
32
46
  private
33
47
 
34
- #--
35
- # TODO fix/figure out ENOENT error
48
+ # @todo improve ENOENT error handling
36
49
  def update_reference_times
37
50
  @reference_atime = pathname.atime
38
51
  @reference_mtime = pathname.mtime
@@ -47,10 +60,10 @@ module Watchr
47
60
  # have changed on the file. The type is the first to match in the
48
61
  # following hierarchy:
49
62
  #
50
- # :deleted, :modified (mtime), :accessed (atime), :changed (ctime)
63
+ # :deleted, :modified (mtime), :accessed (atime), :changed (ctime)
51
64
  #
52
- # ===== Returns
53
- # type<Symbol>:: latest event's type
65
+ # @return [Symbol] type
66
+ # latest event's type
54
67
  #
55
68
  def type
56
69
  return :deleted if !pathname.exist?
@@ -65,9 +78,10 @@ module Watchr
65
78
  @loop = Rev::Loop.default
66
79
  end
67
80
 
68
- # Enters listening loop.
81
+ # Enters listening loop. Will block control flow until application is
82
+ # explicitly stopped/killed.
69
83
  #
70
- # Will block control flow until application is explicitly stopped/killed.
84
+ # @return [undefined]
71
85
  #
72
86
  def listen(monitored_paths)
73
87
  @monitored_paths = monitored_paths
@@ -75,9 +89,13 @@ module Watchr
75
89
  @loop.run
76
90
  end
77
91
 
78
- # Rebuilds file bindings.
92
+ # Rebuilds file bindings. Will detach all current bindings, and reattach
93
+ # the `monitored_paths`
79
94
  #
80
- # will detach all current bindings, and reattach the <tt>monitored_paths</tt>
95
+ # @param [Array<Pathname>] monitored_paths
96
+ # list of paths the application is currently monitoring.
97
+ #
98
+ # @return [undefined]
81
99
  #
82
100
  def refresh(monitored_paths)
83
101
  @monitored_paths = monitored_paths
@@ -87,12 +105,18 @@ module Watchr
87
105
 
88
106
  private
89
107
 
90
- # Binds all <tt>monitored_paths</tt> to the listening loop.
108
+ # Binds all `monitored_paths` to the listening loop.
109
+ #
110
+ # @return [undefined]
111
+ #
91
112
  def attach
92
113
  @monitored_paths.each {|path| SingleFileWatcher.new(path.to_s).attach(@loop) }
93
114
  end
94
115
 
95
116
  # Unbinds all paths currently attached to listening loop.
117
+ #
118
+ # @return [undefined]
119
+ #
96
120
  def detach
97
121
  @loop.watchers.each {|watcher| watcher.detach }
98
122
  end
data/lib/watchr/script.rb CHANGED
@@ -2,21 +2,23 @@ module Watchr
2
2
 
3
3
  # A script object wraps a script file, and is used by a controller.
4
4
  #
5
- # ===== Examples
5
+ # @example
6
6
  #
7
- # path = Pathname.new('specs.watchr')
8
- # script = Watchr::Script.new(path)
7
+ # path = Pathname.new('specs.watchr')
8
+ # script = Watchr::Script.new(path)
9
9
  #
10
10
  class Script
11
+
12
+ # @private
11
13
  DEFAULT_EVENT_TYPE = :modified
12
14
 
13
15
  # Convenience type. Provides clearer and simpler access to rule properties.
14
16
  #
15
- # ===== Examples
17
+ # @example
16
18
  #
17
- # rule = script.watch('lib/.*\.rb') { 'ohaie' }
18
- # rule.pattern #=> 'lib/.*\.rb'
19
- # rule.action.call #=> 'ohaie'
19
+ # rule = script.watch('lib/.*\.rb') { 'ohaie' }
20
+ # rule.pattern #=> 'lib/.*\.rb'
21
+ # rule.action.call #=> 'ohaie'
20
22
  #
21
23
  Rule = Struct.new(:pattern, :event_type, :action)
22
24
 
@@ -26,22 +28,24 @@ module Watchr
26
28
  # that they get a clearly defined set of methods to work with. In other
27
29
  # words, it is the user script's API.
28
30
  #
31
+ # @private
29
32
  class EvalContext #:nodoc:
30
33
 
31
34
  def initialize(script)
32
35
  @__script = script
33
36
  end
34
37
 
35
- # Delegated to Script
38
+ # Delegated to script
36
39
  def default_action(&action)
37
40
  @__script.default_action(&action)
38
41
  end
39
42
 
40
- # Delegated to Script
43
+ # Delegated to script
41
44
  def watch(*args, &block)
42
45
  @__script.watch(*args, &block)
43
46
  end
44
47
 
48
+ # Reload script
45
49
  def reload
46
50
  @__script.parse!
47
51
  end
@@ -49,30 +53,26 @@ module Watchr
49
53
 
50
54
  # EvalContext instance
51
55
  #
52
- # ===== Examples
53
- # script.ec.watch('pattern') { }
54
- # script.ec.rules
56
+ # @example
57
+ #
58
+ # script.ec.watch('pattern') { }
59
+ # script.ec.reload
60
+ #
61
+ # @return [EvalContext]
55
62
  #
56
63
  attr_reader :ec
57
64
 
58
65
  # Defined rules
59
66
  #
60
- # ===== Returns
61
- # Array[Rule]:: rules defined with #watch calls
67
+ # @return [Rule]
68
+ # all rules defined with `#watch` calls
62
69
  #
63
70
  attr_reader :rules
64
71
 
65
- # Default action
66
- #
67
- # ===== Returns
68
- # Proc:: action defined with #default_action call
69
- #
70
- attr_reader :default_action
71
-
72
- # Create a script object for <tt>path</tt>.
72
+ # Create a Script object for script at `path`
73
73
  #
74
- # ===== Parameters
75
- # path<Pathname>:: the path to the script
74
+ # @param [Pathname] path
75
+ # the path to the script
76
76
  #
77
77
  def initialize(path = nil)
78
78
  @path = path
@@ -83,44 +83,46 @@ module Watchr
83
83
 
84
84
  # Main script API method. Builds a new rule, binding a pattern to an action.
85
85
  #
86
- # Whenever a file is saved that matches a rule's <tt>pattern</tt>, its
87
- # corresponding <tt>action</tt> is triggered.
86
+ # Whenever a file is saved that matches a rule's `pattern`, its
87
+ # corresponding `action` is triggered.
88
88
  #
89
89
  # Patterns can be either a Regexp or a string. Because they always
90
90
  # represent paths however, it's simpler to use strings. But remember to use
91
91
  # single quotes (not double quotes), otherwise escape sequences will be
92
- # parsed (for example "foo/bar\.rb" #=> "foo/bar.rb", notice "\." becomes
92
+ # parsed (for example `"foo/bar\.rb" #=> "foo/bar.rb"`, notice "\." becomes
93
93
  # "."), and won't be interpreted as the regexp you expect.
94
94
  #
95
95
  # Also note that patterns will be matched against relative paths (relative
96
- # from current working directory).
96
+ # to current working directory).
97
97
  #
98
- # Actions, the blocks passed to <tt>watch</tt>, receive a MatchData object
99
- # as argument. It will be populated with the whole matched string (md[0])
100
- # as well as individual backreferences (md[1..n]). See MatchData#[]
98
+ # Actions, the blocks passed to `watch`, receive a `MatchData` object as
99
+ # argument. It will be populated with the whole matched string ( `md[0]` )
100
+ # as well as individual backreferences ( `md[1..n]` ). See `MatchData#[]`
101
101
  # documentation for more details.
102
102
  #
103
- # ===== Examples
103
+ # @example
104
104
  #
105
- # # in script file
106
- # watch( 'test/test_.*\.rb' ) {|md| system("ruby #{md[0]}") }
107
- # watch( 'lib/(.*)\.rb' ) {|md| system("ruby test/test_#{md[1]}.rb") }
105
+ # # in script file
106
+ # watch( 'test/test_.*\.rb' ) {|md| system("ruby #{md[0]}") }
107
+ # watch( 'lib/(.*)\.rb' ) {|md| system("ruby test/test_#{md[1]}.rb") }
108
108
  #
109
109
  # With these two rules, watchr will run any test file whenever it is itself
110
110
  # changed (first rule), and will also run a corresponding test file
111
111
  # whenever a lib file is changed (second rule).
112
112
  #
113
- # ===== Parameters
114
- # pattern<~#match>:: pattern to match targetted paths
115
- # event_type<Symbol>::
116
- # Rule will only match events of this type. Accepted types are :accessed,
117
- # :modified, :changed, :delete and nil (any), where the first three
118
- # correspond to atime, mtime and ctime respectively. Defaults to
119
- # :modified.
120
- # action<Block>:: action to trigger
113
+ # @param [#match] pattern
114
+ # pattern to match targetted paths
121
115
  #
122
- # ===== Returns
123
- # rule<Rule>:: rule created by the method
116
+ # @param [Symbol] event_type
117
+ # rule will only match events of this type. Accepted types are
118
+ # `:accessed`, `:modified`, `:changed`, `:delete` and `nil` (any), where
119
+ # the first three correspond to atime, mtime and ctime respectively.
120
+ # Defaults to `:modified`.
121
+ #
122
+ # @yield
123
+ # action to trigger
124
+ #
125
+ # @return [Rule]
124
126
  #
125
127
  def watch(pattern, event_type = DEFAULT_EVENT_TYPE, &action)
126
128
  @rules << Rule.new(pattern, event_type, action || @default_action)
@@ -128,28 +130,29 @@ module Watchr
128
130
  end
129
131
 
130
132
  # Convenience method. Define a default action to be triggered when a rule
131
- # has none specified.
133
+ # has none specified. When called without a block, acts as a getter and
134
+ # returns stored default_action
132
135
  #
133
- # ===== Examples
136
+ # @example
134
137
  #
135
- # # in script file
138
+ # # in script file
136
139
  #
137
- # default_action { system('rake --silent rdoc') }
140
+ # default_action { system('rake --silent yard') }
138
141
  #
139
- # watch( 'lib/.*\.rb' )
140
- # watch( 'README.rdoc' )
141
- # watch( 'TODO.txt' )
142
- # watch( 'LICENSE' )
142
+ # watch( 'lib/.*\.rb' )
143
+ # watch( 'README.md' )
144
+ # watch( 'TODO.txt' )
145
+ # watch( 'LICENSE' )
143
146
  #
144
- # # equivalent to:
147
+ # # is equivalent to:
145
148
  #
146
- # watch( 'lib/.*\.rb' ) { system('rake --silent rdoc') }
147
- # watch( 'README.rdoc' ) { system('rake --silent rdoc') }
148
- # watch( 'TODO.txt' ) { system('rake --silent rdoc') }
149
- # watch( 'LICENSE' ) { system('rake --silent rdoc') }
149
+ # watch( 'lib/.*\.rb' ) { system('rake --silent yard') }
150
+ # watch( 'README.md' ) { system('rake --silent yard') }
151
+ # watch( 'TODO.txt' ) { system('rake --silent yard') }
152
+ # watch( 'LICENSE' ) { system('rake --silent yard') }
150
153
  #
151
- # ===== Returns
152
- # Proc:: default action
154
+ # @return [Proc]
155
+ # default action
153
156
  #
154
157
  def default_action(&action)
155
158
  @default_action = action if action
@@ -163,8 +166,8 @@ module Watchr
163
166
  end
164
167
 
165
168
  # Eval content of script file.
166
- #--
167
- # TODO fix/figure out ENOENT error
169
+ #
170
+ # @todo improve ENOENT error handling
168
171
  def parse!
169
172
  return unless @path
170
173
  reset
@@ -180,14 +183,19 @@ module Watchr
180
183
  # action is actually a wrapper around the rule's action, with the
181
184
  # match_data prepopulated.
182
185
  #
183
- # ===== Params
184
- # path<Pathnane,String>:: Find action that corresponds to this path.
185
- # event_type<Symbol>:: Find action only if rule's event if of this type.
186
+ # @example
187
+ #
188
+ # script.watch( 'test/test_.*\.rb' ) {|md| "ruby #{md[0]}" }
189
+ # script.action_for('test/test_watchr.rb').call #=> "ruby test/test_watchr.rb"
190
+ #
191
+ # @param [Pathname, String] path
192
+ # find action that corresponds to this path.
186
193
  #
187
- # ===== Examples
194
+ # @param [Symbol] event_type
195
+ # find action only if rule's event is of this type.
188
196
  #
189
- # script.watch( 'test/test_.*\.rb' ) {|md| "ruby #{md[0]}" }
190
- # script.action_for('test/test_watchr.rb').call #=> "ruby test/test_watchr.rb"
197
+ # @return [Proc]
198
+ # action, preparsed and ready to be called
191
199
  #
192
200
  def action_for(path, event_type = DEFAULT_EVENT_TYPE)
193
201
  path = rel_path(path).to_s
@@ -202,18 +210,18 @@ module Watchr
202
210
 
203
211
  # Collection of all patterns defined in script.
204
212
  #
205
- # ===== Returns
206
- # patterns<String, Regexp>:: all patterns
213
+ # @return [Array<String,Regexp>]
214
+ # all defined patterns
207
215
  #
208
216
  def patterns
209
217
  #@rules.every.pattern
210
218
  @rules.map {|r| r.pattern }
211
219
  end
212
220
 
213
- # Path to the script file
221
+ # Path to the script file corresponding to this object
214
222
  #
215
- # ===== Returns
216
- # path<Pathname>:: absolute path to script file
223
+ # @return [Pathname]
224
+ # absolute path to script file
217
225
  #
218
226
  def path
219
227
  @path && Pathname(@path.respond_to?(:to_path) ? @path.to_path : @path.to_s).expand_path
@@ -224,11 +232,11 @@ module Watchr
224
232
  # Rules corresponding to a given path, in reversed order of precedence
225
233
  # (latest one is most inportant).
226
234
  #
227
- # ===== Parameters
228
- # path<Pathname, String>:: path to look up rule for
235
+ # @param [Pathname, String] path
236
+ # path to look up rule for
229
237
  #
230
- # ===== Returns
231
- # rules<Array(Rule)>:: rules corresponding to <tt>path</tt>
238
+ # @return [Array<Rule>]
239
+ # rules corresponding to `path`
232
240
  #
233
241
  def rules_for(path)
234
242
  @rules.reverse.select {|rule| path.match(rule.pattern) }
@@ -236,11 +244,11 @@ module Watchr
236
244
 
237
245
  # Make a path relative to current working directory.
238
246
  #
239
- # ===== Parameters
240
- # path<Pathname, String>:: absolute or relative path
247
+ # @param [Pathname, String] path
248
+ # absolute or relative path
241
249
  #
242
- # ===== Returns
243
- # path<Pathname>:: relative path, from current working directory.
250
+ # @return [Pathname]
251
+ # relative path, from current working directory.
244
252
  #
245
253
  def rel_path(path)
246
254
  Pathname(path).expand_path.relative_path_from(Pathname(Dir.pwd))