From 5d376176680a586b3016569e1ae70ee48418acf8 Mon Sep 17 00:00:00 2001 From: Mark Maglana Date: Mon, 30 Sep 2013 16:24:31 -0700 Subject: [PATCH 1/4] Move the test's describe builder to a reusable method --- test/aviator/core/cli/describer_test.rb | 76 ++++++++++++++----------- 1 file changed, 44 insertions(+), 32 deletions(-) diff --git a/test/aviator/core/cli/describer_test.rb b/test/aviator/core/cli/describer_test.rb index bce4ee6..73f1338 100644 --- a/test/aviator/core/cli/describer_test.rb +++ b/test/aviator/core/cli/describer_test.rb @@ -32,6 +32,45 @@ class Aviator::Test .map{|c| c.basename.to_s } end + + def build_display(provider_name, service_name, request_name, request_class) + display = "Request: #{ request_name }\n\n" + + display << "Parameters:\n" + + params = request_class.optional_params.map{|p| [p, :optional]} + + request_class.required_params.map{|p| [p, :required]} + + aliases = request_class.param_aliases + + params.sort{|a,b| a[0].to_s <=> b[0].to_s }.each do |param| + param_name = (aliases.find{|a,p| p == param[0] } || param)[0] + display << " (#{ param[1].to_s }) #{ param_name }\n" + end + + display << "\nSample Code:\n" + + display << " session.#{ service_name }_service.request(:#{ request_name }, endpoint_type: '#{ request_class.endpoint_type }')" + if params + display << " do |params|\n" + params.each do |pair| + display << " params['#{ pair[0] }'] = value\n" + end + display << " end\n" + end + + if request_class.links + display << "\nLinks:\n" + + request_class.links.each do |link| + display << " #{ link[:rel] }:\n" + display << " #{ link[:href] }\n" + end + end + + display + end + describe '::describe_aviator' do @@ -95,41 +134,14 @@ class Aviator::Test request_class = get_random_entry(get_request_classes(provider_name, service_name)) request_name = request_class.name.split('::').last.underscore - display = "Request: #{ request_name }\n\n" - - display << "Parameters:\n" - - params = request_class.optional_params.map{|p| [p, :optional]} + - request_class.required_params.map{|p| [p, :required]} - - params.sort{|a,b| a[0].to_s <=> b[0].to_s }.each do |param| - display << " (#{ param[1].to_s }) #{ param[0] }\n" - end - - display << "\nSample Code:\n" - - display << " session.#{ service_name }_service.request(:#{ request_name }, endpoint_type: '#{ request_class.endpoint_type }')" - if params - display << " do |params|\n" - params.each do |pair| - display << " params['#{ pair[0] }'] = value\n" - end - display << " end\n" - end - - if request_class.links - display << "\nLinks:\n" - - request_class.links.each do |link| - display << " #{ link[:rel] }:\n" - display << " #{ link[:href] }\n" - end - end + expected = build_display(provider_name, service_name, request_name, request_class) - Aviator::Describer.describe_request( + output = Aviator::Describer.describe_request( provider_name, service_name, request_class.api_version.to_s, request_class.endpoint_type.to_s, request_name - ).must_equal display + ) + + output.must_equal expected end end # describe '::describe_request' From 54c2922f95328944721d7f1ea6cd96b6bff05889 Mon Sep 17 00:00:00 2001 From: Mark Maglana Date: Tue, 1 Oct 2013 14:44:50 -0700 Subject: [PATCH 2/4] Clean up and update describer test --- test/aviator/core/cli/describer_test.rb | 356 ++++++++++++++++-------- 1 file changed, 233 insertions(+), 123 deletions(-) diff --git a/test/aviator/core/cli/describer_test.rb b/test/aviator/core/cli/describer_test.rb index 73f1338..c09b945 100644 --- a/test/aviator/core/cli/describer_test.rb +++ b/test/aviator/core/cli/describer_test.rb @@ -1,152 +1,262 @@ require 'test_helper' class Aviator::Test - + describe 'aviator/core/cli/describer' do - - def get_provider_names - Pathname.new(__FILE__) - .join('..', '..', '..', '..', '..', 'lib', 'aviator') - .children - .select{|c| c.directory? && c.basename.to_s != 'core' } - .map{|c| c.basename.to_s } - end - - - def get_random_entry(array) - array[rand(array.length)] - end + def build_request(provider_name, service_name, request_name, &block) + base_name = :sample_base + base_ver = :v999 + base_ept = :public - def get_request_classes(provider_name, service_name) - service = Aviator::Service.new(provider: provider_name, service: service_name) - service.request_classes - end - - - def get_service_names(provider_name) - Pathname.new(__FILE__) - .join('..', '..', '..', '..', '..', 'lib', 'aviator', provider_name) - .children - .select{|c| c.directory? } - .map{|c| c.basename.to_s } - end - - - def build_display(provider_name, service_name, request_name, request_class) - display = "Request: #{ request_name }\n\n" - - display << "Parameters:\n" + unless @base + request_path = [provider_name, service_name, base_ver, base_ept, base_name] - params = request_class.optional_params.map{|p| [p, :optional]} + - request_class.required_params.map{|p| [p, :required]} - - aliases = request_class.param_aliases + @base = request_path.inject(Aviator) do |namespace, sym| + const_name = sym.to_s.camelize - params.sort{|a,b| a[0].to_s <=> b[0].to_s }.each do |param| - param_name = (aliases.find{|a,p| p == param[0] } || param)[0] - display << " (#{ param[1].to_s }) #{ param_name }\n" - end - - display << "\nSample Code:\n" - - display << " session.#{ service_name }_service.request(:#{ request_name }, endpoint_type: '#{ request_class.endpoint_type }')" - if params - display << " do |params|\n" - params.each do |pair| - display << " params['#{ pair[0] }'] = value\n" + if namespace && namespace.const_defined?(const_name, false) + namespace.const_get(const_name, false) + else + nil + end end - display << " end\n" + + @base ||= Aviator.define_request base_name do + meta :provider, provider_name + meta :service, service_name + meta :api_version, base_ver + meta :endpoint_type, base_ept + end end - - if request_class.links - display << "\nLinks:\n" - - request_class.links.each do |link| - display << " #{ link[:rel] }:\n" - display << " #{ link[:href] }\n" - end - end - - display + + inherit = [provider_name.to_sym, service_name.to_sym, base_ver, base_ept, base_name] + + Aviator.define_request request_name, inherit: inherit, &block end - + + + def klass + Aviator::Describer + end + + def provider_names + klass.send(:provider_names) + end + + + def request_classes(provider_name, service_name) + klass.send(:request_classes, provider_name, service_name) + end + + + def service_names(provider_name) + klass.send(:service_names, provider_names.first) + end + describe '::describe_aviator' do - - it 'describes the aviator gem' do - provider_names = get_provider_names - - display = "Available providers:\n" - - provider_names.each do |provider_name| - display << " #{ provider_name }\n" - end - Aviator::Describer.describe_aviator.must_equal display + it 'shows a list of providers' do + expected = "Available providers:\n" + expected << provider_names.map{|p| " #{ p }" }.join("\n") + "\n" + + klass.describe_aviator.must_equal expected end - + end # describe '::describe_aviator' - - + + describe '::describe_provider' do - - it 'describes the given provider' do - provider_name = get_random_entry(get_provider_names) - service_names = get_service_names(provider_name) - - display = "Available services for #{ provider_name }:\n" - - service_names.each do |service_name| - display << " #{ service_name }\n" - end - Aviator::Describer.describe_provider('openstack').must_equal display + it 'shows a list of available provider services' do + provider = provider_names.first + + expected = "Available services for #{ provider }:\n" + expected << service_names(provider).map{|s| " #{ s }" }.join("\n") + "\n" + + klass.describe_provider(provider).must_equal expected end - + end # describe '::describe_provider' - - - describe '::describe_service' do - - it 'describes a given service for a given provider' do - provider_name = get_random_entry(get_provider_names) - service_name = get_random_entry(get_service_names(provider_name)) - request_classes = get_request_classes(provider_name, service_name) - - display = "Available requests for #{ provider_name } #{ service_name }_service:\n" - request_classes.each do |klass| - display << " #{ klass.api_version } #{ klass.endpoint_type } #{ klass.name.split('::').last.underscore }\n" + + describe '::describe_service' do + + it 'shows a list of available service requests' do + provider = provider_names.first + service = service_names(provider).first + requests = request_classes(provider, service) + + expected = "Available requests for #{ provider } #{ service }_service:\n" + + requests.each do |klass| + expected << " #{ klass.api_version } #{ klass.endpoint_type } #{ klass.name.split('::').last.underscore }\n" end - - Aviator::Describer.describe_service(provider_name, service_name).must_equal display + + klass.describe_service(provider, service).must_equal expected end - - end # describe '::describe_service' - - + + end # describe '::describe_service' + + describe '::describe_request' do - - it 'describes a given request' do - provider_name = get_random_entry(get_provider_names) - service_name = get_random_entry(get_service_names(provider_name)) - request_class = get_random_entry(get_request_classes(provider_name, service_name)) - request_name = request_class.name.split('::').last.underscore - - expected = build_display(provider_name, service_name, request_name, request_class) - - output = Aviator::Describer.describe_request( - provider_name, service_name, request_class.api_version.to_s, - request_class.endpoint_type.to_s, request_name + + it 'shows the request name and sample code' do + provider = provider_names.first + service = service_names(provider).first + request_name = 'sample_request1' + + request_class = build_request(provider, service, request_name) + + expected = <<-EOF +Request: #{ request_name } + +Sample Code: + session.#{ service }_service.request(:#{ request_name }) +EOF + + output = klass.describe_request( + provider, + service, + request_class.api_version.to_s, + request_class.endpoint_type.to_s, + request_name.to_s ) - + output.must_equal expected end - - end # describe '::describe_request' - - + + + it "shows parameters when provided" do + provider = provider_names.first + service = service_names(provider).first + request_name = 'sample_request2' + + request_class = build_request(provider, service, request_name) do + param :theParam, required: true + param :another, required: false + end + + expected = <<-EOF +Request: #{ request_name } + +Parameters: + +----------+----------+ + | NAME | REQUIRED | + +----------+----------+ + | another | N | + | theParam | Y | + +----------+----------+ + +Sample Code: + session.#{ service }_service.request(:#{ request_name }) do |params| + params.another = value + params.theParam = value + end +EOF + + output = klass.describe_request( + provider, + service, + request_class.api_version.to_s, + request_class.endpoint_type.to_s, + request_name.to_s + ) + + output.must_equal expected + end + + + it "display aliases when available" do + provider = provider_names.first + service = service_names(provider).first + request_name = 'sample_request3' + + request_class = build_request(provider, service, request_name) do + param :theParam, required: true, alias: :the_param + param :anotherParam, required: false, alias: :another_param + end + + expected = <<-EOF +Request: #{ request_name } + +Parameters: + +--------------+----------+---------------+ + | NAME | REQUIRED | ALIAS | + +--------------+----------+---------------+ + | anotherParam | N | another_param | + | theParam | Y | the_param | + +--------------+----------+---------------+ + +Sample Code: + session.#{ service }_service.request(:#{ request_name }) do |params| + params.another_param = value + params.the_param = value + end +EOF + + output = klass.describe_request( + provider, + service, + request_class.api_version.to_s, + request_class.endpoint_type.to_s, + request_name.to_s + ) + + output.must_equal expected + end + + + it "display links when available" do + provider = provider_names.first + service = service_names(provider).first + request_name = 'sample_request4' + + request_class = build_request(provider, service, request_name) do + param :theParam, required: true, alias: :the_param + param :anotherParam, required: false, alias: :another_param + + link 'link1', 'http://www.link.com' + end + + expected = <<-EOF +Request: #{ request_name } + +Parameters: + +--------------+----------+---------------+ + | NAME | REQUIRED | ALIAS | + +--------------+----------+---------------+ + | anotherParam | N | another_param | + | theParam | Y | the_param | + +--------------+----------+---------------+ + +Sample Code: + session.#{ service }_service.request(:#{ request_name }) do |params| + params.another_param = value + params.the_param = value + end + +Links: + link1: + http://www.link.com +EOF + + output = klass.describe_request( + provider, + service, + request_class.api_version.to_s, + request_class.endpoint_type.to_s, + request_name.to_s + ) + + output.must_equal expected + end + + + end # describe '::describe_request' + + end # describe 'aviator/core/cli/describe' - + end # class Aviator::Test From 8ef54885e2cd703486630d02756d6ae11edf730d Mon Sep 17 00:00:00 2001 From: Mark Maglana Date: Tue, 1 Oct 2013 14:45:08 -0700 Subject: [PATCH 3/4] Use terminal-table gem for describer --- aviator.gemspec | 3 ++- lib/aviator/core/cli.rb | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/aviator.gemspec b/aviator.gemspec index bf7718d..0ad3146 100644 --- a/aviator.gemspec +++ b/aviator.gemspec @@ -21,7 +21,8 @@ Gem::Specification.new do |spec| spec.add_dependency 'faraday', '~> 0.8.0' spec.add_dependency 'activesupport', '>= 3.2.8' spec.add_dependency 'thor', '~> 0.18.1' - + spec.add_dependency 'terminal-table', '>= 1.4.5' + spec.add_development_dependency "bundler", "~> 1.3" spec.add_development_dependency "rake" spec.add_development_dependency 'rb-fsevent', '~> 0.9.0' diff --git a/lib/aviator/core/cli.rb b/lib/aviator/core/cli.rb index 184ced1..cd937d0 100644 --- a/lib/aviator/core/cli.rb +++ b/lib/aviator/core/cli.rb @@ -1 +1,2 @@ +require "terminal-table" require "aviator/core/cli/describer" From b64f7b89da5edcaa1e5c85aa2099269e20c7fad9 Mon Sep 17 00:00:00 2001 From: Mark Maglana Date: Tue, 1 Oct 2013 14:45:30 -0700 Subject: [PATCH 4/4] Update Describer according to new test specs --- lib/aviator/core/cli/describer.rb | 145 ++++++++++++++++++++---------- 1 file changed, 98 insertions(+), 47 deletions(-) diff --git a/lib/aviator/core/cli/describer.rb b/lib/aviator/core/cli/describer.rb index cc29a5e..6d28099 100644 --- a/lib/aviator/core/cli/describer.rb +++ b/lib/aviator/core/cli/describer.rb @@ -1,37 +1,25 @@ module Aviator - - module Describer + + class Describer def self.describe_aviator - provider_names = Pathname.new(__FILE__) - .join('..', '..', '..') - .children - .select{|c| c.directory? && c.basename.to_s != 'core' } - .map{|c| c.basename.to_s } - str = "Available providers:\n" provider_names.each do |provider_name| str << " #{ provider_name }\n" end - + str end def self.describe_provider(provider_name) - service_names = Pathname.new(__FILE__) - .join('..', '..', '..', provider_name) - .children - .select{|c| c.directory? } - .map{|c| c.basename.to_s } - str = "Available services for #{ provider_name }:\n" - service_names.each do |service_name| + service_names(provider_name).each do |service_name| str << " #{ service_name }\n" end - + str end @@ -40,56 +28,119 @@ module Aviator service = Aviator::Service.new provider: provider_name, service: service_name request_class = "Aviator::#{ provider_name.camelize }::#{ service_name.camelize }::"\ "#{ api_version.camelize }::#{ endpoint_type.camelize }::#{ request_name.camelize }".constantize - - str = "Request: #{ request_name }\n\n" - - str << "Parameters:\n" - params = request_class.optional_params.map{|p| [p, :optional]} + - request_class.required_params.map{|p| [p, :required]} - - params.sort{|a,b| a[0].to_s <=> b[0].to_s }.each do |param| - str << " (#{ param[1].to_s }) #{ param[0] }\n" + display = "Request: #{ request_name }\n" + + + # Build the parameters + params = request_class.optional_params.map{|p| [p, false]} + + request_class.required_params.map{|p| [p, true]} + + aliases = request_class.param_aliases + + if params.length > 0 + display << "\n" + + headings = ['NAME', 'REQUIRED'] + + headings << 'ALIAS' if aliases.length > 0 + + rows = [] + params.sort{|a,b| a[0].to_s <=> b[0].to_s }.each do |param| + row = [ param[0], param[1] ? 'Y' : 'N' ] + + if aliases.length > 0 + row << (aliases.find{|a,p| p == param[0] } || [''])[0] + end + + rows << row + end + + widths = [ + rows.map{|row| row[0].length }.max, + rows.map{|row| row[1].length }.max + ] + + widths << rows.map{|row| row[2].length }.max if aliases.length > 0 + + table = Terminal::Table.new(headings: headings, rows: rows) + + table.align_column(1, :center) + + display << "Parameters:\n" + display << " " + table.to_s.split("\n").join("\n ") + display << "\n" end - - str << "\nSample Code:\n" - str << " session.#{ service_name }_service.request(:#{ request_name }, endpoint_type: '#{ request_class.endpoint_type }')" - if params - str << " do |params|\n" + + # Build the sample code + display << "\nSample Code:\n" + + display << " session.#{ service_name }_service.request(:#{ request_name })" + + if params && params.length > 0 + display << " do |params|\n" params.each do |pair| - str << " params['#{ pair[0] }'] = value\n" + display << " params.#{ (aliases.find{|a,p| p == pair[0] } || pair)[0] } = value\n" end - str << " end\n" + display << " end" end - - if request_class.links - str << "\nLinks:\n" - + + display << "\n" + + + # Build the links + if request_class.links && request_class.links.length > 0 + display << "\nLinks:\n" + request_class.links.each do |link| - str << " #{ link[:rel] }:\n" - str << " #{ link[:href] }\n" + display << " #{ link[:rel] }:\n" + display << " #{ link[:href] }\n" end end - - str + + display end def self.describe_service(provider_name, service_name) - service = Aviator::Service.new(provider: provider_name, service: service_name) - klasses = service.request_classes - str = "Available requests for #{ provider_name } #{ service_name }_service:\n" - klasses.each do |klass| + request_classes(provider_name, service_name).each do |klass| str << " #{ klass.api_version } #{ klass.endpoint_type } #{ klass.name.split('::').last.underscore }\n" end - + str end + class <