1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181
|
module GrapePathHelpers
# wrapper around Grape::Route that adds a helper method
class DecoratedRoute
attr_reader :route, :helper_names, :helper_arguments,
:extension, :route_options
PATH_SEGMENTS_REGEXP = %r{\(/?\.:?\w+\)|/(?!\))|(?<=\))|\??\*}
PATH_SEGMENTS_WITH_WILDCARDS_REGEXP = %r{\(/?\.:?\w+\)|/(?!\))|(?<=\))|\?}
def self.sanitize_method_name(string)
string.gsub(/\W|^[0-9]/, '_')
end
def initialize(route)
@route = route
@route_options = route.options
@helper_names = []
@helper_arguments = required_helper_segments
@extension = default_extension
define_path_helpers
end
def default_extension
pattern = /\((\.\:?\w+)\)$/
match = route_path.match(pattern)
return '' unless match
ext = match.captures.first
if ext == '.:format'
''
else
ext
end
end
def define_path_helpers
route_versions.each do |version|
route_attributes = { version: version, format: extension }
method_name = path_helper_name(route_attributes)
@helper_names << method_name
define_path_helper(method_name, route_attributes)
end
end
def define_path_helper(method_name, route_attributes)
method_body = <<-RUBY
def #{method_name}(attributes = {}, include_wildcard_segments = false)
attrs = #{route_attributes}.merge(attributes)
query_params = attrs.delete(:params)
content_type = attrs.delete(:format)
path = '/' + path_segments_with_values(attrs, include_wildcard_segments).join('/')
path + content_type + query_string(query_params)
end
RUBY
instance_eval method_body
end
def query_string(params)
if params.nil?
''
else
'?' + params.to_param
end
end
def route_versions
return [nil] if route_version.nil? || route_version.empty?
if route_version.is_a?(String)
version_pattern = /[^\[",\]\s]+/
route_version.scan(version_pattern)
else
route_version
end
end
def path_helper_name(opts = {})
if route_options[:as]
name = route_options[:as].to_s
else
segments = path_segments_with_values(opts)
name = if segments.empty?
'root'
else
segments.join('_')
end
end
sanitized_name = self.class.sanitize_method_name(name)
sanitized_name + '_path'
end
def segment_to_value(segment, opts = {})
if dynamic_segment?(segment)
options = route.options.merge(stringify_keys(opts))
key = segment.slice(1..-1).to_sym
options[key]
else
segment
end
end
def path_segments_with_values(opts, include_wildcard_segments = false)
segments = path_segments(include_wildcard_segments).map do |s|
segment_to_value(s, opts)
end
segments.reject(&:blank?)
end
def path_segments(include_wildcard_segments = false)
pattern = if include_wildcard_segments
PATH_SEGMENTS_WITH_WILDCARDS_REGEXP
else
PATH_SEGMENTS_REGEXP
end
route_path.split(pattern).reject(&:blank?)
end
def dynamic_path_segments
segments = path_segments.select do |segment|
dynamic_segment?(segment)
end
segments.map { |s| s.slice(1..-1) }
end
def dynamic_segment?(segment)
segment.start_with?(':', '*')
end
def optional_segment?(segment)
segment.start_with?('(')
end
def required_helper_segments
segments_in_options = dynamic_path_segments.select do |segment|
route.options[segment.to_sym]
end
dynamic_path_segments - segments_in_options
end
def special_keys
%w[format params]
end
def uses_segments_in_path_helper?(segments)
segments = segments.reject { |x| special_keys.include?(x) }
if helper_arguments.empty? && segments.any?
false
else
helper_arguments.all? { |x| segments.include?(x) }
end
end
def route_path
route.path
end
def route_version
route.version
end
def route_namespace
route.namespace
end
def route_method
route.request_method
end
private
def stringify_keys(original)
original.each_with_object({}) do |(key, value), hash|
hash[key.to_sym] = value
end
end
end
end
|