From 80a4a818d5ee2dfbd63ed05665bc5ddc4786e020 Mon Sep 17 00:00:00 2001 From: Daniel Leyden Date: Fri, 21 Oct 2016 10:48:32 +0100 Subject: [PATCH 1/3] Support for inheriting resource mappings When url map is in use, but the application is mounted through a different mechanism, e.g. 'use' in sinatra, provide a way to re-use that mapping Change-Id: Icc259a44e386bd1ddf48e09462f7ddc3f5110039 --- lib/doc_my_routes/doc/errors.rb | 1 + lib/doc_my_routes/doc/mapping.rb | 16 ++++++++++++---- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/lib/doc_my_routes/doc/errors.rb b/lib/doc_my_routes/doc/errors.rb index 435e8c4..12558d3 100644 --- a/lib/doc_my_routes/doc/errors.rb +++ b/lib/doc_my_routes/doc/errors.rb @@ -3,4 +3,5 @@ module DocMyRoutes class ExampleMissing < StandardError; end class UnsupportedError < StandardError; end class MultipleMappingDetected < UnsupportedError; end + class NoMappingDetected < UnsupportedError; end end diff --git a/lib/doc_my_routes/doc/mapping.rb b/lib/doc_my_routes/doc/mapping.rb index 112163d..ee55bb2 100644 --- a/lib/doc_my_routes/doc/mapping.rb +++ b/lib/doc_my_routes/doc/mapping.rb @@ -36,6 +36,10 @@ def mapping_used? Object.const_defined?('Rack::URLMap') end + def inherit_mapping(child_class, super_class) + (@inherited_mappings ||= {})[child_class.to_s] = super_class.to_s + end + # This method associates to each route its namespace, if detected. # # Note: when application A is inherited by B and only B is mapped, from @@ -100,15 +104,19 @@ def mount_point_for_resource(resource) class_name = remapped_applications[class_name].first if \ remapped_applications.key?(class_name) - locations = route_mapping[class_name] + validate_locations(class_name, extract_locations(class_name)) + end - validate_locations(class_name, locations) + def extract_locations(class_name) + route_mapping[class_name] || route_mapping[(@inherited_mappings || {})[class_name]] end # Detects if multiple locations are available and for now fail def validate_locations(resource, locations) - fail "Resource #{resource} has multiple mappings, but that's not " \ - "supported yet: #{locations}" if locations.size > 1 + fail "Resource #{resource} has no mapping, so we can't tell where it is mounted!" \ + if locations.nil? + fail MultipleMappingDetected, "Resource #{resource} has multiple mappings, but that's " \ + "not supported yet: #{locations}" if locations.size > 1 return locations.first if locations.size == 1 From 4af3d9313603584609fdf95d5cd7516fddb218a6 Mon Sep 17 00:00:00 2001 From: Daniel Leyden Date: Fri, 21 Oct 2016 17:56:14 +0100 Subject: [PATCH 2/3] Adding tests for inherited mapping Change-Id: I80d134a2b6c0213e8553ee6ec36ba29f18619f91 --- lib/doc_my_routes/doc/mapping.rb | 6 +++--- lib/doc_my_routes/version.rb | 2 +- spec/system/myapp_spec.rb | 32 ++++++++++++++++++++++++++++++++ 3 files changed, 36 insertions(+), 4 deletions(-) diff --git a/lib/doc_my_routes/doc/mapping.rb b/lib/doc_my_routes/doc/mapping.rb index ee55bb2..50ca646 100644 --- a/lib/doc_my_routes/doc/mapping.rb +++ b/lib/doc_my_routes/doc/mapping.rb @@ -113,10 +113,10 @@ def extract_locations(class_name) # Detects if multiple locations are available and for now fail def validate_locations(resource, locations) - fail "Resource #{resource} has no mapping, so we can't tell where it is mounted!" \ - if locations.nil? + fail NoMappingDetected, "Resource #{resource} has no mapping, so we can't tell where " \ + 'it is mounted!' if locations.nil? fail MultipleMappingDetected, "Resource #{resource} has multiple mappings, but that's " \ - "not supported yet: #{locations}" if locations.size > 1 + "not supported yet: #{locations}" if locations.size > 1 return locations.first if locations.size == 1 diff --git a/lib/doc_my_routes/version.rb b/lib/doc_my_routes/version.rb index ce2e3f3..808a255 100644 --- a/lib/doc_my_routes/version.rb +++ b/lib/doc_my_routes/version.rb @@ -1,4 +1,4 @@ # DocMyRoutes version module DocMyRoutes - VERSION = '0.10.0' + VERSION = '0.11.0' end diff --git a/spec/system/myapp_spec.rb b/spec/system/myapp_spec.rb index d585abb..4003085 100644 --- a/spec/system/myapp_spec.rb +++ b/spec/system/myapp_spec.rb @@ -10,6 +10,7 @@ # The tests are only focused on the route created in each context # without taking into consideration the real DocMyRoutes routes DocMyRoutes::RouteCollection.routes.clear + DocMyRoutes::Mapping.instance_variable_set :@remapped_applications, nil reload_app end @@ -56,5 +57,36 @@ expect(subject.map(&:namespace)).to eq(['/myapp', '/myapp']) end end + + context 'where a different app is mapped that uses that app' do + let(:other_class) do + Object.send(:remove_const, :MyOtherClass) if Object.constants.include?(:MyOtherClass) + MyOtherClass = Class.new do + def self.class + MyOtherClass + end + end + end + + before do + Rack::URLMap.new('/other_app' => other_class) + end + + subject { DocMyRoutes::RouteCollection.routes[app_name].map(&:path) } + + it 'fails due to no mapping being available' do + expect { subject }.to raise_error DocMyRoutes::NoMappingDetected + end + + context 'and the app is marked to inherit the mapping from the different app' do + before do + DocMyRoutes::Mapping.inherit_mapping(Object.const_get(app_name), MyOtherClass) + end + + it 'the routes are correctly namespaced' do + expect(subject).to eq(['/other_app', '/other_app']) + end + end + end end end From 24fab914baf164b3d43fa887a2130a9dd992ad32 Mon Sep 17 00:00:00 2001 From: Daniel Leyden Date: Tue, 15 Nov 2016 17:29:33 +0000 Subject: [PATCH 3/3] Updating README Change-Id: I4856ec48caa9f79d90f4de41179c307f7d239b36 --- README.md | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/README.md b/README.md index ee71d7d..d57ea27 100644 --- a/README.md +++ b/README.md @@ -199,6 +199,31 @@ DocMyRoutes::Documentation.generate ... ``` +Note: there are occasions where an application may be mounted using url map and +be composed of other apps by making use of the 'use' directive in rack. In this +case, you need to tell DocMyRoutes to link the two together. By doing this, +DocMyRoutes will automatically provide documentation for the child apps mounted +wherever the composed app ends up being mounted. + +e.g. + +```ruby +class MyChildApp; end +class MyOtherChildApp; end + +class MyComposedApp + DocMyRoutes::Mapping.inherit_mapping(MyChildApp, self) + DocMyRoutes::Mapping.inherit_mapping(MyOtherChildApp, self) + + use MyChildApp + use MyOtherChildApp +end + +app = Rack::Builder.app do + run Rack::URLMap.new('/myapp' => MyComposedApp.new) +end +``` + ## Customisation Some aspects of DocMyRoutes can be customised to provide a different user