diff --git a/features/api_blueprint_documentation.feature b/features/api_blueprint_documentation.feature index 3aa7d119..8475775f 100644 --- a/features/api_blueprint_documentation.feature +++ b/features/api_blueprint_documentation.feature @@ -110,7 +110,9 @@ Feature: Generate API Blueprint documentation from test examples route '/orders/{id}', "Single Order" do parameter :id, 'Order id', required: true, type: 'string', :example => '1' - attribute :name, 'The order name', required: true, type: 'string', :example => '1' + attribute :name, 'The order name', required: true, :example => 'a name' + attribute :amount, required: false + attribute :description, 'The order description', type: 'string', required: false, example: "a description" get 'Returns a single order' do explanation "This is used to return orders." @@ -354,10 +356,12 @@ Feature: Generate API Blueprint documentation from test examples ## Single Order [/orders/{id}] + Parameters - + id: (required, string) - Order id + + id: 1 (required, string) - Order id + Attributes (object) - + name: (required, string) - The order name + + name: a name (required) - The order name + + amount + + description: a description (string) - The order description ### Deletes a specific order [DELETE] diff --git a/lib/rspec_api_documentation/views/api_blueprint_index.rb b/lib/rspec_api_documentation/views/api_blueprint_index.rb index 70ebf989..b6f264f2 100644 --- a/lib/rspec_api_documentation/views/api_blueprint_index.rb +++ b/lib/rspec_api_documentation/views/api_blueprint_index.rb @@ -9,8 +9,8 @@ def initialize(index, configuration) def sections super.map do |section| routes = section[:examples].group_by(&:route_uri).map do |route_uri, examples| - attrs = examples.map { |example| example.metadata[:attributes] }.flatten.compact.uniq { |attr| attr[:name] } - params = examples.map { |example| example.metadata[:parameters] }.flatten.compact.uniq { |param| param[:name] } + attrs = fields(:attributes, examples) + params = fields(:parameters, examples) methods = examples.group_by(&:http_method).map do |http_method, examples| { @@ -42,6 +42,49 @@ def examples ApiBlueprintExample.new(example, @configuration) end end + + private + + # APIB has both `parameters` and `attributes`. This generates a hash + # with all of its properties, like name, description, required. + # { + # required: true, + # example: "1", + # type: "string", + # name: "id", + # description: "The id", + # properties_description: "required, string" + # } + def fields(property_name, examples) + examples + .map { |example| example.metadata[property_name] } + .flatten + .compact + .uniq { |property| property[:name] } + .map do |property| + properties = [] + properties << "required" if property[:required] + properties << property[:type] if property[:type] + if properties.count > 0 + property[:properties_description] = properties.join(", ") + else + property[:properties_description] = nil + end + + property[:description] = nil if description_blank?(property) + property + end + end + + # When no `description` was specified for a parameter, the DSL class + # is making `description = "#{scope} #{name}"`, which is bad because it + # assumes that all formats want this behavior. To avoid changing there + # and breaking everything, I do my own check here and if description + # equals the name, I assume it is blank. + def description_blank?(property) + !property[:description] || + property[:description].to_s.strip == property[:name].to_s.strip + end end end end diff --git a/spec/views/api_blueprint_index_spec.rb b/spec/views/api_blueprint_index_spec.rb index 43596897..6232f6c7 100644 --- a/spec/views/api_blueprint_index_spec.rb +++ b/spec/views/api_blueprint_index_spec.rb @@ -37,7 +37,7 @@ let(:rspec_example_posts) do post_group.route "/posts", "Posts Collection" do - attribute :description, "Order description", required: false + attribute :description, required: false get("/posts") do example_request 'Get all posts' do @@ -105,12 +105,14 @@ type: "string", name: "id", description: "The id", + properties_description: "required, string" }] expect(post_route[:has_attributes?]).to eq true expect(post_route[:attributes]).to eq [{ required: true, name: "name", description: "Order name 1", + properties_description: "required" }] posts_examples = posts_route[:http_methods].map { |http_method| http_method[:examples] }.flatten @@ -123,7 +125,8 @@ expect(posts_route[:attributes]).to eq [{ required: false, name: "description", - description: "Order description", + description: nil, + properties_description: nil }] end end diff --git a/templates/rspec_api_documentation/api_blueprint_index.mustache b/templates/rspec_api_documentation/api_blueprint_index.mustache index d5d33e8f..18f95212 100644 --- a/templates/rspec_api_documentation/api_blueprint_index.mustache +++ b/templates/rspec_api_documentation/api_blueprint_index.mustache @@ -25,14 +25,14 @@ explanation: {{ explanation }} + Parameters {{# parameters }} - + {{ name }}: ({{# required }}required, {{/ required }}{{ type }}) - {{ description }} + + {{ name }}{{# example }}: {{ example }}{{/ example }}{{# properties_description }} ({{ properties_description }}){{/ properties_description }}{{# description }} - {{ description }}{{/ description }} {{/ parameters }} {{/ has_parameters? }} {{# has_attributes? }} + Attributes (object) {{# attributes }} - + {{ name }}: ({{# required }}required, {{/ required }}{{ type }}) - {{ description }} + + {{ name }}{{# example }}: {{ example }}{{/ example }}{{# properties_description }} ({{ properties_description }}){{/ properties_description }}{{# description }} - {{ description }}{{/ description }} {{/ attributes }} {{/ has_attributes? }} {{# http_methods }}