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