Skip to content

Instantly share code, notes, and snippets.

@ridiculous
Created April 15, 2016 00:24
Show Gist options
  • Save ridiculous/e2ce738e542a6e807eeec25d758eff5d to your computer and use it in GitHub Desktop.
Save ridiculous/e2ce738e542a6e807eeec25d758eff5d to your computer and use it in GitHub Desktop.
module VersionableApi
def self.extended(base)
base.class_eval do
def call_versioned_method(name)
VersionableApi.controllers[self.class].call_action(self, name)
end
end
end
class << self
def controllers
@controllers ||= {}
end
def use(klass, mod, versions)
controllers[klass] ||= VersionedController.new(klass)
controllers[klass].default mod
versions.sort.each do |version|
controllers[klass].add_version version
end
end
end
def versionable_action(name, *versions, &block)
VersionableApi.use self, Module.new { define_method name, &block }, versions
define_method(name) { call_versioned_method(name) }
end
class VersionedController
def initialize(controller)
@controller = controller
@mod = Module.new
end
def default(mod)
@mod.prepend mod
end
def add_version(version)
versions[version] = "Versions::#{@controller}::Version#{version.tr('-', '')}".constantize
end
def call_action(context, name)
versions[context.params[:api_version]].instance_method(name).bind(context).call
end
# @note Assumes @versions keys are already sorted
def versions
@versions ||= Hash.new do |me, key|
if key.nil? || me.empty?
@mod
else
# We don't have the requested version, so find the latest one we do have
target_version = me.keys.reverse.detect { |version| version < key }
if target_version
me[target_version]
else
@mod
end
end
end
end
end
end
@ridiculous
Copy link
Author

Example

# app/controllers/events_controller.rb
def create
  # create functionality
end

# becomes ...
extend VersionableApi

versionable_action :create, '2015-06-01' do
  # create functionality
end

The new version behavior is expected to be defined in a similarly named module:

# app/controllers/versions/events_controller/version20150601.rb
module Versions::EventsController::Version20150601
  def create
    # new functionality goes here and will be executed in the context of the controller
  end
end

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment