diff --git a/lib/global_id/identification.rb b/lib/global_id/identification.rb index 1cd4941..ef309fa 100644 --- a/lib/global_id/identification.rb +++ b/lib/global_id/identification.rb @@ -116,5 +116,35 @@ def to_signed_global_id(options = {}) def to_sgid_param(options = {}) to_signed_global_id(options).to_param end + + class << self + def included(base) + base.extend(ClassMethods) + end + end + + module ClassMethods + # Build a Global ID from the given object. + # + # If the object responds to `to_global_id` it will return the result of that call. + # Person.build_global_id(Person.find(1)) # => #> + # If the object is a string or an integer, it will build a GlobalID using that object. + # Person.build_global_id(1) # => #> + # If the object is not a string or an integer, it will raise an ArgumentError. + # Person.build_global_id(Person) # => ArgumentError: Can't build a Global ID for Class + # + # An app is required to create a GlobalID. Pass the :app option or set the default GlobalID.app. + + def build_global_id(obj, options = {}) + return obj.to_global_id(options) if obj.respond_to?(:to_global_id) + raise ArgumentError, "Can't build a Global ID for #{obj.class}" unless obj.is_a?(String) || obj.is_a?(Integer) + + unless (app = options.fetch(:app) { GlobalID.app }) + raise ArgumentError, "An app is required to create a GlobalID. Pass the :app option or set the default GlobalID.app." + end + + GlobalID.new(URI::GID.build(app: app, model_name: name, model_id: obj, params: options.except(:app, :verifier, :for))) + end + end end end diff --git a/test/cases/global_identification_test.rb b/test/cases/global_identification_test.rb index 86f51d9..b2ab85e 100644 --- a/test/cases/global_identification_test.rb +++ b/test/cases/global_identification_test.rb @@ -8,11 +8,15 @@ class GlobalIdentificationTest < ActiveSupport::TestCase test 'creates a Global ID from self' do assert_equal GlobalID.create(@model), @model.to_global_id assert_equal GlobalID.create(@model), @model.to_gid + assert_equal PersonModel.build_global_id(@model), @model.to_gid + assert_equal PersonModel.build_global_id(1), @model.to_global_id end test 'creates a Global ID with custom params' do assert_equal GlobalID.create(@model, some: 'param'), @model.to_global_id(some: 'param') assert_equal GlobalID.create(@model, some: 'param'), @model.to_gid(some: 'param') + assert_equal PersonModel.build_global_id(@model, some: 'param'), @model.to_gid(some: 'param') + assert_equal PersonModel.build_global_id(1, some: 'param'), @model.to_global_id(some: 'param') end test 'creates a signed Global ID from self' do @@ -30,6 +34,10 @@ class GlobalIdentificationTest < ActiveSupport::TestCase assert_equal SignedGlobalID.create(@model, some: 'param'), @model.to_sgid(some: 'param') end + test "doesn't create a Global ID if ID is not valid" do + assert_raises(ArgumentError) { PersonModel.build_global_id(PersonModel) } + end + test 'dup should clear memoized to_global_id' do global_id = @model.to_global_id dup_model = @model.dup