duck_test 0.1.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. data/bin/ducktest +29 -0
  2. data/lib/duck_test/autoload_config.rb +103 -0
  3. data/lib/duck_test/base.rb +41 -0
  4. data/lib/duck_test/commands.rb +208 -0
  5. data/lib/duck_test/config.rb +675 -0
  6. data/lib/duck_test/config_helper.rb +99 -0
  7. data/lib/duck_test/console.rb +18 -0
  8. data/lib/duck_test/default_config.rb +48 -0
  9. data/lib/duck_test/frame_work/base.rb +587 -0
  10. data/lib/duck_test/frame_work/file_manager.rb +511 -0
  11. data/lib/duck_test/frame_work/filter_set.rb +233 -0
  12. data/lib/duck_test/frame_work/map.rb +331 -0
  13. data/lib/duck_test/frame_work/queue.rb +221 -0
  14. data/lib/duck_test/frame_work/queue_event.rb +29 -0
  15. data/lib/duck_test/frame_work/rspec/base.rb +17 -0
  16. data/lib/duck_test/frame_work/rspec/frame_work.rb +30 -0
  17. data/lib/duck_test/frame_work/test_unit/base.rb +14 -0
  18. data/lib/duck_test/frame_work/test_unit/frame_work.rb +33 -0
  19. data/lib/duck_test/frame_work/watch_config.rb +69 -0
  20. data/lib/duck_test/gem/helper.rb +107 -0
  21. data/lib/duck_test/logger.rb +127 -0
  22. data/lib/duck_test/option_parser.rb +30 -0
  23. data/lib/duck_test/platforms/base.rb +18 -0
  24. data/lib/duck_test/platforms/dependencies.rb +18 -0
  25. data/lib/duck_test/platforms/generic/base.rb +15 -0
  26. data/lib/duck_test/platforms/generic/listener.rb +104 -0
  27. data/lib/duck_test/platforms/linux/base.rb +15 -0
  28. data/lib/duck_test/platforms/linux/listener.rb +76 -0
  29. data/lib/duck_test/platforms/listener.rb +303 -0
  30. data/lib/duck_test/platforms/mac/base.rb +15 -0
  31. data/lib/duck_test/platforms/mac/listener.rb +79 -0
  32. data/lib/duck_test/platforms/mac/listener.rb.orig +147 -0
  33. data/lib/duck_test/platforms/os_helper.rb +102 -0
  34. data/lib/duck_test/platforms/watch_event.rb +47 -0
  35. data/lib/duck_test/platforms/windows/base.rb +15 -0
  36. data/lib/duck_test/platforms/windows/listener.rb +123 -0
  37. data/lib/duck_test/railtie.rb +29 -0
  38. data/lib/duck_test/usage.rb +34 -0
  39. data/lib/duck_test/usage.yml +112 -0
  40. data/lib/duck_test/version.rb +3 -0
  41. data/lib/duck_test.rb +6 -0
  42. data/lib/notes.txt +215 -0
  43. data/lib/tasks/duck_tests.rake +35 -0
  44. data/lib/tasks/gem_tasks.rake +18 -0
  45. metadata +92 -0
