Skip to content

Commit

Permalink
Updated automatic lookup of representers for entities
Browse files Browse the repository at this point in the history
  • Loading branch information
Ethan Langevin committed Jul 31, 2014
1 parent a109b40 commit 68d6d95
Show file tree
Hide file tree
Showing 2 changed files with 66 additions and 20 deletions.
56 changes: 44 additions & 12 deletions lib/roar/rails/formats.rb
Original file line number Diff line number Diff line change
Expand Up @@ -38,21 +38,18 @@ def name_for(format, model, controller_path) # DISCUSS: should we pass and proce
end

def collection_representer(format, model, controller_path)
infer_representer(controller_path)
add_representer_suffix(controller_path).camelize.constantize
end

def entity_representer(format, model, controller_path)
model_name = model.class.name.underscore
representer_name = add_representer_suffix(
model.class.name.underscore
)

if namespace = controller_path.namespace
model_name = "#{namespace}/#{model_name}"
end

infer_representer(model_name)
end

def infer_representer(model_name)
add_representer_suffix(model_name).camelize.constantize
find_namespaced_class(
controller_path.camelize,
representer_name.camelize
)
end

def add_representer_suffix(prefix)
Expand All @@ -64,11 +61,46 @@ def detect_collection(model)
return true if Object.const_defined?("ActiveRecord") and model.kind_of?(ActiveRecord::Relation)
end

def find_namespaced_class(basis, to_find)
# If the class we're looking for starts with :: then just use that
return to_find.constantize if to_find =~ /^::/

ancestor_mods = build_ancestor_modules(basis)
namespace = find_class_in_namespaces(ancestor_mods, to_find)

namespace.nil? ? to_find.constantize : namespace.const_get(to_find)
end

def build_ancestor_modules(basis)
namespaces = []
ancestors = basis.split('::')

if ancestors.size > 1
# Transform any namespace this class has into a module
receiver = Object
namespaces = ancestors[0..-2].map do |mod|
receiver = receiver.const_get(mod)
end
end

namespaces
end

def find_class_in_namespaces(modules, class_name)
modules.reverse.detect do |ns|
begin
ns.const_get(class_name, false)
rescue NameError
nil
end
end
end

class Path < String
def namespace
return unless ns = self.match(/(.+)\/\w+$/)
ns[1]
end
end
end
end
end
30 changes: 22 additions & 8 deletions test/formats_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,21 @@ module ObjectsRepresenter
end

module V1
module SingerRepresenter
end
module BassistRepresenter
end
module SingersRepresenter
end
Singer = Class.new

SingerRepresenter = Class.new
BassistRepresenter = Class.new
SingersRepresenter = Class.new
end

class Bassist
module V2
Singer = Class.new
SingerRepresenter = Class.new
SingersRepresenter = Class.new
end

Bassist = Class.new

class FormatsTest < MiniTest::Spec
let (:subject) { Roar::Rails::Formats.new }

Expand Down Expand Up @@ -93,6 +97,16 @@ class FormatsTest < MiniTest::Spec
subject.for(:json, [Object.new], "v1/singers").must_equal V1::SingersRepresenter
end
end

describe "namespaced class" do
it "returns a namespaced entity" do
subject.for(:json, V1::Singer.new, 'v1/singers').must_equal V1::SingerRepresenter
end

it 'finds the right class in another namespace' do
subject.for(:json, V2::Singer.new, 'v1/singers').must_equal V2::SingerRepresenter
end
end
end

describe "with ActiveRecord::Relation" do
Expand Down Expand Up @@ -135,4 +149,4 @@ class PathTest < MiniTest::Spec
it { path.new("bands").namespace.must_equal nil }
it { path.new("v1/bands").namespace.must_equal "v1" }
it { path.new("api/v1/bands").namespace.must_equal "api/v1" }
end
end

0 comments on commit 68d6d95

Please sign in to comment.