From 480ea5ae37cb27538e909a4844240258525fb096 Mon Sep 17 00:00:00 2001 From: Derek Lindahl Date: Mon, 6 Apr 2015 15:41:55 -0700 Subject: [PATCH] Add alternate string identifier support for Resource.find This allows the usage of non-Fixnum unique identifiers for GETs for a specific resource as long as a matching _link is defined in the Api Schema. --- lib/frenetic.rb | 1 + lib/frenetic/behaviors.rb | 6 ++ .../behaviors/alternate_string_identifier.rb | 55 +++++++++++++++++++ .../alternate_string_identifier_spec.rb | 44 +++++++++++++++ 4 files changed, 106 insertions(+) create mode 100644 lib/frenetic/behaviors.rb create mode 100644 lib/frenetic/behaviors/alternate_string_identifier.rb create mode 100644 spec/behaviors/alternate_string_identifier_spec.rb diff --git a/lib/frenetic.rb b/lib/frenetic.rb index ac01761..30ae3c8 100644 --- a/lib/frenetic.rb +++ b/lib/frenetic.rb @@ -6,6 +6,7 @@ require 'frenetic/version' require 'frenetic/errors' +require 'frenetic/behaviors' require 'frenetic/briefly_memoizable' require 'frenetic/connection' require 'frenetic/middleware/hal_json' diff --git a/lib/frenetic/behaviors.rb b/lib/frenetic/behaviors.rb new file mode 100644 index 0000000..2440745 --- /dev/null +++ b/lib/frenetic/behaviors.rb @@ -0,0 +1,6 @@ +require 'frenetic/behaviors/alternate_string_identifier' + +class Frenetic + module Behaviors + end +end diff --git a/lib/frenetic/behaviors/alternate_string_identifier.rb b/lib/frenetic/behaviors/alternate_string_identifier.rb new file mode 100644 index 0000000..dbf5da1 --- /dev/null +++ b/lib/frenetic/behaviors/alternate_string_identifier.rb @@ -0,0 +1,55 @@ +# Allows a resource to be found by a string-based alternative key +# +# For example +# +# module MyClient +# module MyResource < Frenetic::Resource +# extend Frenetic::Behaviors::AlternateStringIdentifier +# +# def self.find(id) +# super(finder_params(id, :username)) +# end +# end +# end +# +# Given an Api Schema such as: +# +# { +# _links: { +# my_resource: [{ +# { href: '/api/my_resource/{id}', rel: 'id' }, +# { href: '/api/my_resource/{username}?specific_to=username', rel: 'username' }, +# }] +# } +# } +# +# MyClient::MyResource.find will choose the alternate link relation based on +# the string-based ID passed in. +# +# MyClient::MyResource.find(1) +# # Executes /api/my_resource/1 +# +# MyClient::MyResource.find('100') +# # Executes /api/my_resource/100 +# +# MyClient::MyResource.find('jdoe') +# Executes /api/my_resource/jdoe?specific_to=username +# +class Frenetic + module Behaviors + module AlternateStringIdentifier + def finder_params(unique_id, alternate_key) + return unique_id if unique_id.is_a? Hash + params = {} + key = nil + if unique_id.to_i.to_s == unique_id.to_s + key = :id + elsif !unique_id.nil? + key = alternate_key + end + params[key] = unique_id + params + end + end + end +end diff --git a/spec/behaviors/alternate_string_identifier_spec.rb b/spec/behaviors/alternate_string_identifier_spec.rb new file mode 100644 index 0000000..15708da --- /dev/null +++ b/spec/behaviors/alternate_string_identifier_spec.rb @@ -0,0 +1,44 @@ +require 'spec_helper' + +describe Frenetic::Behaviors::AlternateStringIdentifier do + let(:my_temp_resource) do + Class.new(Frenetic::Resource) + end + + before do + stub_const 'MyTempResource', my_temp_resource + MyTempResource.send(:extend, described_class) + end + + describe '.finder_params' do + let(:id) { } + let(:alternate_key) { } + + subject { MyTempResource.finder_params(id, alternate_key) } + + context 'with a Fixnum identifier' do + let(:id) { 1 } + + it 'uses :id for the finder key' do + expect(subject).to include id:id + end + end + + context 'with a String identifier representing a Fixnum' do + let(:id) { '100' } + + it 'uses :id for the finder key' do + expect(subject).to include id:id + end + end + + context 'with a String identifier' do + let(:id) { 'foo' } + let(:alternate_key) { 'alt' } + + it 'uses :id for the finder key' do + expect(subject).to include 'alt' => id + end + end + end +end