@@ -0,0 +1,233 @@
1
+ module DuckTest
2
+ module FrameWork
3
+
4
+ # Data and methods that are used to filter directories and files.
5
+ class FilterSet
6
+ include LoggerHelper
7
+
8
+ attr_accessor :included
9
+ attr_accessor :included_dirs
10
+ attr_accessor :excluded
11
+ attr_accessor :excluded_dirs
12
+ attr_accessor :non_loadable
13
+
14
+ ##################################################################################
15
+ # Initialize a new FilterSet
16
+ # @return [FilterSet]
17
+ def initialize(options = {})
18
+ super()
19
+
20
+ self.included = options[:included]
21
+ self.included_dirs = options[:included_dirs]
22
+ self.excluded = options[:excluded]
23
+ self.excluded_dirs = options[:excluded_dirs]
24
+ self.non_loadable = options[:non_loadable]
25
+
26
+ return self
27
+ end
28
+
29
+ ##################################################################################
30
+ # @note You can pass a Symbol named :all instead of a Regexp and the method will always return true. This provides the ability to specify "all" files as part of a filter.
31
+ # Compares a file_spec against an array of {http://www.ruby-doc.org/core-1.9.3/Regexp.html Regexp's} (filters).
32
+ #
33
+ # match_filters?("test.rb", /^book/) # => false
34
+ #
35
+ # match_filters?("test.rb", [/^book/]) # => false
36
+ #
37
+ # match_filters?("test.rb", [/^book/, /^test/]) # => true
38
+ #
39
+ # match_filters?("test.rb", :all) # => true
40
+ #
41
+ # match_filters?("test.rb", [:all]) # => true
42
+ #
43
+ # @param [String] file_spec A file name that adheres to {http://ruby-doc.org/core-1.9.3/File.html#method-c-basename File.basename}.
44
+ # @param [Array] filters An Array of {http://www.ruby-doc.org/core-1.9.3/Regexp.html Regexp's}. Each Regexp is compared against file_spec.
45
+ # The first Regexp that matches file_spec wins and returns true, otherwise, this method returns false.
46
+ # Also, you can pass an Array with a single Symbol named :all and match_filters? will always return true.
47
+ # @param [String] subdirectory If file_spec is a directory, then, subdirectory will be used during the evaluations instead of file_spec.
48
+ # @return [Boolean] Returns true if a match is found, otherwise, false
49
+ def match_filters?(file_spec = nil, filters = nil, subdirectory = nil)
50
+
51
+ begin
52
+
53
+ unless file_spec.blank? || filters.blank?
54
+
55
+ ducklog.system %(FilterSet.match_filters?(#{file_spec}, #{filters}, #{subdirectory}))
56
+
57
+ filters = filters.kind_of?(Array) ? filters : [filters]
58
+ subdirectory = subdirectory.blank? ? "" : subdirectory
59
+
60
+ filters.each do |expression|
61
+
62
+ if expression.kind_of?(Symbol) && expression.eql?(:all)
63
+ ducklog.system "returning true due to :all flag"
64
+ return true
65
+
66
+ elsif expression.kind_of?(Regexp)
67
+
68
+ if File.directory?(file_spec)
69
+
70
+ # blank subdirectory is allowed, because, we might be comparing against a
71
+ # watch root directory.
72
+ if subdirectory.blank?
73
+ return true
74
+
75
+ elsif subdirectory.match(expression)
76
+ ducklog.system "returning true due to Regexp MATCH !!!!"
77
+ return true
78
+
79
+ end
80
+
81
+ elsif File.basename(file_spec).match(expression)
82
+ ducklog.system "returning true due to Regexp MATCH !!!!"
83
+ return true
84
+
85
+ end
86
+ end
87
+ end
88
+ end
89
+
90
+ rescue Exception => e
91
+ ducklog.exception e
92
+ end
93
+
94
+ ducklog.system "FilterSet.match_filters?() returning false"
95
+
96
+ return false
97
+ end
98
+
99
+ ##################################################################################
100
+ # Conveinence method that calls {FilterSet#match_filters? match_filters?} with the current value of {FilterSet#included included}
101
+ # - In this context, file_spec cannot be blank.
102
+ # - Will return true if self.included array is nil or empty.
103
+ # @param [String] file_spec See {FilterSet#match_filters? match_filters?}
104
+ # @return [Boolean] Returns true if a match is found, otherwise, false
105
+ def included?(file_spec)
106
+ ducklog.system %(FilterSet.included?(#{file_spec}, #{self.included}))
107
+ if file_spec.blank?
108
+ return false
109
+
110
+ elsif self.has_included?
111
+ return self.match_filters?(file_spec, self.included)
112
+
113
+ else
114
+ return true
115
+
116
+ end
117
+ end
118
+
119
+ ##################################################################################
120
+ # Conveinence method that determines if an {FilterSet#included included} filter exists.
121
+ # @return [Boolean] Returns true if the {FilterSet#included included} filters exists, otherwise, false.
122
+ def has_included?
123
+ return self.included.blank? ? false : true
124
+ end
125
+
126
+ ##################################################################################
127
+ # Conveinence method that calls {FilterSet#match_filters? match_filters?} with the current value of {FilterSet#included_dirs included_dirs}
128
+ # - In this context, file_spec cannot be blank.
129
+ # - In this context, subdirectory CAN BE blank.
130
+ # - Will return true if self.included_dirs array is nil or empty.
131
+ # @param [String] file_spec See {FilterSet#match_filters? match_filters?}
132
+ # @param [String] subdirectory Subdirectory is any directory directly off of the watch root directory. Subdirectory CAN BE blank.
133
+ # @return [Boolean] Returns true if a match is found, otherwise, false
134
+ def included_dirs?(file_spec, subdirectory)
135
+ ducklog.system %(FilterSet.included?(#{file_spec}, #{self.included}, #{subdirectory}))
136
+ if file_spec.blank?
137
+ return false
138
+
139
+ elsif self.has_included_dirs?
140
+ return self.match_filters?(file_spec, self.included_dirs, subdirectory)
141
+
142
+ else
143
+ return true
144
+
145
+ end
146
+ end
147
+
148
+ ##################################################################################
149
+ # Conveinence method that determines if an {FilterSet#included_dirs included_dirs} filter exists.
150
+ # @return [Boolean] Returns true if the {FilterSet#included_dirs included_dirs} filters exists, otherwise, false.
151
+ def has_included_dirs?
152
+ return self.included_dirs.blank? ? false : true
153
+ end
154
+
155
+ ##################################################################################
156
+ # Conveinence method that calls {FilterSet#match_filters? match_filters?} with the current value of {FilterSet#excluded excluded}
157
+ # - In this context, file_spec cannot be blank.
158
+ # - Will return true if self.excluded array is nil or empty.
159
+ # @param [String] file_spec See {FilterSet#match_filters? match_filters?}
160
+ # @return [Boolean] Returns true if a match is found, otherwise, false
161
+ def excluded?(file_spec)
162
+ ducklog.system %(FilterSet.excluded?(#{file_spec}, #{self.excluded}))
163
+ if file_spec.blank?
164
+ return false
165
+
166
+ else
167
+ return self.match_filters?(file_spec, self.excluded)
168
+
169
+ end
170
+ end
171
+
172
+ ##################################################################################
173
+ # Conveinence method that determines if an {FilterSet#excluded excluded} filter exists.
174
+ # @return [Boolean] Returns true if the {FilterSet#excluded excluded} filters exists, otherwise, false.
175
+ def has_excluded?
176
+ return self.excluded.blank? ? false : true
177
+ end
178
+
179
+ ##################################################################################
180
+ # Conveinence method that calls {FilterSet#match_filters? match_filters?} with the current value of {FilterSet#excluded_dirs excluded_dirs}
181
+ # - In this context, file_spec cannot be blank.
182
+ # - In this context, subdirectory CAN BE blank.
183
+ # - Will return true if self.excluded_dirs array is nil or empty.
184
+ # @param [String] file_spec See {FilterSet#match_filters? match_filters?}
185
+ # @param [String] subdirectory Subdirectory is any directory directly off of the watch root directory. Subdirectory CAN BE blank.
186
+ # @return [Boolean] Returns true if a match is found, otherwise, false
187
+ def excluded_dirs?(file_spec, subdirectory)
188
+ ducklog.system %(FilterSet.excluded_dirs?(#{file_spec}, #{self.excluded_dirs}, #{subdirectory}))
189
+ if file_spec.blank?
190
+ return false
191
+
192
+ else
193
+ return self.match_filters?(file_spec, self.excluded_dirs, subdirectory)
194
+
195
+ end
196
+ end
197
+
198
+ ##################################################################################
199
+ # Conveinence method that determines if an {FilterSet#excluded_dirs excluded_dirs} filter exists.
200
+ # @return [Boolean] Returns true if the {FilterSet#excluded_dirs excluded_dirs} filters exists, otherwise, false.
201
+ def has_excluded_dirs?
202
+ return self.excluded_dirs.blank? ? false : true
203
+ end
204
+
205
+ ##################################################################################
206
+ # Conveinence method that calls {FilterSet#match_filters? match_filters?} with the current value of {FilterSet#non_loadable non_loadable}
207
+ # - In this context, file_spec cannot be blank.
208
+ # - In this context, subdirectory CAN BE blank.
209
+ # - Will return true if self.non_loadable array is nil or empty.
210
+ # @param [String] file_spec See {FilterSet#match_filters? match_filters?}
211
+ # @param [String] subdirectory Subdirectory is any directory directly off of the watch root directory. Subdirectory CAN BE blank.
212
+ # @return [Boolean] Returns true if a match is found, otherwise, false
213
+ def non_loadable?(file_spec, subdirectory)
214
+ ducklog.system %(FilterSet.non_loadable?(#{file_spec}, #{self.non_loadable}, #{subdirectory}))
215
+ if file_spec.blank?
216
+ return false
217
+
218
+ else
219
+ return self.match_filters?(file_spec, self.non_loadable, subdirectory)
220
+
221
+ end
222
+ end
223
+
224
+ ##################################################################################
225
+ # Conveinence method that determines if an {FilterSet#non_loadable non_loadable} filter exists.
226
+ # @return [Boolean] Returns true if the {FilterSet#non_loadable non_loadable} filters exists, otherwise, false.
227
+ def has_non_loadable?
228
+ return self.non_loadable.blank? ? false : true
229
+ end
230
+
231
+ end
232
+ end
233
+ end
@@ -0,0 +1,331 @@
1
+ module DuckTest
2
+ # ...
3
+ module FrameWork
4
+
5
+ ##################################################################################
6
+ # {include:file:MAPS.md}
7
+ class Map
8
+ include DuckTest::ConfigHelper
9
+
10
+ # An Array of {Map} objects representing target runnables tests.
11
+ attr_accessor :maps
12
+
13
+ ##################################################################################
14
+ # Initialize a new Map. A Map can be initialized in multiple variations.
15
+ # sub_directory and file_name are defaulted to nil, therefore, those values are optional. However, the
16
+ # gotcha is that you cannot specify file_name without first specifying sub_directory which make the order of
17
+ # the arguments important. If you omit file_name or sub_directory and file_name initialize will recognize
18
+ # it by checking the sub_directory and file_name arguments. If either of them are a Hash, then, it assumes
19
+ # that value is the options Hash.
20
+ #
21
+ # # normal form
22
+ # Map.new(/models/, /bike/, watch_basedir: :app, runnable_basedir: :test)
23
+ #
24
+ # # specify sub_directory and options
25
+ # Map.new(/models/, watch_basedir: :app, runnable_basedir: :test)
26
+ #
27
+ # # options only
28
+ # Map.new(watch_basedir: :app, runnable_basedir: :test)
29
+ #
30
+ # Any value passed as part of the options Hash will override the preceding sub_directory or file_name value set by a normal argument.
31
+ #
32
+ # # specify all arguments as part of the options Hash
33
+ # Map.new(sub_directory: /models/, file_name: /bike/, watch_basedir: :app, runnable_basedir: :test)
34
+ #
35
+ # Since {DuckTest::Config} uses the Map class directly for creating Map objects this feature
36
+ # should allow developer to create maps in the config file like the following:
37
+ #
38
+ # DuckTest.config do
39
+ # watch "**/*" do
40
+ # map /models/, /bike/
41
+ # end
42
+ # end
43
+ #
44
+ # If a block is passed, it is executed against self. Therefore, all of the instance methods are available to be called within the block.
45
+ #
46
+ # Map.new(/^models/, /[a-z]_store/, watch_basedir: :app) do
47
+ # target /^unit/, /[a-z]_spec.rb/, watch_basedir: :spec
48
+ # target /^functional/, /[a-z]_controller_[a-z]/, watch_basedir: :test
49
+ # end
50
+ #
51
+ # @param [Proc, Regexp, Symbol, String] sub_directory See {#sub_directory}
52
+ # @param [Proc, Regexp, Symbol, String] file_name See {#file_name}
53
+ # @param [Hash] options An options Hash containing values used to initialize the object.
54
+ # @option options [String] :file_name See {#file_name}
55
+ # @option options [String] :runnable_basedir See {DuckTest::ConfigHelper#runnable_basedir}
56
+ # @option options [String] :sub_directory See {#sub_directory}
57
+ # @option options [String] :watch_basedir See {DuckTest::ConfigHelper#watch_basedir}
58
+ # @param [Block] &block A standard Ruby code block.
59
+ # @return [Map]
60
+ def initialize(sub_directory = nil, file_name = nil, options = {}, &block)
61
+ super()
62
+
63
+ options = sub_directory.kind_of?(Hash) ? sub_directory : options
64
+ options = file_name.kind_of?(Hash) ? file_name : options
65
+
66
+ self.watch_basedir = options[:watch_basedir]
67
+
68
+ self.file_name file_name unless file_name.blank? || file_name.kind_of?(Hash)
69
+ self.file_name options[:file_name] unless options[:file_name].blank?
70
+
71
+ self.maps = [] # don't accept a maps array as a parameter
72
+
73
+ self.sub_directory sub_directory unless sub_directory.blank? || sub_directory.kind_of?(Hash)
74
+ self.sub_directory options[:sub_directory] unless options[:sub_directory].blank?
75
+
76
+ self.runnable_basedir = options[:runnable_basedir]
77
+
78
+ self.instance_exec(&block) if block_given?
79
+ return self
80
+ end
81
+
82
+ ##################################################################################
83
+ # Creates a new Map object based on options and adds it to self. Must be called within a {#initialize} block.
84
+ #
85
+ # # in block form
86
+ # Map.new(/^models/, /[a-z]_store/, watch_basedir: :app).build do
87
+ # target /^functional/, /[a-z]_controller_[a-z]/ # runnable_basedir trickles down to watch_basedir
88
+ # target /^unit/, /[a-z]_spec.rb/, watch_basedir: :spec # overrides tickled runnable_basedir
89
+ # end
90
+ #
91
+ # It is important to note that the runnable_basedir is passed to the target block as watch_basedir. This allows
92
+ # you to specify a runnable_basedir to the Map object and have it trickle down to all of the targets eliminating the
93
+ # need to specify it for every target block. Also, {DuckTest::Config} will use this feature by allowing you to specify
94
+ # watch_basedir and runnable_basedir at the top of a config file and have those values be used for all mappings.
95
+ #
96
+ # @param [Hash] options See {#initialize}
97
+ # @param [Block] &block A standard Ruby code block.
98
+ # @return [Map] The recently created Map object.
99
+ def target(sub_directory = nil, file_name = nil, options = {}, &block)
100
+ options = sub_directory.kind_of?(Hash) ? sub_directory : options
101
+ options = file_name.kind_of?(Hash) ? file_name : options
102
+ config = {watch_basedir: self.runnable_basedir}.merge(options)
103
+ self.maps.push(Map.new(sub_directory, file_name, config, &block))
104
+ return self.maps.last
105
+ end
106
+
107
+ ##################################################################################
108
+ # @note See {Map} overview for details on how Regexp, String, Symbols are evaluated and a general understanding of mappings.
109
+ # Sets the current value of the file name expression.
110
+ # See {#file_name_match?}
111
+ # @param [Array, Proc, Regexp, String, Symbol] value An expression to compare against file names.
112
+ # If the value is an Array, then, file_name expects the Array to contain
113
+ # Procs, Regexps, Strings, or Symbols and not sub-arrays.
114
+ # @return [Array, Proc, Regexp, String, Symbol] value Returns the current value of the file_name expression.
115
+ def file_name(value = nil, &block)
116
+ @file_name ||= "all"
117
+ value = value.kind_of?(Symbol) ? value.to_s : value
118
+ if value.kind_of?(Array)
119
+ value.each_with_index {|item, index| value[index] = item.to_s if item.kind_of?(Symbol)}
120
+ end
121
+ @file_name = value unless value.blank?
122
+ @file_name = block if block_given?
123
+ return @file_name
124
+ end
125
+
126
+ ##################################################################################
127
+ # @note See {Map} overview for details on how Regexp, String, Symbols are evaluated and a general understanding of mappings.
128
+ # The current {#file_name} value should be an expression Proc, Regexp, or String. This value is compared against file names
129
+ # retrieved from the file system based on the pattern option of {DuckTest::Config#watch}.
130
+ #
131
+ # map = Map.new
132
+ # map.file_name(/^bike/)
133
+ # map.file_name_match?("bike_spec.rb") # => true
134
+ # map.file_name_match?("truck_spec.rb") # => false
135
+ #
136
+ # @param [String] value The file name being evaluated. Typically, this is the source or target file name.
137
+ # @param [String] cargo A value that is passed to the block if {#file_name} is a block.
138
+ # @return [Boolean] True if match, otherwise, false.
139
+ def file_name_match?(value, cargo = nil)
140
+ result = false
141
+ expressions = self.file_name.blank? ? "all" : self.file_name
142
+ expressions = expressions.kind_of?(Array) ? self.file_name : [self.file_name]
143
+
144
+ expressions.each do |expression|
145
+
146
+ if expression.kind_of?(Regexp)
147
+ result = value =~ expression
148
+
149
+ elsif expression.kind_of?(String)
150
+ result = value =~ /^#{expression}/ || expression.eql?("all")
151
+
152
+ elsif expression.kind_of?(Proc)
153
+ result = expression.call value, cargo
154
+
155
+ end
156
+
157
+ break if result
158
+ end
159
+
160
+ return result
161
+ end
162
+
163
+ ##################################################################################
164
+ # @note See {Map} overview for details on how Regexp, String, Symbols are evaluated and a general understanding of mappings.
165
+ # Sets the current value of the sub-directory expression.
166
+ # See {#sub_directory_match?}
167
+ # @param [Array, Proc, Regexp, String, Symbol] value An expression to compare against directory names.
168
+ # If the value is an Array, then, sub_directory expects the Array to contain
169
+ # Procs, Regexps, Strings, or Symbols and not sub-arrays.
170
+ # @return [Array, Proc, Regexp, String, Symbol] value Returns the current value of the sub_directory expression.
171
+ def sub_directory(value = nil, &block)
172
+ @sub_directory ||= "all"
173
+ value = value.kind_of?(Symbol) ? value.to_s : value
174
+ if value.kind_of?(Array)
175
+ value.each_with_index {|item, index| value[index] = item.to_s if item.kind_of?(Symbol)}
176
+ end
177
+ @sub_directory = value unless value.blank?
178
+ @sub_directory = block if block_given?
179
+ return @sub_directory
180
+ end
181
+
182
+ ##################################################################################
183
+ def match?(target)
184
+ value = false
185
+
186
+ if self.match.kind_of?(Proc)
187
+ value = self.match.call target
188
+ else
189
+ value = self.sub_directory_match?(target[:sub_directory]) && self.file_name_match?(target[:file_name]) ? true : value
190
+ end
191
+
192
+ return value
193
+ end
194
+
195
+ ##################################################################################
196
+ def match_target?(target, source)
197
+ value = false
198
+
199
+ if self.match.kind_of?(Proc)
200
+ value = self.match.call target, source
201
+ else
202
+ value = self.sub_directory_match?(target[:sub_directory]) && self.file_name_match?(target[:file_name], source[:file_name])
203
+ end
204
+
205
+ return value
206
+ end
207
+
208
+ ##################################################################################
209
+ def match(&block)
210
+ @match ||= nil
211
+ @match = block if block_given?
212
+ return @match
213
+ end
214
+
215
+ ##################################################################################
216
+ # @note See {Map} overview for details on how Regexp, String, Symbols are evaluated and a general understanding of mappings.
217
+ # The current {#sub_directory} value should be an expression Proc, Regexp, or String. This value is compared against directory paths
218
+ # retrieved from the file system based on the pattern option of {DuckTest::Config#watch}.
219
+ #
220
+ # Examples:
221
+ #
222
+ # map = Map.new sub_directory: :models
223
+ # map.sub_directory_match?("models") # => true
224
+ # map.sub_directory_match?("controllers") # => false
225
+ #
226
+ # map = Map.new sub_directory: "models"
227
+ # map.sub_directory_match?("models") # => true
228
+ # map.sub_directory_match?("controllers") # => false
229
+ #
230
+ # map = Map.new sub_directory: /models/
231
+ # map.sub_directory_match?("models") # => true
232
+ # map.sub_directory_match?("controllers") # => false
233
+ #
234
+ # map = Map.new sub_directory: :models, watch_basedir: :app
235
+ # map.sub_directory_match?("app/models") # => true
236
+ # map.sub_directory_match?("app/models/sec") # => true
237
+ # map.sub_directory_match?("my_app/models") # => false
238
+ # map.sub_directory_match?("my_app/models/sec") # => false
239
+ # map.sub_directory_match?("app/controllers") # => false
240
+ #
241
+ # map = Map.new sub_directory: "models", watch_basedir: :app
242
+ # map.sub_directory_match?("app/models") # => true
243
+ # map.sub_directory_match?("app/models/sec") # => true
244
+ # map.sub_directory_match?("my_app/models") # => false
245
+ # map.sub_directory_match?("my_app/models/sec") # => false
246
+ # map.sub_directory_match?("app/controllers") # => false
247
+ #
248
+ # map = Map.new sub_directory: /^models/, watch_basedir: :app
249
+ # map.sub_directory_match?("app/models") # => true
250
+ # map.sub_directory_match?("app/models/sec") # => true
251
+ # map.sub_directory_match?("my_app/models") # => false
252
+ # map.sub_directory_match?("my_app/models/sec") # => false
253
+ # map.sub_directory_match?("app/controllers") # => false
254
+ #
255
+ # map = Map.new sub_directory: /models/, watch_basedir: :app
256
+ # map.sub_directory_match?("app/models") # => true
257
+ # map.sub_directory_match?("app/models/sec") # => true
258
+ # map.sub_directory_match?("my_app/models") # => true
259
+ # map.sub_directory_match?("my_app/models/sec") # => true
260
+ # map.sub_directory_match?("app/controllers") # => false
261
+ #
262
+ # @param [String] value The file name being evaluated. Typically, this is the source or target file name.
263
+ # @param [String] cargo A value that is passed to the block if {#sub_directory} is a block.
264
+ # @return [Boolean] True if match, otherwise, false.
265
+ def sub_directory_match?(value, cargo = nil)
266
+ result = false
267
+ expressions = self.sub_directory.blank? ? "all" : self.sub_directory
268
+ expressions = expressions.kind_of?(Array) ? self.sub_directory : [self.sub_directory]
269
+
270
+ # the value being compared via this method is expecting to be a directory
271
+ # possibly containing path separators. The following expressions interrogate
272
+ # value for the existence of the current value of self.watch_basedir. If it exists, then,
273
+ # it is removed, otherwise, value is left in tact.
274
+ # The reason for this is that runnable and watch definitions require a pattern
275
+ # to retrieve files. The self.watch_basedir provides the developer with the conveience
276
+ # of not having to include the watch_basedir directory in all of the mappings.
277
+ # see the description and examples under the watch_basedir method.
278
+
279
+ # first look for watch_basedir with SEPARATOR appended to it: "models/"
280
+ unless self.watch_basedir.blank?
281
+ if value =~ /^#{%(#{self.watch_basedir}#{File::SEPARATOR})}/
282
+ value = value.gsub(%(#{self.watch_basedir}#{File::SEPARATOR}), "")
283
+
284
+ elsif value =~ /^#{self.watch_basedir}/
285
+ value = value.gsub(self.watch_basedir, "")
286
+
287
+ end
288
+ end
289
+
290
+ expressions.each do |expression|
291
+
292
+ if expression.kind_of?(Regexp)
293
+ result = value =~ expression
294
+
295
+ elsif expression.kind_of?(String)
296
+ result = value =~ /^#{expression}/ || expression.eql?("all")
297
+
298
+ elsif expression.kind_of?(Proc)
299
+ result = expression.call value, cargo
300
+
301
+ end
302
+
303
+ break if result
304
+ end
305
+
306
+ return result
307
+ end
308
+
309
+ ##################################################################################
310
+ # Determines if the current {Map} object is valid by examining the sub_directory and file_name values.
311
+ # Both value must not be nil to be valid.
312
+ # @return [Boolean] Returns true if valid, otherwise, false
313
+ def valid?
314
+ return !self.sub_directory.blank? && !self.file_name.blank?
315
+ end
316
+
317
+ ##################################################################################
318
+ # ...
319
+ def to_s(margin = "")
320
+ buffer = ""
321
+ self.maps.each do |item|
322
+ buffer = "\r\n#{margin} maps:" if buffer.blank?
323
+ buffer += "\r\n#{margin}#{item.to_s(' ')}"
324
+ end
325
+ buffer_basedir = self.watch_basedir.blank? ? "" : self.watch_basedir.ljust(15)
326
+ return "\r\n#{margin}watch_basedir: #{buffer_basedir} runnable_basedir: #{self.runnable_basedir}\r\n#{margin}sub_directory: #{self.sub_directory} file_name: #{self.file_name}#{buffer}"
327
+ end
328
+
329
+ end
330
+ end
331
+ end