duck_map 0.8.0

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.
@@ -0,0 +1,216 @@
1
+ require 'active_support/concern'
2
+
3
+ module DuckMap
4
+
5
+ ##################################################################################
6
+ # Add functionality to ActionDispatch::Routing::Mapper The purpose of this module
7
+ # is to provide methods that can be used within config/routes.rb to define sitemaps
8
+ # and configure sitemap options.
9
+ module Mapper
10
+ extend ActiveSupport::Concern
11
+
12
+ ##################################################################################
13
+ # Defines a sitemap for a Rails app.
14
+ # @return [Nil]
15
+ def sitemap(name = :sitemap, options = {}, &block)
16
+ options = name.kind_of?(Hash) ? name : options
17
+ name = name.kind_of?(String) || name.kind_of?(Symbol) ? name : :sitemap
18
+ config = {controller: :sitemap, url_limit: nil}.merge(options)
19
+
20
+ sitemap_raw_route_name = "#{name}_sitemap"
21
+
22
+ # create a route for the sitemap using the name that was passed to the sitemap method inside config/routes.
23
+ match %(/#{name}.:format), controller: config[:controller], action: name, as: sitemap_raw_route_name
24
+
25
+ # the current Rails implementation keeps the routes in an array. Also, it does nothing to prevent duplicate routes from being added.
26
+ # at the time of development, the route is always at the end of the list, so, it is pretty safe to assume
27
+ # the last route in the list is the sitemap route we just added.
28
+
29
+ # last_route_name is used after we check to see if we just added a duplicate route.
30
+ last_route_name = @set.routes.last.route_name
31
+
32
+ # identify the route as a "sitemap" route and build it's full name.
33
+ @set.routes.last.is_sitemap = true
34
+ @set.routes.last.url_limit = config[:url_limit]
35
+ @set.routes.last.sitemap_route_name = last_route_name
36
+ @set.routes.last.sitemap_raw_route_name = sitemap_raw_route_name
37
+
38
+ # determine if we added a duplicate route.
39
+ # The gem defines a default sitemap in config/routes.rb (inside the gem, not the app).
40
+ # So, it is very likely that most apps will be creating duplicates since most of the code is geared towards
41
+ # automagically configuring as much as possible.
42
+ sitemap_routes = @set.routes.find_all {|route| route.is_sitemap? && route.name.eql?(last_route_name) }
43
+
44
+ # if there are more than one routes with the same name, then, we must have added a duplicate. so, remove it.
45
+ #@set.routes.pop if sitemap_routes.length > 1
46
+ @set.routes.routes.pop if sitemap_routes.length > 1
47
+
48
+ # now, find the route again.
49
+ sitemap_route = @set.routes.find {|route| route.is_sitemap? && route.name.eql?(last_route_name) }
50
+
51
+ # once a sitemap route has been flagged as being defined with a block, then, you should never set it back to false.
52
+ # one of the features is to be able to encapsulate a set of routes within a sitemap as many times as you need.
53
+ # meaning, you might want to wrap five routes at the top of the file, three in the middle, and two at the bottom and
54
+ # have all of them included in the default sitemap.
55
+ # Since all routes within a sitemap block will be marked with the same name,
56
+ # I am not keeping track of sitemaps being defined with or without a block, so, all I need to know is about one of them.
57
+ unless sitemap_route.sitemap_with_block?
58
+ sitemap_route.sitemap_with_block = true if block_given?
59
+ end
60
+
61
+ # DuckMap::SitemapControllerHelpers is a module that is included in SitemapBaseController and contains
62
+ # methods such as sitemap_build, etc. Define a method to handle the sitemap on DuckMap::SitemapControllerHelpers
63
+ # so that method is visible to the default sitemap controller as well as any custom controllers that inherit from it.
64
+ # originally, I was simply defining the method directly on SitemapBaseController, however, it was causing problems
65
+ # during the development cycle of edit and refresh. Defining methods here seemed to cure that problem.
66
+ # for example, the default sitemap: /sitemap.xml will define a method named: sitemap
67
+ # on the DuckMap::SitemapControllerHelpers module.
68
+ unless DuckMap::SitemapControllerHelpers.public_method_defined?(name)
69
+ DuckMap::SitemapControllerHelpers.send :define_method, name do
70
+
71
+ if DuckMap::Config.attributes[:sitemap_content].eql?(:xml)
72
+
73
+ sitemap_build
74
+
75
+ end
76
+
77
+ respond_to do |format|
78
+ format.xml { render }
79
+ end
80
+ end
81
+ end
82
+
83
+ # determine if the sitemap definition included a block.
84
+ if block_given?
85
+
86
+ # the starting point would be after the current set of routes and would be length plus one.
87
+ # however, the starting point index is the length of routes, since arrays are zero based.
88
+ start_point = @set.routes.length
89
+
90
+ # push a copy of the current filter settings onto an array.
91
+ # this will allow you to specify criteria setting within a sitemap definition without affecting
92
+ # the default settings after the block is finished executing.
93
+ @set.sitemap_filters.push
94
+
95
+ # yield to the block. all standard route code should execute just fine and define namespaces, resource, matches, etc.
96
+ yield
97
+
98
+ total = run_filter(sitemap_route.sitemap_route_name, start_point)
99
+
100
+ # knock the current filter setting off of the stack
101
+ @set.sitemap_filters.pop
102
+
103
+ DuckMap.logger.debug %(total routes filtered: #{@set.routes.length - start_point} included? #{total})
104
+
105
+ @set.routes.each do |route|
106
+ DuckMap.logger.debug %( Route name: #{route.name}) if route.sitemap_route_name.eql?(sitemap_route.sitemap_route_name)
107
+ end
108
+
109
+ end
110
+
111
+ return nil
112
+ end
113
+
114
+ ##################################################################################
115
+ def run_filter(sitemap_route_name = nil, start_point = 0)
116
+ total = 0
117
+
118
+ # assign the sitemap_route_name to the sitemap_route_name attribute of every route that has just been added during the execution of the above block.
119
+ start_point.upto(@set.routes.length + 1) do |index|
120
+
121
+ # this is where the actual filtering of routes occurs and is based on the current sitemap filter settings.
122
+ # if the route passes the criteria, then, it is "marked" as part of the sitemap.
123
+ # no need to evaluate it every time a sitemap is requested. evaluate it now and mark it.
124
+
125
+ if !@set.routes.routes[index].blank? && @set.routes.routes[index].sitemap_route_name.blank?
126
+ if @set.include_route?(@set.routes.routes[index]) && !sitemap_route_name.blank?
127
+ @set.routes.routes[index].sitemap_route_name = sitemap_route_name
128
+ total += 1
129
+ else
130
+ @set.routes.routes[index].sitemap_route_name = "do_not_use"
131
+ end
132
+ end
133
+
134
+ end
135
+
136
+ return total
137
+ end
138
+
139
+ end
140
+
141
+ ##################################################################################
142
+ module MapperMethods
143
+ extend ActiveSupport::Concern
144
+
145
+ ##################################################################################
146
+ # See {DuckMap::Sitemap::RouteFilter::InstanceMethods#blank_route_name blank_route_name}
147
+ def allow_blank_route_name(value)
148
+ @set.blank_route_name = value
149
+ end
150
+
151
+ ##################################################################################
152
+ def clear_filters
153
+ @set.sitemap_filters.clear_filters
154
+ end
155
+
156
+ ##################################################################################
157
+ def clear_filter(key)
158
+ @set.sitemap_filters.clear_filter(key)
159
+ end
160
+
161
+ ##################################################################################
162
+ def exclude_actions(*args)
163
+ args.insert(0, :actions)
164
+ @set.sitemap_filters.exclude_filter(*args)
165
+ end
166
+
167
+ ##################################################################################
168
+ def exclude_controllers(*args)
169
+ args.insert(0, :controllers)
170
+ @set.sitemap_filters.exclude_filter(*args)
171
+ end
172
+
173
+ ##################################################################################
174
+ def exclude_names(*args)
175
+ args.insert(0, :names)
176
+ @set.sitemap_filters.exclude_filter(*args)
177
+ end
178
+
179
+ ##################################################################################
180
+ def exclude_verbs(*args)
181
+ args.insert(0, :verbs)
182
+ @set.sitemap_filters.exclude_filter(*args)
183
+ end
184
+
185
+ ##################################################################################
186
+ def include_actions(*args)
187
+ args.insert(0, :actions)
188
+ @set.sitemap_filters.include_filter(*args)
189
+ end
190
+
191
+ ##################################################################################
192
+ def include_controllers(*args)
193
+ args.insert(0, :controllers)
194
+ @set.sitemap_filters.include_filter(*args)
195
+ end
196
+
197
+ ##################################################################################
198
+ def include_names(*args)
199
+ args.insert(0, :names)
200
+ @set.sitemap_filters.include_filter(*args)
201
+ end
202
+
203
+ ##################################################################################
204
+ def include_verbs(*args)
205
+ args.insert(0, :verbs)
206
+ @set.sitemap_filters.include_filter(*args)
207
+ end
208
+
209
+ ##################################################################################
210
+ def reset_filters
211
+ @set.sitemap_filters.reset
212
+ end
213
+
214
+ end
215
+
216
+ end
@@ -0,0 +1,27 @@
1
+ # DONE
2
+ require 'active_support/concern'
3
+
4
+ module DuckMap
5
+
6
+ ##################################################################################
7
+ # Model has a very specific purpose. To hold the Array of Hash objects that represent
8
+ # the contents of a single sitemap.
9
+ module Model
10
+ extend ActiveSupport::Concern
11
+
12
+ ##################################################################################
13
+ # Array containing all of the Hash objects that represent the contents of a single sitemap.
14
+ # Originally, this method was part of {DuckMap::ControllerHelpers}, however, it was separated
15
+ # and moved here to minimize the number of methods being added to controllers.
16
+ # @return [Array]
17
+ def sitemap_model
18
+ @sitemap_model ||= []
19
+ end
20
+
21
+ def sitemap_model=(value)
22
+ @sitemap_model = value
23
+ end
24
+
25
+ end
26
+
27
+ end
@@ -0,0 +1,275 @@
1
+ require 'active_support/concern'
2
+
3
+ module DuckMap
4
+
5
+ ##################################################################################
6
+ # Conveience methods that wrap standard ActionDispatch::Routing::Route methods and data.
7
+ # The purpose is to harness the existing code to allow extra config arguments to be included
8
+ # on routes within config/routes.rb. ActionDispatch::Routing::Route has a couple of instance variables
9
+ # (defaults and requirements).
10
+ # - defaults is a Hash that contains the arguments passed to methods within config/routes.rb such as
11
+ # resources, match, etc. The arguments passed to most routes config methods will actually make a call
12
+ # to match to add a route and will include any extra arguments you pass in the defaults Hash.
13
+ # The methods of this module extract those values.
14
+ # - requirements is a Hash that contains the controller and action name of the current route.
15
+ module Route
16
+ extend ActiveSupport::Concern
17
+ include DuckMap::ArrayHelper
18
+
19
+ ##################################################################################
20
+ #module InstanceMethods
21
+
22
+ # Identifies the current routes as being a sitemap route.
23
+ attr_accessor :is_sitemap
24
+
25
+ # The route name of the sitemap which the current route is assigned.
26
+ attr_accessor :sitemap_route_name
27
+
28
+ # The route name of the sitemap without the namespace.
29
+ attr_accessor :sitemap_raw_route_name
30
+
31
+ # Identifies that the current sitemap route was defined with a block.
32
+ attr_accessor :sitemap_with_block
33
+
34
+ # Total amount of URL nodes allowed in the sitemap.
35
+ attr_accessor :url_limit
36
+
37
+ ##################################################################################
38
+ # Identifies the current routes as being a sitemap route.
39
+ # @return [Boolean] True if the route is a sitemap route, otherwise, false.
40
+ def is_sitemap?
41
+ @is_sitemap = @is_sitemap.nil? ? false : @is_sitemap
42
+ end
43
+
44
+ ##################################################################################
45
+ # @return [String] Namespace prefix used when creating the route.
46
+ def namespace_prefix
47
+ value = nil
48
+
49
+ unless self.sitemap_raw_route_name.blank?
50
+ value = self.sitemap_route_name.gsub(self.sitemap_raw_route_name, "")
51
+ end
52
+
53
+ return value
54
+ end
55
+
56
+ ##################################################################################
57
+ def namespace_prefix_underscores
58
+ value = 0
59
+
60
+ buffer = self.namespace_prefix
61
+ unless buffer.blank?
62
+ value = buffer.split("_").length
63
+ end
64
+
65
+ return value
66
+ end
67
+
68
+ ##################################################################################
69
+ # Identifies that the current sitemap route was defined with a block.
70
+ # @return [Boolean] True if the route was defined with a block, otherwise, false.
71
+ def sitemap_with_block?
72
+ @sitemap_with_block = @sitemap_with_block.nil? ? false : @sitemap_with_block
73
+ end
74
+
75
+ ##################################################################################
76
+ # Conveience method to return the name assigned to the route. There is no need for nil
77
+ # checking the return value of this method. It will simply return an empty String.
78
+ # @return [String] Name assigned to the route.
79
+ def route_name
80
+ return "#{self.name}"
81
+ end
82
+
83
+ ##################################################################################
84
+ # Returns the controller_name assigned to the route.
85
+ # @return [String] Controller_name name assigned to the route.
86
+ def controller_name
87
+ return self.requirements[:controller].blank? ? "" : self.requirements[:controller].to_s
88
+ end
89
+
90
+ ##################################################################################
91
+ # Returns the action assigned to the route.
92
+ # @return [String] Action name assigned to the route.
93
+ def action_name
94
+ return self.requirements[:action].blank? ? "" : self.requirements[:action].to_s
95
+ end
96
+
97
+ ##################################################################################
98
+ # The class name (as a String) of a model to be used as the source of rows for a route
99
+ # when generating sitemap content.
100
+ # @return [String]
101
+ def model
102
+ return self.defaults[:model]
103
+ end
104
+
105
+ ##################################################################################
106
+ # Setting changefreq directly on the route will override values set within a controller and model.
107
+ # This value will be used when generating a sitemap for the specific route.
108
+ #
109
+ # MyApp::Application.routes.draw do
110
+ #
111
+ # resources :trucks, :changefreq => "daily"
112
+ #
113
+ # end
114
+ #
115
+ # produces url's like the following:
116
+ #
117
+ # <url>
118
+ # <loc>http://localhost:3000/trucks/1.html</loc>
119
+ # <lastmod>2011-10-13T06:16:24+00:00</lastmod>
120
+ # <changefreq>daily</changefreq>
121
+ # <priority>0.5</priority>
122
+ # </url>
123
+ #
124
+ # @return [String] Current value of changefreq.
125
+ def changefreq
126
+ return self.defaults[:changefreq]
127
+ end
128
+
129
+ ##################################################################################
130
+ # Setting priority directly on the route will override values set within a controller and model.
131
+ # This value will be used when generating a sitemap for the specific route.
132
+ #
133
+ # MyApp::Application.routes.draw do
134
+ #
135
+ # resources :trucks, :priority => "0.4"
136
+ #
137
+ # end
138
+ #
139
+ # produces url's like the following:
140
+ #
141
+ # <url>
142
+ # <loc>http://localhost:3000/trucks/1.html</loc>
143
+ # <lastmod>2011-10-13T06:16:24+00:00</lastmod>
144
+ # <changefreq>monthly</changefreq>
145
+ # <priority>0.4</priority>
146
+ # </url>
147
+ #
148
+ # @return [String] Current value of priority.
149
+ def priority
150
+ return self.defaults[:priority]
151
+ end
152
+
153
+ ##################################################################################
154
+ # Specifies the extension that should be used when generating a url for the route within a sitemap.
155
+ #
156
+ # MyApp::Application.routes.draw do
157
+ #
158
+ # resources :trucks, :url_format => "xml"
159
+ #
160
+ # end
161
+ #
162
+ # produces url's like the following:
163
+ #
164
+ # <loc>http://localhost:3000/trucks/1.xml</loc>
165
+ # <loc>http://localhost:3000/trucks/2.xml</loc>
166
+ #
167
+ # @return [String]
168
+ def url_format
169
+ # a quick hack to default the extension for the root url to :none
170
+ return self.defaults[:url_format].blank? && self.route_name.eql?("root") ? :none : self.defaults[:url_format]
171
+ end
172
+
173
+ ##################################################################################
174
+ def exclude_actions
175
+ return self.duckmap_defaults(:exclude_actions)
176
+ end
177
+
178
+ ##################################################################################
179
+ def exclude_controllers
180
+ return self.duckmap_defaults(:exclude_controllers)
181
+ end
182
+
183
+ ##################################################################################
184
+ def exclude_names
185
+ return self.duckmap_defaults(:exclude_names)
186
+ end
187
+
188
+ ##################################################################################
189
+ def exclude_verbs
190
+ return self.duckmap_defaults(:exclude_verbs)
191
+ end
192
+
193
+ ##################################################################################
194
+ def include_actions
195
+ return self.duckmap_defaults(:include_actions)
196
+ end
197
+
198
+ ##################################################################################
199
+ def include_controllers
200
+ return self.duckmap_defaults(:include_controllers)
201
+ end
202
+
203
+ ##################################################################################
204
+ def include_names
205
+ return self.convert_to(self.duckmap_defaults(:include_names), :string)
206
+ end
207
+
208
+ ##################################################################################
209
+ def include_verbs
210
+ return self.duckmap_defaults(:include_verbs)
211
+ end
212
+
213
+ ##################################################################################
214
+ def verb_symbol
215
+ value = nil
216
+ unless self.verb.blank?
217
+ buffer = self.verb.to_s.downcase
218
+ if buffer.include?("delete")
219
+ value = :delete
220
+
221
+ elsif buffer.include?("get")
222
+ value = :get
223
+
224
+ elsif buffer.include?("post")
225
+ value = :post
226
+
227
+ elsif buffer.include?("put")
228
+ value = :put
229
+
230
+ end
231
+
232
+ end
233
+ return value
234
+ end
235
+
236
+ ##################################################################################
237
+ # Indicates if the current route requirements segments keys to generate a url.
238
+ # @return [Boolean] True if keys are required to generate a url, otherwise, false.
239
+ def keys_required?
240
+ keys = self.segment_keys.dup
241
+ keys.delete(:format)
242
+ return keys.length > 0 ? true : false
243
+ end
244
+
245
+ ##################################################################################
246
+ # Looks for a key within ActionDispatch::Routing::Route.defaults.
247
+ # If found:
248
+ # - determine the type of value:
249
+ # - If Array, return the array.
250
+ # - If String, create an array, add the String to it, and return the array.
251
+ # - If Symbol, create an array, add the Symbol to it, and return the array.
252
+ # If nothing found, return an empty array.
253
+ # returns [Array]
254
+ def duckmap_defaults(key)
255
+ values = []
256
+
257
+ if self.defaults && self.defaults[key]
258
+ if self.defaults[key].kind_of?(Array)
259
+ values = self.defaults[key]
260
+
261
+ elsif self.defaults[key].kind_of?(String)
262
+ values.push(self.defaults[key])
263
+
264
+ elsif self.defaults[key].kind_of?(Symbol)
265
+ values.push(self.defaults[key])
266
+
267
+ end
268
+ end
269
+
270
+ return values
271
+ end
272
+ #end
273
+
274
+ end
275
+ end
@@ -0,0 +1,177 @@
1
+ # the rule is the filter criteria acts as a list of things to include. period.
2
+ # include methods will add to the list of criteria to include.
3
+ # exclude methods will remove from the list of criteria to include.
4
+ # for route level evaluations, the list of criteria to include is empty. therefore, meaning nothing is included.
5
+ # the include attributes are added to the list of criteria to include, then, the exclude attributes are processed
6
+ # to remove attributes from the list of criteria to include.
7
+ # this will match the default behavior of nothing being included unless explicitly included.
8
+ require 'active_support/concern'
9
+
10
+ module DuckMap
11
+
12
+ class DuckmapExclude < StandardError
13
+ end
14
+
15
+ class DuckmapInclude < StandardError
16
+ end
17
+
18
+ class ExplicitExclude < StandardError
19
+ end
20
+
21
+ class ExplicitInclude < StandardError
22
+ end
23
+
24
+ class RouteNameMissing < StandardError
25
+ end
26
+
27
+ ##################################################################################
28
+ # Mixin module for ActionDispatch::Routing::RouteSet. This module is responsible for evaluating each route
29
+ # for consideration to be included in a sitemap.
30
+ module RouteFilter
31
+ extend ActiveSupport::Concern
32
+
33
+ # Indicates to the route filter to exclude / include routes that are missing names.
34
+ attr_accessor :blank_route_name
35
+
36
+ ##################################################################################
37
+ # Indicates to the route filter to exclude / include routes that are missing names.
38
+ # @return [Boolean]
39
+ def blank_route_name?
40
+ return self.blank_route_name.nil? ? false : self.blank_route_name
41
+ end
42
+
43
+ ##################################################################################
44
+ # A Hash containing all of the values for exlude sitemap_filters.
45
+ # @return [Hash]
46
+ def sitemap_filters
47
+ return @sitemap_filters ||= FilterStack.new
48
+ end
49
+
50
+ ##################################################################################
51
+ # Determines if the current routes passes the current filter criteria.
52
+ # @return [Boolean] True if it passes, otherwise, false.
53
+ def include_route?(route)
54
+ value = false
55
+
56
+ unless route.blank? || route.path.spec =~ %r{/rails/info/properties|^/assets}
57
+ # this block looks very busy, but, actually all that is really going on here is we are matching
58
+ # parts of the current route against sitemap_filter data configured via config/routes.rb, then,
59
+ # raising and catching exceptions based on the outcome of each evaluation.
60
+ # the rule is all routes excluded, unless included via some type of filter criteria.
61
+
62
+ begin
63
+
64
+ DuckMap.logger.debug "\r\n Route: #{route.verb_symbol} #{route.route_name.ljust(30)} #{route.controller_name} => #{route.action_name}"
65
+ DuckMap.logger.debug route
66
+ DuckMap.logger.debug %(#{"Path:".rjust(30)} #{route.path.spec})
67
+
68
+ # we don't want to include routes without a name.
69
+ if route.name.blank?
70
+ unless self.blank_route_name?
71
+ raise RouteNameMissing, "route name blank"
72
+ end
73
+ end
74
+
75
+ if match_any?(route.action_name, route.exclude_actions) ||
76
+ match_any?(route.controller_name, route.exclude_controllers) ||
77
+ match_any?(route.name, route.exclude_names) ||
78
+ match_any?(route.verb_symbol, route.exclude_verbs)
79
+
80
+ raise DuckmapExclude, "exclude"
81
+
82
+ end
83
+
84
+ if match_any?(route.action_name, route.include_actions) ||
85
+ match_any?(route.controller_name, route.include_controllers) ||
86
+ match_any?(route.name, route.include_names) ||
87
+ match_any?(route.verb_symbol, route.include_verbs)
88
+
89
+ raise DuckmapInclude, "include"
90
+
91
+ end
92
+
93
+ if match_any?(route.action_name, self.sitemap_filters.current_filter[:actions])
94
+ raise ExplicitInclude, "include"
95
+ end
96
+
97
+ if match_any?(route.verb_symbol, self.sitemap_filters.current_filter[:verbs])
98
+ raise ExplicitInclude, "include"
99
+ end
100
+
101
+ if match_any?(route.controller_name, self.sitemap_filters.current_filter[:controllers])
102
+ raise ExplicitInclude, "include"
103
+ end
104
+
105
+ if match_any?(route.name, self.sitemap_filters.current_filter[:names])
106
+ raise ExplicitInclude, "include"
107
+ end
108
+
109
+ rescue DuckmapExclude => e
110
+ DuckMap.logger.debug %(#{"Duckmap Exclude".rjust(30)} -> #{e})
111
+
112
+ if match_any?(route.action_name, route.include_actions) ||
113
+ match_any?(route.controller_name, route.include_controllers) ||
114
+ match_any?(route.name, route.include_names) ||
115
+ match_any?(route.verb_symbol, route.include_verbs)
116
+
117
+ DuckMap.logger.debug %(#{"Duckmap Exclude".rjust(30)} -> included again...)
118
+ value = true
119
+ end
120
+
121
+ rescue DuckmapInclude => e
122
+ DuckMap.logger.debug %(#{"Duckmap Include".rjust(30)} -> #{e})
123
+ value = true
124
+
125
+ rescue ExplicitInclude => e
126
+ DuckMap.logger.debug %(#{"Explicit Include".rjust(30)} -> #{e})
127
+ value = true
128
+
129
+ rescue RouteNameMissing => e
130
+ DuckMap.logger.debug %(#{"Route Name Missing".rjust(30)} -> #{e})
131
+
132
+ rescue Exception => e
133
+ DuckMap.logger.info %(#{"Unknown Exception".rjust(30)} -> #{e})
134
+ DuckMap.logger.info e.backtrace.join("\r\n")
135
+ end
136
+
137
+ end
138
+
139
+ return value
140
+ end
141
+
142
+ ##################################################################################
143
+ # Matches a single value against an array of Strings, Symbols, and Regexp's.
144
+ # @param [String] data Any value as a String to compare against any of the Strings, Symbols, or Regexp's in the values argument.
145
+ # @param [Array] values An array of Strings, Symbols, or Regexp's to compare against the data argument. The array can be a mix of all three possible types.
146
+ # @return [Boolean] True if data matches any of the values or expressions in the values argument, otherwise, false.
147
+ def match_any?(data = nil, values = [])
148
+
149
+ unless data.blank?
150
+
151
+ unless values.kind_of?(Array)
152
+ # wow, this worked!!??
153
+ # values was not an array, so, add values to a new array and assign back to values
154
+ values = [values]
155
+ end
156
+
157
+ values.each do |value|
158
+
159
+ if value.kind_of?(String) && (data.to_s.downcase.eql?(value.downcase) || value.eql?("all"))
160
+ return true
161
+
162
+ elsif value.kind_of?(Symbol) && (data.downcase.to_sym.eql?(value) || value.eql?(:all))
163
+ return true
164
+
165
+ elsif value.kind_of?(Regexp) && data.match(value)
166
+ return true
167
+
168
+ end
169
+ end
170
+
171
+ end
172
+
173
+ return false
174
+ end
175
+
176
+ end
177
+ end