Class: RailsVersionedRouting::VersionedGroup

Inherits:
Object
  • Object
show all
Defined in:
lib/rails_versioned_routing.rb

Defined Under Namespace

Classes: OptimizedPath, Visitor

Instance Method Summary collapse

Constructor Details

#initialize(routes) ⇒ VersionedGroup

Returns a new instance of VersionedGroup.



97
98
99
# File 'lib/rails_versioned_routing.rb', line 97

def initialize(routes)
  @routes = routes
end

Instance Method Details

#denormalize_path(path) ⇒ Object



189
190
191
# File 'lib/rails_versioned_routing.rb', line 189

def denormalize_path(path)
  path.map {|slug| slug.is_a?(Symbol) ? :VARIABLE : slug }
end

#grouped_by_versionObject



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
182
183
184
185
186
187
# File 'lib/rails_versioned_routing.rb', line 101

def grouped_by_version
  # `versions` is a hash whose empty value is
  # a new, nested hash.
  # The outer hash's keys will all be set to
  # version numbers.
  #
  # The value for each will be a hash.
  # The keys for the inner hash will be string key that
  # combines the routes path and HTTP method.
  #
  # Since higher numbered versions appear first
  # we can rely on the side effect of
  # those path/method pairs being already set
  # so we can safely avoid collisions.
  #
  # routes defined in *earlier* versions will appear
  # in each `versions[version_number]` hash unless
  # the current version has already set a matching
  # path/method key.
  versions = Hash.new {|h,k| h[k] = {}}

  @routes.each do |route|
    # routes that have a constraint added to them appear as
    # an rack 'application' of the type ActionDispatch::Routing::Mapper::Constraints
    if route.app.is_a?(ActionDispatch::Routing::Mapper::Constraints)

      # the constraint might not be a versioned constraint. We handle versioned constraint
      # rack apps different ly
      version_constraint = route.app.constraints.find {|constraint| constraint.is_a?(VersionConstraint) }

      # returns a string representation of the path by walking its
      # AST and building a string
      optimized_path = OptimizedPath.new.accept(route.path.spec)

      if version_constraint
        # transforms the variable names in path into a generic form so we can match the pattern
        # not the specific variable.
        # e.g.
        # get 'posts/:id/hello'
        # get 'posts/:post_id'/hello
        # would generate paths of
        # ['posts', :id, 'hello']
        # and
        # ['posts', :post_id, 'hello']
        # but the routing matching should treat them as
        # ['posts', ANY VARIABLE WE DONT CARE ABOUT NAME, 'hello']
        #
        # So, we transfrom all symbols into the same value
        denormalized_path = denormalize_path(optimized_path)

        # the full key for the hash is a combo of the path and the method
        # since the same path will match different controller/actions if
        # the HTTP method differs.
        denormalize_path_and_method = "#{denormalized_path}-#{route.constraints[:request_method]}"

        version = version_constraint.version

        # add to current version
        versions[version][denormalize_path_and_method] = route

        # add to higher versions unless higher version
        # already includes a path that matches
        versions.each do |k,v|
          next if k <= version

          versions[k][denormalize_path_and_method] ||= route
        end

      else
        versions[0][denormalize_path_and_method] = route
      end
    else
      versions[0][optimized_path] = route
    end
  end

  # flatten one level of the hash
  # {
  #   1 => [<#Route>, <#Route>],
  #   2 => [<#Route>]
  # }
  versions.each do |k,v|
    versions[k] = v.values
  end

  versions
end