watchr 0.5.9 → 0.6

Sign up to get free protection for your applications and to get access to all the features.
@@ -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))