fictium 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.github/pull_request_template.md +15 -0
- data/.gitignore +22 -0
- data/.rspec +3 -0
- data/.rubocop.yml +32 -0
- data/.ruby-version +1 -0
- data/.travis.yml +13 -0
- data/CHANGELOG.md +28 -0
- data/CODE_OF_CONDUCT.md +74 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +216 -0
- data/LICENSE +201 -0
- data/LICENSE.txt +21 -0
- data/README.md +108 -0
- data/Rakefile +10 -0
- data/app/.keep +0 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/fictium.gemspec +57 -0
- data/lib/fictium/configurations/configuration.rb +87 -0
- data/lib/fictium/configurations/info.rb +12 -0
- data/lib/fictium/engine.rb +6 -0
- data/lib/fictium/evaluators/parameter_evaluator.rb +57 -0
- data/lib/fictium/evaluators/schema_evaluator.rb +7 -0
- data/lib/fictium/exporters/open_api/schemas/3.0.0.json +1654 -0
- data/lib/fictium/exporters/open_api/v3_exporter/content_formatter.rb +20 -0
- data/lib/fictium/exporters/open_api/v3_exporter/example_formatter.rb +46 -0
- data/lib/fictium/exporters/open_api/v3_exporter/param_formatter.rb +45 -0
- data/lib/fictium/exporters/open_api/v3_exporter/path_formatter.rb +60 -0
- data/lib/fictium/exporters/open_api/v3_exporter/path_generator.rb +37 -0
- data/lib/fictium/exporters/open_api/v3_exporter.rb +79 -0
- data/lib/fictium/loader.rb +15 -0
- data/lib/fictium/poros/action.rb +43 -0
- data/lib/fictium/poros/document.rb +19 -0
- data/lib/fictium/poros/example.rb +15 -0
- data/lib/fictium/poros/model.rb +4 -0
- data/lib/fictium/poros/resource.rb +16 -0
- data/lib/fictium/railtie.rb +4 -0
- data/lib/fictium/rspec/actions.rb +40 -0
- data/lib/fictium/rspec/autocomplete/action.rb +52 -0
- data/lib/fictium/rspec/autocomplete/example.rb +45 -0
- data/lib/fictium/rspec/autocomplete/params.rb +79 -0
- data/lib/fictium/rspec/autocomplete/resource.rb +20 -0
- data/lib/fictium/rspec/examples.rb +48 -0
- data/lib/fictium/rspec/proxies/action.rb +11 -0
- data/lib/fictium/rspec/proxies/base.rb +25 -0
- data/lib/fictium/rspec/proxies/example.rb +15 -0
- data/lib/fictium/rspec/proxy_handler.rb +11 -0
- data/lib/fictium/rspec/resources.rb +41 -0
- data/lib/fictium/rspec.rb +39 -0
- data/lib/fictium/version.rb +5 -0
- data/lib/fictium.rb +29 -0
- data/tasks/.keep +0 -0
- data/tasks/travis/analyze.rb +12 -0
- metadata +321 -0
@@ -0,0 +1,20 @@
|
|
1
|
+
module Fictium
|
2
|
+
module OpenApi
|
3
|
+
class V3Exporter
|
4
|
+
class ContentFormatter
|
5
|
+
def format(http_object, default = nil)
|
6
|
+
type = (http_object.presence && http_object[:content_type].presence) || default
|
7
|
+
return if type.blank?
|
8
|
+
|
9
|
+
{}.tap do |content|
|
10
|
+
media_type = {
|
11
|
+
example: http_object[:body]
|
12
|
+
}
|
13
|
+
media_type[:schema] = http_object[:schema] if http_object[:schema].present?
|
14
|
+
content[type.to_sym] = media_type
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
module Fictium
|
2
|
+
module OpenApi
|
3
|
+
class V3Exporter
|
4
|
+
class ExampleFormatter
|
5
|
+
def format_default(operation, responses, default_example)
|
6
|
+
responses[:default] = format(default_example)
|
7
|
+
return if default_example.request[:content_type].blank?
|
8
|
+
|
9
|
+
operation[:requestBody] = {
|
10
|
+
content: content_formatter.format(default_example.request)
|
11
|
+
}
|
12
|
+
operation[:requestBody][:required] = true if default_example.request[:required]
|
13
|
+
end
|
14
|
+
|
15
|
+
def format(example)
|
16
|
+
{ description: example.summary }.tap do |format|
|
17
|
+
content = content_formatter.format(example.response, default_response_content_type)
|
18
|
+
format[:content] = content if content.present?
|
19
|
+
headers = extract_headers(example)
|
20
|
+
format[:headers] = headers if headers.present?
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def default_response_content_type
|
25
|
+
Fictium.configuration.default_response_content_type
|
26
|
+
end
|
27
|
+
|
28
|
+
def extract_headers(example)
|
29
|
+
{}.tap do |headers|
|
30
|
+
example.headers.each do |name, value|
|
31
|
+
headers[name] = header_formatter.format(name, :header, value)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def content_formatter
|
37
|
+
@content_formatter ||= ContentFormatter.new
|
38
|
+
end
|
39
|
+
|
40
|
+
def header_formatter
|
41
|
+
@header_formatter ||= ParamFormatter.new(ignore_name: true, ignore_in: true)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
module Fictium
|
2
|
+
module OpenApi
|
3
|
+
class V3Exporter
|
4
|
+
class ParamFormatter
|
5
|
+
def initialize(ignore_name: false, ignore_in: false)
|
6
|
+
@ignore_name = ignore_name
|
7
|
+
@ignore_in = ignore_in
|
8
|
+
end
|
9
|
+
|
10
|
+
def format(name, section, hash)
|
11
|
+
param = (hash || {})
|
12
|
+
description = param.slice(:description, :required, :deprecated, :schema)
|
13
|
+
description[:allowEmptyValue] = param[:allow_empty] if param[:allow_empty].present?
|
14
|
+
add_required_fields(description)
|
15
|
+
add_optional_fields(name, section, description)
|
16
|
+
description
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def ignore_in?
|
22
|
+
@ignore_in
|
23
|
+
end
|
24
|
+
|
25
|
+
def ignore_name?
|
26
|
+
@ignore_name
|
27
|
+
end
|
28
|
+
|
29
|
+
def add_required_fields(description)
|
30
|
+
description[:description] ||= ''
|
31
|
+
|
32
|
+
return if description[:schema] || description[:content]
|
33
|
+
|
34
|
+
description[:schema] = {}
|
35
|
+
end
|
36
|
+
|
37
|
+
def add_optional_fields(name, section, description)
|
38
|
+
description[:name] = name unless ignore_name?
|
39
|
+
description[:in] = section unless ignore_in?
|
40
|
+
description[:required] = true if section.to_s == 'path'
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
module Fictium
|
2
|
+
module OpenApi
|
3
|
+
class V3Exporter
|
4
|
+
class PathFormatter
|
5
|
+
def add_path(paths, action)
|
6
|
+
path_object = paths[action.full_path] || default_path_object
|
7
|
+
path_object[action.method.to_sym] = create_operation(action)
|
8
|
+
paths[action.full_path] = path_object
|
9
|
+
end
|
10
|
+
|
11
|
+
private
|
12
|
+
|
13
|
+
def default_path_object
|
14
|
+
{ description: '' }
|
15
|
+
end
|
16
|
+
|
17
|
+
def create_operation(action)
|
18
|
+
{}.tap do |operation|
|
19
|
+
operation[:tags] = action.combined_tags
|
20
|
+
operation[:description] = action.summary
|
21
|
+
operation[:parameters] = format_parameters(action)
|
22
|
+
operation[:responses] = format_responses(operation, action)
|
23
|
+
operation[:deprecated] = action.deprecated?
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def format_parameters(action)
|
28
|
+
[].tap do |result|
|
29
|
+
action.params.each do |section, values|
|
30
|
+
values.each do |name, data|
|
31
|
+
result << param_formatter.format(name, section, data)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def format_responses(operation, action)
|
38
|
+
{}.tap do |responses|
|
39
|
+
default_example = action.default_example
|
40
|
+
break if default_example.blank?
|
41
|
+
|
42
|
+
example_formatter.format_default(operation, responses, default_example)
|
43
|
+
other_examples = action.examples.reject { |example| example == default_example }
|
44
|
+
other_examples.each do |example|
|
45
|
+
responses[example.response[:status]] = example_formatter.format(example)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def example_formatter
|
51
|
+
@example_formatter ||= ExampleFormatter.new
|
52
|
+
end
|
53
|
+
|
54
|
+
def param_formatter
|
55
|
+
@param_formatter ||= ParamFormatter.new
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module Fictium
|
2
|
+
module OpenApi
|
3
|
+
class V3Exporter
|
4
|
+
class PathGenerator
|
5
|
+
attr_reader :document
|
6
|
+
|
7
|
+
def initialize(document)
|
8
|
+
@document = document
|
9
|
+
end
|
10
|
+
|
11
|
+
def generate
|
12
|
+
{}.tap do |paths|
|
13
|
+
document.resources.each do |resource|
|
14
|
+
generate_from_resource(paths, resource)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def generate_from_resource(paths, resource)
|
22
|
+
resource.actions.each do |action|
|
23
|
+
generate_from_action(paths, action)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def generate_from_action(paths, action)
|
28
|
+
path_formatter.add_path(paths, action)
|
29
|
+
end
|
30
|
+
|
31
|
+
def path_formatter
|
32
|
+
@path_formatter ||= PathFormatter.new
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
require_relative 'v3_exporter/content_formatter'
|
2
|
+
require_relative 'v3_exporter/example_formatter'
|
3
|
+
require_relative 'v3_exporter/param_formatter'
|
4
|
+
|
5
|
+
require_relative 'v3_exporter/path_formatter'
|
6
|
+
require_relative 'v3_exporter/path_generator'
|
7
|
+
|
8
|
+
module Fictium
|
9
|
+
module OpenApi
|
10
|
+
class V3Exporter
|
11
|
+
DEFAULT_PROPERTIES = {
|
12
|
+
openapi: '3.0.0'
|
13
|
+
}.freeze
|
14
|
+
FIXTURE_TYPES = %w[servers security tags].freeze
|
15
|
+
INFO_OPTIONS = %w[title description terms_of_service contract license version].freeze
|
16
|
+
|
17
|
+
def export(document)
|
18
|
+
result = DEFAULT_PROPERTIES
|
19
|
+
.merge(create_fixtures)
|
20
|
+
.merge(info: create_info, paths: create_paths(document))
|
21
|
+
validate!(result)
|
22
|
+
FileUtils.mkdir_p(File.dirname(export_file))
|
23
|
+
File.write(export_file, pretty_print? ? JSON.pretty_generate(result) : result.to_json)
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def export_file
|
29
|
+
@export_file ||=
|
30
|
+
File.join(Fictium.configuration.export_path, 'open_api', '3.0.0', 'swagger.json')
|
31
|
+
end
|
32
|
+
|
33
|
+
def create_fixtures
|
34
|
+
{}.tap do |fixtures|
|
35
|
+
FIXTURE_TYPES.each do |name|
|
36
|
+
result = load_fixtures(name)
|
37
|
+
fixtures[name.camelize(:lower)] = result if result.present?
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def create_info
|
43
|
+
{}.tap do |info|
|
44
|
+
INFO_OPTIONS.each do |option|
|
45
|
+
value = Fictium.configuration.info.public_send(option)
|
46
|
+
info[option.camelize(:lower)] = value if value.present?
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def create_paths(document)
|
52
|
+
V3Exporter::PathGenerator.new(document).generate
|
53
|
+
end
|
54
|
+
|
55
|
+
def load_fixtures(name)
|
56
|
+
fixture_file = File.join(fixture_path, "#{name}.json")
|
57
|
+
return unless File.exist?(fixture_file)
|
58
|
+
|
59
|
+
JSON.parse(File.read(fixture_file))
|
60
|
+
end
|
61
|
+
|
62
|
+
def fixture_path
|
63
|
+
Fictium.configuration.fixture_path
|
64
|
+
end
|
65
|
+
|
66
|
+
def validate!(result)
|
67
|
+
JSON::Validator.validate!(schema, result)
|
68
|
+
end
|
69
|
+
|
70
|
+
def schema
|
71
|
+
@schema ||= JSON.parse(File.read(File.join(__dir__, 'schemas', '3.0.0.json')))
|
72
|
+
end
|
73
|
+
|
74
|
+
def pretty_print?
|
75
|
+
Fictium.configuration.pretty_print
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require_relative 'configurations/configuration'
|
2
|
+
require_relative 'configurations/info'
|
3
|
+
|
4
|
+
require_relative 'evaluators/parameter_evaluator'
|
5
|
+
require_relative 'evaluators/schema_evaluator'
|
6
|
+
|
7
|
+
require_relative 'poros/model'
|
8
|
+
|
9
|
+
require_relative 'poros/action'
|
10
|
+
require_relative 'poros/document'
|
11
|
+
require_relative 'poros/example'
|
12
|
+
require_relative 'poros/resource'
|
13
|
+
|
14
|
+
# Require default (OpenApi v3) exporter
|
15
|
+
require_relative 'exporters/open_api/v3_exporter'
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module Fictium
|
2
|
+
class Action < Fictium::Model
|
3
|
+
attr_reader :resource, :examples, :params
|
4
|
+
attr_accessor :path, :summary, :description, :method, :tags, :deprecated, :docs
|
5
|
+
|
6
|
+
def initialize(resource)
|
7
|
+
@resource = resource
|
8
|
+
@params = ActiveSupport::HashWithIndifferentAccess.new
|
9
|
+
@examples = []
|
10
|
+
@tags = []
|
11
|
+
@deprecated = false
|
12
|
+
end
|
13
|
+
|
14
|
+
def full_path
|
15
|
+
"#{resource.base_path}#{path}"
|
16
|
+
end
|
17
|
+
|
18
|
+
def [](section)
|
19
|
+
@params[section] ||= ActiveSupport::HashWithIndifferentAccess.new
|
20
|
+
end
|
21
|
+
|
22
|
+
def add_params_in(section, &block)
|
23
|
+
self[section].merge!(Fictium::ParameterEvaluator.new.evaluate_params(&block))
|
24
|
+
nil
|
25
|
+
end
|
26
|
+
|
27
|
+
def add_example
|
28
|
+
Fictium::Example.new(self).tap { |example| examples << example }
|
29
|
+
end
|
30
|
+
|
31
|
+
def combined_tags
|
32
|
+
resource.tags + tags
|
33
|
+
end
|
34
|
+
|
35
|
+
def deprecated?
|
36
|
+
deprecated
|
37
|
+
end
|
38
|
+
|
39
|
+
def default_example
|
40
|
+
examples.find(&:default?).presence || examples.first
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Fictium
|
2
|
+
class Document < Fictium::Model
|
3
|
+
attr_reader :resources
|
4
|
+
|
5
|
+
def initialize
|
6
|
+
@resources = []
|
7
|
+
end
|
8
|
+
|
9
|
+
def create_resource
|
10
|
+
Fictium::Resource.new(self).tap { |resource| resources << resource }
|
11
|
+
end
|
12
|
+
|
13
|
+
def export
|
14
|
+
Fictium.configuration.exporters.each do |exporter|
|
15
|
+
exporter.export(self)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module Fictium
|
2
|
+
class Example < Fictium::Model
|
3
|
+
attr_reader :action
|
4
|
+
attr_accessor :summary, :description, :response, :request, :default, :headers
|
5
|
+
|
6
|
+
def initialize(action)
|
7
|
+
@action = action
|
8
|
+
@headers = ActiveSupport::HashWithIndifferentAccess.new
|
9
|
+
end
|
10
|
+
|
11
|
+
def default?
|
12
|
+
default
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module Fictium
|
2
|
+
class Resource < Fictium::Model
|
3
|
+
attr_reader :document, :actions
|
4
|
+
attr_accessor :name, :base_path, :summary, :description, :tags
|
5
|
+
|
6
|
+
def initialize(document)
|
7
|
+
@document = document
|
8
|
+
@actions = []
|
9
|
+
@tags = []
|
10
|
+
end
|
11
|
+
|
12
|
+
def create_action
|
13
|
+
Fictium::Action.new(self).tap { |action| actions << action }
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module Fictium
|
2
|
+
module RSpec
|
3
|
+
module Actions
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
included do
|
7
|
+
metadata[:fictium_action] = metadata[:fictium_resource].create_action
|
8
|
+
Fictium::RSpec::Autocomplete::Action.description_attributes(
|
9
|
+
metadata[:fictium_action],
|
10
|
+
metadata[:description]
|
11
|
+
)
|
12
|
+
end
|
13
|
+
|
14
|
+
class_methods do
|
15
|
+
def path(path)
|
16
|
+
metadata[:fictium_action].path = path
|
17
|
+
end
|
18
|
+
|
19
|
+
def params_in(section, &block)
|
20
|
+
metadata[:fictium_action].add_params_in(section, &block)
|
21
|
+
end
|
22
|
+
|
23
|
+
def example(*args, **kwargs)
|
24
|
+
Fictium::RSpec::Proxies::Example.new(self, args, kwargs)
|
25
|
+
end
|
26
|
+
|
27
|
+
def deprecate!
|
28
|
+
metadata[:fictium_action].deprecated = true
|
29
|
+
end
|
30
|
+
|
31
|
+
def action_docs(description: nil, url:)
|
32
|
+
metadata[:fictium_action].docs = {}.tap do |docs|
|
33
|
+
docs[:url] = url
|
34
|
+
docs[:description] = description if description.present?
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
module Fictium
|
2
|
+
module RSpec
|
3
|
+
module Autocomplete
|
4
|
+
module Action
|
5
|
+
ACTION_NAME = /#([A-Z_]+)/i.freeze
|
6
|
+
DEFAULT_PATHS = {
|
7
|
+
index: '',
|
8
|
+
create: '',
|
9
|
+
new: '/new',
|
10
|
+
show: '/{id}',
|
11
|
+
update: '/{id}',
|
12
|
+
destroy: '/{id}'
|
13
|
+
}.freeze
|
14
|
+
class << self
|
15
|
+
def description_attributes(action, description)
|
16
|
+
name = find_action_name(description)&.downcase
|
17
|
+
find_summary(action, name)
|
18
|
+
find_path(action, name)
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def find_summary(action, name)
|
24
|
+
return if name.blank?
|
25
|
+
|
26
|
+
key = :"default_summary_for_#{name}"
|
27
|
+
summary_method = descriptors[key] || Fictium.configuration.unknown_action_descriptor
|
28
|
+
one_argument = summary_method.arity == 1
|
29
|
+
action.summary =
|
30
|
+
one_argument ? summary_method.call(action) : summary_method.call(action, name)
|
31
|
+
end
|
32
|
+
|
33
|
+
def descriptors
|
34
|
+
@descriptors ||= Fictium.configuration.default_action_descriptors || {}
|
35
|
+
end
|
36
|
+
|
37
|
+
def find_path(action, name)
|
38
|
+
return if name.blank?
|
39
|
+
|
40
|
+
key = name.to_sym
|
41
|
+
action.path = DEFAULT_PATHS[key] || "/{id}/#{name}"
|
42
|
+
end
|
43
|
+
|
44
|
+
def find_action_name(description)
|
45
|
+
match = description.match(ACTION_NAME)
|
46
|
+
match.presence && match[1]
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
module Fictium
|
2
|
+
module RSpec
|
3
|
+
module Autocomplete
|
4
|
+
module Example
|
5
|
+
class << self
|
6
|
+
def process_http_response(example, response)
|
7
|
+
example.response ||= {}
|
8
|
+
example.response.merge!(
|
9
|
+
status: response.status,
|
10
|
+
body: response.body,
|
11
|
+
content_type: response.content_type
|
12
|
+
)
|
13
|
+
process_http_request(example, response.request)
|
14
|
+
return unless example.default?
|
15
|
+
|
16
|
+
autocomplete_params.extract_from_response(example, response)
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def autocomplete_params
|
22
|
+
Fictium::RSpec::Autocomplete::Params
|
23
|
+
end
|
24
|
+
|
25
|
+
def process_http_request(example, request)
|
26
|
+
example.request ||= {}
|
27
|
+
example.request.merge!(
|
28
|
+
content_type: request.content_type,
|
29
|
+
body: request.body.string
|
30
|
+
)
|
31
|
+
extract_method(example, request)
|
32
|
+
return unless example.default?
|
33
|
+
|
34
|
+
autocomplete_params.extract_from_request(example.action, request)
|
35
|
+
end
|
36
|
+
|
37
|
+
def extract_method(example, request)
|
38
|
+
action = example.action
|
39
|
+
action.method = request.method.downcase.to_sym if action.method.blank?
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
module Fictium
|
2
|
+
module RSpec
|
3
|
+
module Autocomplete
|
4
|
+
module Params
|
5
|
+
REQUEST_SECTIONS = %i[query header path cookie].freeze
|
6
|
+
PATH_TEMPLATE = /{([A-Z_\-][A-Z0-9_\-]*)}/i.freeze
|
7
|
+
|
8
|
+
class << self
|
9
|
+
def extract_from_request(action, request)
|
10
|
+
REQUEST_SECTIONS.each do |section|
|
11
|
+
action.params[section] ||= ActiveSupport::HashWithIndifferentAccess.new
|
12
|
+
send(:"parse_request_#{section}", action.params[section], action, request)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def extract_from_response(example, response)
|
17
|
+
example.headers ||= ActiveSupport::HashWithIndifferentAccess.new
|
18
|
+
response.headers.each do |name, value|
|
19
|
+
next unless valid_header?(name)
|
20
|
+
|
21
|
+
example.headers[name] ||= {}
|
22
|
+
example.headers[name].merge!(
|
23
|
+
example: value
|
24
|
+
)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
def parse_request_query(params, _action, request)
|
31
|
+
request.query_parameters.each do |key, value|
|
32
|
+
params[key] ||= {}
|
33
|
+
params[key].merge!(
|
34
|
+
example: value
|
35
|
+
)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def parse_request_header(params, _action, request)
|
40
|
+
request.headers.to_h.each do |name, value|
|
41
|
+
next unless valid_header?(name)
|
42
|
+
|
43
|
+
params[name] ||= {}
|
44
|
+
params[name].merge!(
|
45
|
+
example: value
|
46
|
+
)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def parse_request_path(params, action, _request)
|
51
|
+
action.full_path.scan(PATH_TEMPLATE).flatten.each do |name|
|
52
|
+
params[name] ||= {}
|
53
|
+
# TODO: Extract example from request
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def parse_request_cookie(params, _action, request)
|
58
|
+
request.cookies.each do |key, value|
|
59
|
+
params[key] ||= {}
|
60
|
+
params[key].merge!(
|
61
|
+
example: value
|
62
|
+
)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def valid_header?(name)
|
67
|
+
return false if ignored_header_groups.any? { |group| name.downcase.start_with?(group) }
|
68
|
+
|
69
|
+
!Fictium.configuration.ignored_header_values.include?(name.downcase)
|
70
|
+
end
|
71
|
+
|
72
|
+
def ignored_header_groups
|
73
|
+
Fictium.configuration.ignored_header_groups
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Fictium
|
2
|
+
module RSpec
|
3
|
+
module Autocomplete
|
4
|
+
module Resource
|
5
|
+
CONTROLLER_TERMINATION = /Controller$/.freeze
|
6
|
+
|
7
|
+
class << self
|
8
|
+
def name_attributes(resource, controller_name)
|
9
|
+
resource_path = controller_name.sub(CONTROLLER_TERMINATION, '').underscore
|
10
|
+
resource.base_path = "/#{resource_path}"
|
11
|
+
path_sections = resource_path.split('/')
|
12
|
+
plural = path_sections.last
|
13
|
+
resource.name = plural.singularize.humanize(capitalize: false)
|
14
|
+
resource.summary = Fictium.configuration.summary_format.call(plural)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|