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.
- data/bin/ducktest +29 -0
- data/lib/duck_test/autoload_config.rb +103 -0
- data/lib/duck_test/base.rb +41 -0
- data/lib/duck_test/commands.rb +208 -0
- data/lib/duck_test/config.rb +675 -0
- data/lib/duck_test/config_helper.rb +99 -0
- data/lib/duck_test/console.rb +18 -0
- data/lib/duck_test/default_config.rb +48 -0
- data/lib/duck_test/frame_work/base.rb +587 -0
- data/lib/duck_test/frame_work/file_manager.rb +511 -0
- data/lib/duck_test/frame_work/filter_set.rb +233 -0
- data/lib/duck_test/frame_work/map.rb +331 -0
- data/lib/duck_test/frame_work/queue.rb +221 -0
- data/lib/duck_test/frame_work/queue_event.rb +29 -0
- data/lib/duck_test/frame_work/rspec/base.rb +17 -0
- data/lib/duck_test/frame_work/rspec/frame_work.rb +30 -0
- data/lib/duck_test/frame_work/test_unit/base.rb +14 -0
- data/lib/duck_test/frame_work/test_unit/frame_work.rb +33 -0
- data/lib/duck_test/frame_work/watch_config.rb +69 -0
- data/lib/duck_test/gem/helper.rb +107 -0
- data/lib/duck_test/logger.rb +127 -0
- data/lib/duck_test/option_parser.rb +30 -0
- data/lib/duck_test/platforms/base.rb +18 -0
- data/lib/duck_test/platforms/dependencies.rb +18 -0
- data/lib/duck_test/platforms/generic/base.rb +15 -0
- data/lib/duck_test/platforms/generic/listener.rb +104 -0
- data/lib/duck_test/platforms/linux/base.rb +15 -0
- data/lib/duck_test/platforms/linux/listener.rb +76 -0
- data/lib/duck_test/platforms/listener.rb +303 -0
- data/lib/duck_test/platforms/mac/base.rb +15 -0
- data/lib/duck_test/platforms/mac/listener.rb +79 -0
- data/lib/duck_test/platforms/mac/listener.rb.orig +147 -0
- data/lib/duck_test/platforms/os_helper.rb +102 -0
- data/lib/duck_test/platforms/watch_event.rb +47 -0
- data/lib/duck_test/platforms/windows/base.rb +15 -0
- data/lib/duck_test/platforms/windows/listener.rb +123 -0
- data/lib/duck_test/railtie.rb +29 -0
- data/lib/duck_test/usage.rb +34 -0
- data/lib/duck_test/usage.yml +112 -0
- data/lib/duck_test/version.rb +3 -0
- data/lib/duck_test.rb +6 -0
- data/lib/notes.txt +215 -0
- data/lib/tasks/duck_tests.rake +35 -0
- data/lib/tasks/gem_tasks.rake +18 -0
- 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
|