Created
April 15, 2016 00:24
-
-
Save ridiculous/e2ce738e542a6e807eeec25d758eff5d to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Example
The new version behavior is expected to be defined in a similarly named module: