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.
- data/app/controllers/sitemap_base_controller.rb +13 -0
- data/app/controllers/sitemap_controller.rb +3 -0
- data/app/views/sitemap/default_template.xml.erb +10 -0
- data/config/routes.rb +5 -0
- data/lib/duck_map/array_helper.rb +50 -0
- data/lib/duck_map/attributes.rb +182 -0
- data/lib/duck_map/class_helpers.rb +55 -0
- data/lib/duck_map/config.rb +367 -0
- data/lib/duck_map/controller_helpers.rb +206 -0
- data/lib/duck_map/engine.rb +92 -0
- data/lib/duck_map/filter_stack.rb +200 -0
- data/lib/duck_map/handlers/base.rb +102 -0
- data/lib/duck_map/handlers/index.rb +140 -0
- data/lib/duck_map/handlers/show.rb +231 -0
- data/lib/duck_map/last_mod.rb +45 -0
- data/lib/duck_map/list.rb +82 -0
- data/lib/duck_map/logger.rb +193 -0
- data/lib/duck_map/mapper.rb +216 -0
- data/lib/duck_map/model.rb +27 -0
- data/lib/duck_map/route.rb +275 -0
- data/lib/duck_map/route_filter.rb +177 -0
- data/lib/duck_map/route_set.rb +209 -0
- data/lib/duck_map/sitemap_object.rb +457 -0
- data/lib/duck_map/static.rb +146 -0
- data/lib/duck_map/sync.rb +192 -0
- data/lib/duck_map/version.rb +3 -0
- data/lib/duck_map/view_helpers.rb +107 -0
- data/lib/duck_map.rb +3 -0
- data/lib/generators/duckmap/sitemaps/USAGE +23 -0
- data/lib/generators/duckmap/sitemaps/sitemaps_generator.rb +36 -0
- data/lib/generators/duckmap/static/USAGE +47 -0
- data/lib/generators/duckmap/static/static_generator.rb +51 -0
- data/lib/generators/duckmap/sync/USAGE +25 -0
- data/lib/generators/duckmap/sync/sync_generator.rb +29 -0
- metadata +96 -0
@@ -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
|