diff --git a/CHANGELOG.md b/CHANGELOG.md
index 9498cad..cd97a37 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 0.1.7
+
+- Make camelizing of model properties configurable. #55
+
## 0.1.6
- Document notes DSL
diff --git a/README.md b/README.md
index ec65a17..a218035 100644
--- a/README.md
+++ b/README.md
@@ -102,6 +102,12 @@ The following table shows all the current configuration options and their defaul
:pretty |
+
+camelize_model_properties |
+Camelizes property names of models. For example, a property name called first_name would be converted to firstName. |
+true |
+
+
@@ -174,19 +180,19 @@ end
### DRYing up common documentation
Suppose you have a header or a parameter that must be present on several controllers and methods. Instead of duplicating it on all the controllers you can do this on your API base controller:
-
+
```ruby
class Api::BaseController < ActionController::Base
class << self
Swagger::Docs::Generator::set_real_methods
-
+
def inherited(subclass)
super
subclass.class_eval do
setup_basic_api_documentation
end
end
-
+
private
def setup_basic_api_documentation
[:index, :show, :create, :update, :delete].each do |api_action|
@@ -198,7 +204,7 @@ class Api::BaseController < ActionController::Base
end
end
```
-
+
And then use it as a superclass to all you API controllers. All the subclassed controllers will have the same documentation applied to them.
### DSL Methods
@@ -608,7 +614,7 @@ users.json output:
## Thanks to our contributors
-Thanks to jdar, fotinakis, stevschmid, ldnunes and all of our contributors for making swagger-docs even better.
+Thanks to jdar, fotinakis, stevschmid, ldnunes, aaronrenner and all of our contributors for making swagger-docs even better.
## Contributing
diff --git a/lib/swagger/docs.rb b/lib/swagger/docs.rb
index 92129d2..82dca82 100644
--- a/lib/swagger/docs.rb
+++ b/lib/swagger/docs.rb
@@ -1,5 +1,7 @@
require "swagger/docs/config"
require "swagger/docs/dsl"
+require "swagger/docs/api_declaration_file_metadata"
+require "swagger/docs/api_declaration_file"
require "swagger/docs/generator"
require "swagger/docs/impotent_methods"
require "swagger/docs/methods"
diff --git a/lib/swagger/docs/api_declaration_file.rb b/lib/swagger/docs/api_declaration_file.rb
new file mode 100644
index 0000000..e161a70
--- /dev/null
+++ b/lib/swagger/docs/api_declaration_file.rb
@@ -0,0 +1,120 @@
+module Swagger
+ module Docs
+ class ApiDeclarationFile
+ attr_reader :metadata, :apis
+
+ def initialize(metadata, apis, models)
+ @metadata = metadata
+ @apis = camelize_keys_deep apis
+ @models = models
+ end
+
+ def generate_resource
+ resource = build_resource_root_hash
+ # Add the already-normalized models to the resource.
+ resource = resource.merge({:models => models}) if models.present?
+ resource
+ end
+
+ def base_path
+ metadata.base_path
+ end
+
+ def path
+ metadata.path
+ end
+
+ def swagger_version
+ metadata.swagger_version
+ end
+
+ def api_version
+ metadata.api_version
+ end
+
+ def controller_base_path
+ metadata.controller_base_path
+ end
+
+ def camelize_model_properties
+ metadata.camelize_model_properties
+ end
+
+ def resource_path
+ demod
+ end
+
+ def resource_file_path
+ trim_leading_slash(debased_path.to_s.underscore)
+ end
+
+ def models
+ normalize_model_properties @models
+ end
+
+ private
+
+ def build_resource_root_hash
+ {
+ "apiVersion" => api_version,
+ "swaggerVersion" => swagger_version,
+ "basePath" => base_path,
+ "resourcePath" => resource_path,
+ "apis" => apis,
+ "resourceFilePath" => resource_file_path
+ }
+ end
+
+ def normalize_model_properties(models)
+ Hash[
+ models.map do |k, v|
+ if camelize_model_properties
+ [k.to_s, camelize_keys_deep(v)]
+ else
+ [k.to_s, stringify_keys_deep(v)]
+ end
+ end]
+ end
+
+ def demod
+ "#{debased_path.to_s.camelize}".demodulize.camelize.underscore
+ end
+
+ def debased_path
+ path.gsub("#{controller_base_path}", "")
+ end
+
+ def trim_leading_slash(str)
+ return str if !str
+ str.gsub(/\A\/+/, '')
+ end
+
+ def camelize_keys_deep(obj)
+ process_keys_deep(obj){|key| key.to_s.camelize(:lower)}
+ end
+
+ def stringify_keys_deep(obj)
+ process_keys_deep(obj){|key| key.to_s}
+ end
+
+ def process_keys_deep(obj, &block)
+ if obj.is_a? Hash
+ Hash[
+ obj.map do |k, v|
+ new_key = block.call(k)
+ new_value = process_keys_deep v, &block
+ [new_key, new_value]
+ end
+ ]
+ elsif obj.is_a? Array
+ new_value = obj.collect do |a|
+ process_keys_deep a, &block
+ end
+ else
+ obj
+ end
+ end
+
+ end
+ end
+end
diff --git a/lib/swagger/docs/api_declaration_file_metadata.rb b/lib/swagger/docs/api_declaration_file_metadata.rb
new file mode 100644
index 0000000..ecf6730
--- /dev/null
+++ b/lib/swagger/docs/api_declaration_file_metadata.rb
@@ -0,0 +1,18 @@
+module Swagger
+ module Docs
+ class ApiDeclarationFileMetadata
+ DEFAULT_SWAGGER_VERSION = "1.2"
+
+ attr_reader :api_version, :path, :base_path, :controller_base_path, :swagger_version, :camelize_model_properties
+
+ def initialize(api_version, path, base_path, controller_base_path, options={})
+ @api_version = api_version
+ @path = path
+ @base_path = base_path
+ @controller_base_path = controller_base_path
+ @swagger_version = options.fetch(:swagger_version, DEFAULT_SWAGGER_VERSION)
+ @camelize_model_properties = options.fetch(:camelize_model_properties, true)
+ end
+ end
+ end
+end
diff --git a/lib/swagger/docs/generator.rb b/lib/swagger/docs/generator.rb
index 50b47c5..844f467 100644
--- a/lib/swagger/docs/generator.rb
+++ b/lib/swagger/docs/generator.rb
@@ -54,7 +54,7 @@ def generate_docs(apis=nil)
end
def generate_doc(api_version, settings, config)
- root = { :api_version => api_version, :swagger_version => "1.2", :base_path => settings[:base_path] + "/", :apis => []}
+ root = { "apiVersion" => api_version, "swaggerVersion" => "1.2", "basePath" => settings[:base_path] + "/", :apis => []}
results = {:processed => [], :skipped => []}
resources = []
@@ -71,8 +71,7 @@ def generate_doc(api_version, settings, config)
root[:apis] << resource_api
end
end
- root[:resources] = resources
- camelize_keys_deep!(root)
+ root['resources'] = resources
results[:root] = root
results
end
@@ -134,15 +133,12 @@ def process_path(path, root, config, settings)
end
def generate_resource(path, apis, models, settings, root, config)
- debased_path = get_debased_path(path, settings[:controller_base_path])
- demod = "#{debased_path.to_s.camelize}".demodulize.camelize.underscore
- resource_path = trim_leading_slash(debased_path.to_s.underscore)
- resource = root.merge({:resource_path => "#{demod}", :apis => apis})
- camelize_keys_deep!(resource)
- # Add the already-normalized models to the resource.
- resource = resource.merge({:models => models}) if models.present?
- resource[:resource_file_path] = resource_path
- resource
+ metadata = ApiDeclarationFileMetadata.new(root["apiVersion"], path, root["basePath"],
+ settings[:controller_base_path],
+ camelize_model_properties: config.fetch(:camelize_model_properties, true),
+ swagger_version: root["swaggerVersion"])
+ declaration = ApiDeclarationFile.new(metadata, apis, models)
+ declaration.generate_resource
end
def get_route_path_apis(path, route, klass, settings, config)
diff --git a/lib/swagger/docs/version.rb b/lib/swagger/docs/version.rb
index 13d9e88..a64e304 100644
--- a/lib/swagger/docs/version.rb
+++ b/lib/swagger/docs/version.rb
@@ -1,5 +1,5 @@
module Swagger
module Docs
- VERSION = "0.1.6"
+ VERSION = "0.1.7"
end
end
diff --git a/spec/lib/swagger/docs/api_declaration_file_metadata_spec.rb b/spec/lib/swagger/docs/api_declaration_file_metadata_spec.rb
new file mode 100644
index 0000000..74f2807
--- /dev/null
+++ b/spec/lib/swagger/docs/api_declaration_file_metadata_spec.rb
@@ -0,0 +1,55 @@
+require 'spec_helper'
+
+describe Swagger::Docs::ApiDeclarationFileMetadata do
+
+ describe "#initialize" do
+ it "sets the api_version property" do
+ metadata = described_class.new("1.0", "path", "basePath", "controllerBasePath")
+
+ expect(metadata.api_version).to eq("1.0")
+ end
+
+ it "sets the path property" do
+ metadata = described_class.new("1.0", "path", "basePath", "controllerBasePath")
+
+ expect(metadata.path).to eq("path")
+ end
+
+ it "sets the base_path property" do
+ metadata = described_class.new("1.0", "path", "basePath", "controllerBasePath")
+
+ expect(metadata.base_path).to eq("basePath")
+ end
+
+ it "sets the controller_base_path property" do
+ metadata = described_class.new("1.0", "path", "basePath", "controllerBasePath")
+
+ expect(metadata.controller_base_path).to eq("controllerBasePath")
+ end
+
+ it "defaults the swagger_version property to DEFAULT_SWAGGER_VERSION" do
+ metadata = described_class.new("1.0", "path", "basePath", "controllerBasePath")
+
+ expect(metadata.swagger_version).to eq(described_class::DEFAULT_SWAGGER_VERSION)
+ end
+
+ it "allows the swagger_version property to be_overriden" do
+ metadata = described_class.new("1.0", "path", "basePath", "controllerBasePath", swagger_version: "2.0")
+
+ expect(metadata.swagger_version).to eq("2.0")
+ end
+
+
+ it "defaults the camelize_model_properties property to true" do
+ metadata = described_class.new("1.0", "path", "basePath", "controllerBasePath")
+
+ expect(metadata.camelize_model_properties).to eq(true)
+ end
+
+ it "allows the camelize_model_properties property to be overidden" do
+ metadata = described_class.new("1.0", "path", "basePath", "controllerBasePath", camelize_model_properties: false)
+
+ expect(metadata.camelize_model_properties).to eq(false)
+ end
+ end
+end
diff --git a/spec/lib/swagger/docs/api_declaration_file_spec.rb b/spec/lib/swagger/docs/api_declaration_file_spec.rb
new file mode 100644
index 0000000..b2b2574
--- /dev/null
+++ b/spec/lib/swagger/docs/api_declaration_file_spec.rb
@@ -0,0 +1,198 @@
+require "spec_helper"
+
+describe Swagger::Docs::ApiDeclarationFile do
+ let(:apis) do
+ [
+ {
+ :path=>"sample/{id}",
+ :operations=>[
+ {
+ :summary=>"Updates an existing User",
+ :parameters=>[
+ {:param_type=>:path, :name=>:id, :type=>:integer, :description=>"User Id", :required=>true},
+ {:param_type=>:form, :name=>:first_name, :type=>:string, :description=>"First name", :required=>false},
+ {:param_type=>:form, :name=>:last_name, :type=>:string, :description=>"Last name", :required=>false},
+ {:param_type=>:form, :name=>:email, :type=>:string, :description=>"Email address", :required=>false},
+ {:param_type=>:form, :name=>:tag, :type=>:Tag, :description=>"Tag object", :required=>true}
+ ],
+ :response_messages=>[
+ {:code=>401, :message=>"Unauthorized"},
+ {:code=>404, :message=>"Not Found"},
+ {:code=>406, :message=>"Not Acceptable"}
+ ],
+ :notes=>"Only the given fields are updated.",
+ :method=>:put,
+ :nickname=>"Api::V1::Sample#update"
+ }
+ ]
+ }
+ ]
+ end
+
+ let(:models) do
+ {
+ :Tag=>
+ {
+ :id=>:Tag,
+ :required=>[:id],
+ :properties=>
+ {
+ :id=>{:type=>:integer, :description=>"User Id"},
+ :first_name=>{:type=>:string, :description=>"First Name"},
+ :last_name=>{:type=>:string, :description=>"Last Name"}
+ },
+ :description=>"A Tag object."
+ }
+ }
+ end
+
+ let(:metadata) do
+ Swagger::Docs::ApiDeclarationFileMetadata.new("1.0", "api/v1/sample", "http://api.no.where/", "")
+ end
+
+ describe "#generate_resource" do
+
+ it "generates the appropriate response" do
+ declaration = described_class.new(metadata, apis, models)
+
+ expected_response = {
+ "apiVersion"=> declaration.api_version,
+ "swaggerVersion"=> declaration.swagger_version,
+ "basePath"=> declaration.base_path,
+ "apis"=> declaration.apis,
+ "resourcePath"=> declaration.resource_path,
+ :models=> declaration.models,
+ "resourceFilePath" => declaration.resource_file_path
+ }
+ expect(declaration.generate_resource).to eq(expected_response)
+ end
+ end
+
+ describe "#base_path" do
+ it "returns metadata.base_path" do
+ metadata = double("metadata", base_path: "/hello")
+ declaration = described_class.new(metadata, apis, models)
+ expect(declaration.base_path).to eq(metadata.base_path)
+ end
+ end
+
+ describe "#path" do
+ it "returns metadata.path" do
+ metadata = double("metadata", path: "/hello")
+ declaration = described_class.new(metadata, apis, models)
+ expect(declaration.path).to eq(metadata.path)
+ end
+ end
+
+ describe "#controller_base_path" do
+ it "returns metadata.controller_base_path" do
+ metadata = double("metadata", controller_base_path: "/hello")
+ declaration = described_class.new(metadata, apis, models)
+ expect(declaration.controller_base_path).to eq(metadata.controller_base_path)
+ end
+ end
+
+ describe "#swagger_version" do
+ it "returns metadata.swagger_version" do
+ metadata = double("metadata", swagger_version: "1.2")
+ declaration = described_class.new(metadata, apis, models)
+ expect(declaration.swagger_version).to eq(metadata.swagger_version)
+ end
+ end
+
+ describe "#api_version" do
+ it "returns metadata.api_version" do
+ metadata = double("metadata", api_version: "1.0")
+ declaration = described_class.new(metadata, apis, models)
+ expect(declaration.api_version).to eq(metadata.api_version)
+ end
+ end
+
+ describe "#camelize_model_properties" do
+ it "returns metadata.camelize_model_properties" do
+ metadata = double("metadata", camelize_model_properties: false)
+ declaration = described_class.new(metadata, apis, models)
+ expect(declaration.camelize_model_properties).to eq(metadata.camelize_model_properties)
+ end
+ end
+
+ describe "#models" do
+ context "with camelize_model_properties set to true" do
+ it "returns a models hash that's ready for output" do
+ declaration = described_class.new(metadata, apis, models)
+ allow(declaration).to receive(:camelize_model_properties).and_return(true)
+ expected_models_hash = {
+ "Tag" =>
+ {
+ "id" => :Tag,
+ "required" =>[:id],
+ "properties" =>
+ {
+ "id" =>{"type"=>:integer, "description"=>"User Id"},
+ "firstName"=>{"type"=>:string, "description"=>"First Name"},
+ "lastName"=>{"type"=>:string, "description"=>"Last Name"},
+ },
+ "description"=>"A Tag object."
+ }
+ }
+
+ expect(declaration.models).to eq(expected_models_hash)
+ end
+ end
+
+ context "with camelize_model_properties set to false" do
+ it "returns a models hash that's ready for output" do
+ declaration = described_class.new(metadata, apis, models)
+ allow(declaration).to receive(:camelize_model_properties).and_return(false)
+ expected_models_hash = {
+ "Tag" =>
+ {
+ "id" => :Tag,
+ "required" =>[:id],
+ "properties" =>
+ {
+ "id" =>{"type"=>:integer, "description"=>"User Id"},
+ "first_name"=>{"type"=>:string, "description"=>"First Name"},
+ "last_name"=>{"type"=>:string, "description"=>"Last Name"},
+ },
+ "description"=>"A Tag object."
+ }
+ }
+
+ expect(declaration.models).to eq(expected_models_hash)
+ end
+ end
+ end
+
+ describe "#apis" do
+ it "returns a api hash that's ready for output" do
+ declaration = described_class.new(metadata, apis, models)
+ expected_apis_array = [
+ {
+ "path"=>"sample/{id}",
+ "operations"=>[
+ {
+ "summary"=>"Updates an existing User",
+ "parameters"=>[
+ {"paramType"=>:path, "name"=>:id, "type"=>:integer, "description"=>"User Id", "required"=>true},
+ {"paramType"=>:form, "name"=>:first_name, "type"=>:string, "description"=>"First name", "required"=>false},
+ {"paramType"=>:form, "name"=>:last_name, "type"=>:string, "description"=>"Last name", "required"=>false},
+ {"paramType"=>:form, "name"=>:email, "type"=>:string, "description"=>"Email address", "required"=>false},
+ {"paramType"=>:form, "name"=>:tag, "type"=>:Tag, "description"=>"Tag object", "required"=>true}
+ ],
+ "responseMessages"=>[
+ {"code"=>401, "message"=>"Unauthorized"},
+ {"code"=>404, "message"=>"Not Found"},
+ {"code"=>406, "message"=>"Not Acceptable"}
+ ],
+ "notes"=>"Only the given fields are updated.",
+ "method"=>:put,
+ "nickname"=>"Api::V1::Sample#update"
+ }
+ ]
+ }
+ ]
+ expect(declaration.apis).to eq(expected_apis_array)
+ end
+ end
+end
diff --git a/spec/lib/swagger/docs/generator_spec.rb b/spec/lib/swagger/docs/generator_spec.rb
index c660cfd..16d7eb3 100644
--- a/spec/lib/swagger/docs/generator_spec.rb
+++ b/spec/lib/swagger/docs/generator_spec.rb
@@ -321,7 +321,7 @@
}
}
}
- expect(models['tag']).to eq expected_model
+ expect(models['Tag']).to eq expected_model
end
end
end