dryer_clients 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/Gemfile +2 -0
- data/LICENSE +17 -0
- data/README.md +52 -0
- data/dryer_clients.gemspec +32 -0
- data/lib/dryer/clients/api_descriptions/description_schema.rb +83 -0
- data/lib/dryer/clients/api_descriptions/resources/generate_name.rb +26 -0
- data/lib/dryer/clients/create.rb +44 -0
- data/lib/dryer/clients/gems/api_description_files/create.rb +72 -0
- data/lib/dryer/clients/gems/client_files/create.rb +54 -0
- data/lib/dryer/clients/gems/contract_files/create.rb +56 -0
- data/lib/dryer/clients/gems/create.rb +85 -0
- data/lib/dryer/clients/gems/gemfiles/create.rb +38 -0
- data/lib/dryer/clients/gems/gemspec_files/create.rb +63 -0
- data/lib/dryer/clients/gems/main_files/create.rb +48 -0
- data/lib/dryer/clients/generated_client.rb +11 -0
- data/lib/dryer/clients/generated_clients/create.rb +28 -0
- data/lib/dryer/clients/generated_clients/paths/variables/validate.rb +41 -0
- data/lib/dryer/clients/generated_clients/request.rb +56 -0
- data/lib/dryer/clients/generated_clients/requests/validate.rb +63 -0
- data/lib/dryer/clients/generated_clients/resource.rb +14 -0
- data/lib/dryer/clients/generated_clients/resources/create.rb +85 -0
- data/lib/dryer/clients/generated_clients/response.rb +22 -0
- data/lib/dryer/clients/generated_clients/responses/create.rb +61 -0
- data/lib/dryer/clients.rb +25 -0
- data/lib/dryer_clients.rb +1 -0
- metadata +168 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 444ea8835abfd4a2916e899334724404a51bf0a1c17fa8b5d53f2d85f182f498
|
4
|
+
data.tar.gz: fef7016f3011677d5e049484e94b9301de36fc78bb84ac015bad9546c8a7a276
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 4d2eae4ef4347fa02cd488901182927561d78ec17ee683bc016bbff8e9dfb46811c660f6bf6f2bdff955c9c04781910def4e4f245dc8468b8d6b4e963e4aefb2
|
7
|
+
data.tar.gz: 82524d96f45ab440a097f2596d5496d1092143fe2a234a1f7a5feff1aad7695964c5a3c4e4d20a55d45ea3871c4dac440814803fe31225cec8bb8c34cb397b6b
|
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
MIT License
|
2
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
3
|
+
a copy of this software and associated documentation files (the
|
4
|
+
"Software"), to deal in the Software without restriction, including
|
5
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
6
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
7
|
+
permit persons to whom the Software is furnished to do so, subject to
|
8
|
+
the following conditions:
|
9
|
+
The above copyright notice and this permission notice shall be
|
10
|
+
included in all copies or substantial portions of the Software.
|
11
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
12
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
13
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
14
|
+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
15
|
+
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
16
|
+
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
17
|
+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
# Dryer Clients
|
2
|
+
A gem providing that generates an API client gem based on an api defintion.
|
3
|
+
The API defintions depend heavily on [dry-validation](https://dry-rb.org/gems/dry-validation/1.8/) contracts
|
4
|
+
for header/request/response validation
|
5
|
+
|
6
|
+
## Installation
|
7
|
+
add the following to you gemfile
|
8
|
+
```
|
9
|
+
gem "dryer_clients"
|
10
|
+
```
|
11
|
+
|
12
|
+
## Usage
|
13
|
+
To generate a client gem for an API there are two steps:
|
14
|
+
|
15
|
+
1. Define the api. [Check out the schema definition here.](./lib/dryer/clients/api_descriptions/description_schema.rb)
|
16
|
+
Note that this is schema is a subset of the schema used by [dryer_routes](github.com/jbernie/dryer_routes),
|
17
|
+
so any definition that works with the dryer_routes gem, will also work here.
|
18
|
+
|
19
|
+
2. Generate your client. I set up mine as part of a rake task.
|
20
|
+
```ruby
|
21
|
+
Dryer::Clients::Gems::Create.call(
|
22
|
+
gem_name: 'my_special_gem_name,
|
23
|
+
output_directory: './generated/ruby_client,
|
24
|
+
api_description: './path_to_my_api_description_file',
|
25
|
+
contract_directory: './directory_where_all_my_dry-validation_contracts_are'
|
26
|
+
)
|
27
|
+
```
|
28
|
+
|
29
|
+
When run, this will output a gem in the specified output directory. It can be published/used like any other
|
30
|
+
ruby gem.
|
31
|
+
|
32
|
+
### Caveats
|
33
|
+
Due to the loosey goosey nature of how ruby handles module loading, when passing in
|
34
|
+
the contract directory, make sure that there are no external dependencies outside of
|
35
|
+
the files passed in (other than the dry-validation gem), otherwise you will get a
|
36
|
+
'not found' error when the gem tries to load some class that is not included in the gem.
|
37
|
+
|
38
|
+
## Development
|
39
|
+
This gem is set up to be developed using [Nix](https://nixos.org/) and
|
40
|
+
[ruby_gem_dev_shell](https://github.com/jbernie2/ruby_gem_dev_shell)
|
41
|
+
Once you have nix installed you can run `make env` to enter the development
|
42
|
+
environment and then `make` to see the list of available commands
|
43
|
+
|
44
|
+
## Contributing
|
45
|
+
Please create a github issue to report any problems using the Gem.
|
46
|
+
Thanks for your help in making testing easier for everyone!
|
47
|
+
|
48
|
+
## Versioning
|
49
|
+
Dryer Clients follows Semantic Versioning 2.0 as defined at https://semver.org.
|
50
|
+
|
51
|
+
## License
|
52
|
+
This code is free to use under the terms of the MIT license.
|
@@ -0,0 +1,32 @@
|
|
1
|
+
Gem::Specification.new do |spec|
|
2
|
+
spec.name = 'dryer_clients'
|
3
|
+
spec.version = "0.1.0"
|
4
|
+
spec.authors = ['John Bernier']
|
5
|
+
spec.email = ['john.b.bernier@gmail.com']
|
6
|
+
spec.summary = 'Library that leverages dry contracts to generate API clients'
|
7
|
+
spec.description = <<~DOC
|
8
|
+
Given a description of an API, generates a ruby client for that API.
|
9
|
+
DOC
|
10
|
+
spec.homepage = 'https://github.com/jbernie2/dryer_clients'
|
11
|
+
spec.license = 'MIT'
|
12
|
+
spec.platform = Gem::Platform::RUBY
|
13
|
+
spec.required_ruby_version = '>= 3.0.0'
|
14
|
+
spec.files = Dir[
|
15
|
+
'dryer_clients.gemspec',
|
16
|
+
'README.md',
|
17
|
+
'LICENSE',
|
18
|
+
'CHANGELOG.md',
|
19
|
+
'lib/**/*.rb',
|
20
|
+
'.github/*.md',
|
21
|
+
'Gemfile'
|
22
|
+
]
|
23
|
+
|
24
|
+
spec.add_dependency "zeitwerk", "~> 2.6"
|
25
|
+
spec.add_dependency "dry-validation", "~> 1.10"
|
26
|
+
spec.add_dependency "dry-monads", "~> 1.6"
|
27
|
+
spec.add_dependency "dryer_services", "~> 2.0"
|
28
|
+
|
29
|
+
spec.add_development_dependency "rspec", "~> 3.10"
|
30
|
+
spec.add_development_dependency "webmock", "~> 3.14"
|
31
|
+
spec.add_development_dependency "debug", "~> 1.8"
|
32
|
+
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
require 'dry-validation'
|
2
|
+
|
3
|
+
module Dryer
|
4
|
+
module Clients
|
5
|
+
module ApiDescriptions
|
6
|
+
class DescriptionSchema < Dry::Validation::Contract
|
7
|
+
|
8
|
+
params do
|
9
|
+
required(:url).filled(:string)
|
10
|
+
required(:actions).filled(:hash)
|
11
|
+
end
|
12
|
+
|
13
|
+
class ActionSchema < Dry::Validation::Contract
|
14
|
+
params do
|
15
|
+
required(:method).filled(:symbol)
|
16
|
+
optional(:request_contract)
|
17
|
+
optional(:url_parameters_contract)
|
18
|
+
optional(:headers_contract)
|
19
|
+
optional(:response_contracts).hash()
|
20
|
+
end
|
21
|
+
|
22
|
+
rule(:request_contract) do
|
23
|
+
unless valid_contract?(value)
|
24
|
+
key.failure('must be a dry-validation contract')
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
rule(:url_parameters_contract) do
|
29
|
+
unless valid_contract?(value)
|
30
|
+
key.failure('must be a dry-validation contract')
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
rule(:headers_contract) do
|
35
|
+
unless valid_contract?(value)
|
36
|
+
key.failure('must be a dry-validation contract')
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
rule(:response_contracts) do
|
41
|
+
values[:response_contracts].each do |key, value|
|
42
|
+
unless valid_contract?(value)
|
43
|
+
key(:response_contracts).failure(
|
44
|
+
'must be a dry-validation contract'
|
45
|
+
)
|
46
|
+
end
|
47
|
+
end if values[:response_contracts]
|
48
|
+
end
|
49
|
+
|
50
|
+
def valid_contract?(value)
|
51
|
+
case value
|
52
|
+
when Class
|
53
|
+
value <= Dry::Validation::Contract
|
54
|
+
when String
|
55
|
+
begin
|
56
|
+
contract_class = Module.const_get(value)
|
57
|
+
contract_class <= Dry::Validation::Contract
|
58
|
+
rescue NameError => e
|
59
|
+
false
|
60
|
+
end
|
61
|
+
else
|
62
|
+
true
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
rule(:actions) do
|
68
|
+
values[:actions].each do |key, value|
|
69
|
+
res = ActionSchema.new.call(value)
|
70
|
+
if !res.success?
|
71
|
+
res.errors.to_h.each do |name, messages|
|
72
|
+
messages.each do |msg|
|
73
|
+
key([key_name, name]).failure(msg)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'dryer_services'
|
2
|
+
|
3
|
+
module Dryer
|
4
|
+
module Clients
|
5
|
+
module ApiDescriptions
|
6
|
+
module Resources
|
7
|
+
class GenerateName < Dryer::Services::SimpleService
|
8
|
+
def initialize(resource)
|
9
|
+
@resource = resource
|
10
|
+
end
|
11
|
+
|
12
|
+
def call
|
13
|
+
resource[:url]
|
14
|
+
.split("/")
|
15
|
+
.reject { |part| part.start_with?(":") }
|
16
|
+
.reject { |part| part.empty? }
|
17
|
+
.join("_")
|
18
|
+
end
|
19
|
+
|
20
|
+
attr_reader :resource
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
@@ -0,0 +1,44 @@
|
|
1
|
+
require 'dryer_services'
|
2
|
+
|
3
|
+
module Dryer
|
4
|
+
module Clients
|
5
|
+
class Create < Dryer::Services::SimpleService
|
6
|
+
|
7
|
+
def initialize(*api_desc)
|
8
|
+
if api_desc.is_a?(Array) && api_desc[0].is_a?(Array)
|
9
|
+
@api_desc = api_desc[0]
|
10
|
+
else
|
11
|
+
@api_desc = api_desc || []
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def call
|
16
|
+
validate_api_description.then do |errors|
|
17
|
+
if errors.empty?
|
18
|
+
GeneratedClients::Create.call(api_desc)
|
19
|
+
else
|
20
|
+
raise errors
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
attr_reader :api_desc
|
27
|
+
|
28
|
+
def validate_api_description
|
29
|
+
errors = api_desc.map do |r|
|
30
|
+
ApiDescriptions::DescriptionSchema.new.call(r)
|
31
|
+
end.select { |r| !r.errors.empty? }
|
32
|
+
|
33
|
+
if !errors.empty?
|
34
|
+
messages = errors.inject({}) do |messages, e|
|
35
|
+
messages.merge(e.errors.to_h)
|
36
|
+
end
|
37
|
+
messages
|
38
|
+
else
|
39
|
+
[]
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
require "dryer_services"
|
2
|
+
require "fileutils"
|
3
|
+
require 'pathname'
|
4
|
+
require "debug"
|
5
|
+
|
6
|
+
module Dryer
|
7
|
+
module Clients
|
8
|
+
module Gems
|
9
|
+
module ApiDescriptionFiles
|
10
|
+
class Create < Dryer::Services::SimpleService
|
11
|
+
def initialize(
|
12
|
+
gem_module_name:,
|
13
|
+
api_description:,
|
14
|
+
output_directory:
|
15
|
+
)
|
16
|
+
@gem_module_name = gem_module_name
|
17
|
+
@api_description = api_description
|
18
|
+
@output_directory = output_directory
|
19
|
+
end
|
20
|
+
|
21
|
+
def call
|
22
|
+
{
|
23
|
+
path: "#{output_directory}/api_description.rb",
|
24
|
+
contents: api_description_file_contents(stringify_class_names(api_description))
|
25
|
+
}
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
attr_reader :gem_module_name,
|
30
|
+
:output_directory,
|
31
|
+
:api_description
|
32
|
+
|
33
|
+
def api_description_file_contents(description)
|
34
|
+
<<~FILE
|
35
|
+
module #{gem_module_name}
|
36
|
+
class ApiDescription
|
37
|
+
def self.definition
|
38
|
+
#{description}
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
FILE
|
43
|
+
end
|
44
|
+
|
45
|
+
def stringify_class_names(description)
|
46
|
+
case description
|
47
|
+
when Array
|
48
|
+
description.map { |h| stringify_hash(h) }
|
49
|
+
when Hash
|
50
|
+
[ stringify_hash(description) ]
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def stringify_hash(hash)
|
55
|
+
hash.inject({}) do |acc, (key, value)|
|
56
|
+
acc[key] = case value
|
57
|
+
when Class
|
58
|
+
"#{gem_module_name}::#{value.to_s}"
|
59
|
+
when Hash
|
60
|
+
stringify_hash(value)
|
61
|
+
else
|
62
|
+
value
|
63
|
+
end
|
64
|
+
acc
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
@@ -0,0 +1,54 @@
|
|
1
|
+
require "dryer_services"
|
2
|
+
require "fileutils"
|
3
|
+
require 'pathname'
|
4
|
+
require "debug"
|
5
|
+
|
6
|
+
module Dryer
|
7
|
+
module Clients
|
8
|
+
module Gems
|
9
|
+
module ClientFiles
|
10
|
+
class Create < Dryer::Services::SimpleService
|
11
|
+
def initialize(
|
12
|
+
gem_module_name:,
|
13
|
+
output_directory:
|
14
|
+
)
|
15
|
+
@gem_module_name = gem_module_name
|
16
|
+
@output_directory = output_directory
|
17
|
+
end
|
18
|
+
|
19
|
+
def call
|
20
|
+
{
|
21
|
+
path: "#{output_directory}/client.rb",
|
22
|
+
contents: file_contents
|
23
|
+
}
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
attr_reader :gem_module_name,
|
28
|
+
:output_directory
|
29
|
+
|
30
|
+
def file_contents
|
31
|
+
<<~CLIENT
|
32
|
+
module #{gem_module_name}
|
33
|
+
class Client
|
34
|
+
def initialize(base_url)
|
35
|
+
@base_url = base_url
|
36
|
+
end
|
37
|
+
|
38
|
+
def client
|
39
|
+
@client ||= Dryer::Clients::Create.call(
|
40
|
+
ApiDescription.definition
|
41
|
+
).new(base_url)
|
42
|
+
end
|
43
|
+
|
44
|
+
attr_reader :base_url
|
45
|
+
end
|
46
|
+
end
|
47
|
+
CLIENT
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
@@ -0,0 +1,56 @@
|
|
1
|
+
require "dryer_services"
|
2
|
+
require "fileutils"
|
3
|
+
require 'pathname'
|
4
|
+
require "debug"
|
5
|
+
|
6
|
+
module Dryer
|
7
|
+
module Clients
|
8
|
+
module Gems
|
9
|
+
module ContractFiles
|
10
|
+
class Create < Dryer::Services::SimpleService
|
11
|
+
def initialize(
|
12
|
+
gem_module_name:,
|
13
|
+
input_directory:,
|
14
|
+
output_directory:
|
15
|
+
)
|
16
|
+
@gem_module_name = gem_module_name
|
17
|
+
@input_directory = input_directory
|
18
|
+
@output_directory = output_directory
|
19
|
+
end
|
20
|
+
|
21
|
+
def call
|
22
|
+
input_paths.map do |input|
|
23
|
+
contents = File.read(input)
|
24
|
+
{
|
25
|
+
path: output_path(input),
|
26
|
+
contents: encapsulate_in_gem_module(contents)
|
27
|
+
}
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
attr_reader :gem_module_name,
|
33
|
+
:input_directory,
|
34
|
+
:output_directory
|
35
|
+
|
36
|
+
def input_paths
|
37
|
+
Dir["#{input_directory}/**/*"].reject { |fn| File.directory?(fn) }
|
38
|
+
end
|
39
|
+
|
40
|
+
def output_path(input_path)
|
41
|
+
output_directory + input_path.gsub(input_directory, "")
|
42
|
+
end
|
43
|
+
|
44
|
+
def encapsulate_in_gem_module(file_contents)
|
45
|
+
<<~FILE
|
46
|
+
module #{gem_module_name}
|
47
|
+
#{file_contents}
|
48
|
+
end
|
49
|
+
FILE
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
@@ -0,0 +1,85 @@
|
|
1
|
+
require "dryer_services"
|
2
|
+
require "fileutils"
|
3
|
+
require 'pathname'
|
4
|
+
require "debug"
|
5
|
+
|
6
|
+
module Dryer
|
7
|
+
module Clients
|
8
|
+
module Gems
|
9
|
+
class Create < Dryer::Services::SimpleService
|
10
|
+
def initialize(
|
11
|
+
gem_name:,
|
12
|
+
output_directory:,
|
13
|
+
api_description:,
|
14
|
+
contract_directory:
|
15
|
+
)
|
16
|
+
@gem_name = gem_name
|
17
|
+
@output_directory = output_directory
|
18
|
+
@contract_directory = contract_directory
|
19
|
+
@api_description = api_description
|
20
|
+
end
|
21
|
+
|
22
|
+
def call
|
23
|
+
ContractFiles::Create.call(
|
24
|
+
gem_module_name: camelize(gem_name),
|
25
|
+
input_directory: contract_directory,
|
26
|
+
output_directory: contract_output_dir
|
27
|
+
).append(
|
28
|
+
ApiDescriptionFiles::Create.call(
|
29
|
+
gem_module_name: camelize(gem_name),
|
30
|
+
api_description: api_description,
|
31
|
+
output_directory: dependencies_dir
|
32
|
+
),
|
33
|
+
ClientFiles::Create.call(
|
34
|
+
gem_module_name: camelize(gem_name),
|
35
|
+
output_directory: dependencies_dir
|
36
|
+
),
|
37
|
+
MainFiles::Create.call(
|
38
|
+
gem_name: gem_name,
|
39
|
+
gem_module_name: camelize(gem_name),
|
40
|
+
output_directory: lib_dir
|
41
|
+
),
|
42
|
+
Gemfiles::Create.call(
|
43
|
+
output_directory: output_directory
|
44
|
+
)
|
45
|
+
).then do |files|
|
46
|
+
gemspec = GemspecFiles::Create.call(
|
47
|
+
gem_name: gem_name,
|
48
|
+
output_directory: output_directory
|
49
|
+
)
|
50
|
+
File.exist?(gemspec[:path]) ? files : files.append(gemspec)
|
51
|
+
end.map do |file|
|
52
|
+
FileUtils.mkdir_p(File.dirname(file[:path]))
|
53
|
+
File.open(File.expand_path(file[:path]), "w") do |f|
|
54
|
+
f.write(file[:contents])
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
output_directory
|
59
|
+
end
|
60
|
+
|
61
|
+
private
|
62
|
+
attr_reader :api_description,
|
63
|
+
:gem_name,
|
64
|
+
:output_directory,
|
65
|
+
:contract_directory
|
66
|
+
|
67
|
+
def lib_dir
|
68
|
+
"#{output_directory}/lib"
|
69
|
+
end
|
70
|
+
|
71
|
+
def dependencies_dir
|
72
|
+
"#{lib_dir}/#{gem_name}"
|
73
|
+
end
|
74
|
+
|
75
|
+
def contract_output_dir
|
76
|
+
"#{dependencies_dir}/contracts"
|
77
|
+
end
|
78
|
+
|
79
|
+
def camelize(str)
|
80
|
+
str.split(/[\-_]/).map{|e| e.capitalize}.join
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require "dryer_services"
|
2
|
+
require "fileutils"
|
3
|
+
require 'pathname'
|
4
|
+
require "debug"
|
5
|
+
|
6
|
+
module Dryer
|
7
|
+
module Clients
|
8
|
+
module Gems
|
9
|
+
module Gemfiles
|
10
|
+
class Create < Dryer::Services::SimpleService
|
11
|
+
def initialize(
|
12
|
+
output_directory:
|
13
|
+
)
|
14
|
+
@output_directory = output_directory
|
15
|
+
end
|
16
|
+
|
17
|
+
def call
|
18
|
+
{
|
19
|
+
path: "#{output_directory}/Gemfile",
|
20
|
+
contents: file_contents
|
21
|
+
}
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
attr_reader :output_directory
|
26
|
+
|
27
|
+
def file_contents
|
28
|
+
<<~GEMFILE
|
29
|
+
source 'http://rubygems.org'
|
30
|
+
gemspec
|
31
|
+
GEMFILE
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
@@ -0,0 +1,63 @@
|
|
1
|
+
require "dryer_services"
|
2
|
+
require "fileutils"
|
3
|
+
require 'pathname'
|
4
|
+
require "debug"
|
5
|
+
|
6
|
+
module Dryer
|
7
|
+
module Clients
|
8
|
+
module Gems
|
9
|
+
module GemspecFiles
|
10
|
+
class Create < Dryer::Services::SimpleService
|
11
|
+
def initialize(
|
12
|
+
gem_name:,
|
13
|
+
output_directory:
|
14
|
+
)
|
15
|
+
@gem_name = gem_name
|
16
|
+
@output_directory = output_directory
|
17
|
+
end
|
18
|
+
|
19
|
+
def call
|
20
|
+
{
|
21
|
+
path: "#{output_directory}/#{gem_name}.gemspec",
|
22
|
+
contents: file_contents
|
23
|
+
}
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
attr_reader :gem_name,
|
28
|
+
:output_directory
|
29
|
+
|
30
|
+
def file_contents
|
31
|
+
<<~GEMSPEC
|
32
|
+
Gem::Specification.new do |spec|
|
33
|
+
spec.name = '#{gem_name}'
|
34
|
+
spec.version = "0.0.1"
|
35
|
+
spec.authors = ['']
|
36
|
+
spec.email = ['']
|
37
|
+
spec.summary = 'Http client generated using dryer_clients gem'
|
38
|
+
spec.description = <<~DOC
|
39
|
+
An Http client generated from an API description using the dryer_clients gem
|
40
|
+
DOC
|
41
|
+
spec.license = 'MIT'
|
42
|
+
spec.platform = Gem::Platform::RUBY
|
43
|
+
spec.required_ruby_version = '>= 3.0.0'
|
44
|
+
spec.files = Dir[
|
45
|
+
'#{gem_name}.gemspec',
|
46
|
+
'README.md',
|
47
|
+
'LICENSE',
|
48
|
+
'CHANGELOG.md',
|
49
|
+
'lib/**/*.rb',
|
50
|
+
'.github/*.md',
|
51
|
+
'Gemfile'
|
52
|
+
]
|
53
|
+
spec.add_dependency "dryer_clients", "~> 0.0"
|
54
|
+
spec.add_dependency "zeitwerk", "~> 2.6"
|
55
|
+
end
|
56
|
+
GEMSPEC
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
@@ -0,0 +1,48 @@
|
|
1
|
+
require "dryer_services"
|
2
|
+
require "fileutils"
|
3
|
+
require 'pathname'
|
4
|
+
require "debug"
|
5
|
+
|
6
|
+
module Dryer
|
7
|
+
module Clients
|
8
|
+
module Gems
|
9
|
+
module MainFiles
|
10
|
+
class Create < Dryer::Services::SimpleService
|
11
|
+
def initialize(
|
12
|
+
gem_name:,
|
13
|
+
gem_module_name:,
|
14
|
+
output_directory:
|
15
|
+
)
|
16
|
+
@gem_name = gem_name
|
17
|
+
@gem_module_name = gem_module_name
|
18
|
+
@output_directory = output_directory
|
19
|
+
end
|
20
|
+
|
21
|
+
def call
|
22
|
+
{
|
23
|
+
path: "#{output_directory}/#{gem_name}.rb",
|
24
|
+
contents: file_contents
|
25
|
+
}
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
attr_reader :gem_name, :gem_module_name, :output_directory
|
30
|
+
|
31
|
+
def file_contents
|
32
|
+
<<~MAIN
|
33
|
+
require "dryer_clients"
|
34
|
+
require "zeitwerk"
|
35
|
+
loader = Zeitwerk::Loader.for_gem
|
36
|
+
loader.setup
|
37
|
+
|
38
|
+
module #{gem_module_name}
|
39
|
+
|
40
|
+
end
|
41
|
+
MAIN
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'dryer_services'
|
2
|
+
|
3
|
+
module Dryer
|
4
|
+
module Clients
|
5
|
+
module GeneratedClients
|
6
|
+
class Create < Dryer::Services::SimpleService
|
7
|
+
def initialize(api_desc)
|
8
|
+
@api_desc = api_desc
|
9
|
+
end
|
10
|
+
|
11
|
+
def call
|
12
|
+
api_desc.inject(Class.new(GeneratedClient)) do |client, resource|
|
13
|
+
resource_object = Resources::Create.call(resource)
|
14
|
+
client.send(
|
15
|
+
:define_method,
|
16
|
+
ApiDescriptions::Resources::GenerateName.call(resource)
|
17
|
+
) do
|
18
|
+
resource_object.new(self.base_url)
|
19
|
+
end
|
20
|
+
client
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
attr_reader :api_desc
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'dryer_services'
|
2
|
+
|
3
|
+
module Dryer
|
4
|
+
module Clients
|
5
|
+
module GeneratedClients
|
6
|
+
module Paths
|
7
|
+
module Variables
|
8
|
+
class Validate < Dryer::Services::ResultService
|
9
|
+
|
10
|
+
def initialize(path, path_variables)
|
11
|
+
@path = path
|
12
|
+
@path_variables = path_variables
|
13
|
+
end
|
14
|
+
|
15
|
+
def call
|
16
|
+
if path_variable_keys.length != path_variables.length
|
17
|
+
Failure(
|
18
|
+
StandardError.new(
|
19
|
+
<<~MSG
|
20
|
+
Path #{path} requires #{path_variable_keys.length} variables,
|
21
|
+
#{path_variables} contains #{path_variables.length}.
|
22
|
+
MSG
|
23
|
+
)
|
24
|
+
)
|
25
|
+
else
|
26
|
+
Success()
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
attr_reader :path, :path_variables
|
32
|
+
|
33
|
+
def path_variable_keys
|
34
|
+
path.scan(/:\w+/)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
require 'net/http'
|
2
|
+
|
3
|
+
module Dryer
|
4
|
+
module Clients
|
5
|
+
module GeneratedClients
|
6
|
+
class Request
|
7
|
+
def initialize(
|
8
|
+
base_url:,
|
9
|
+
method:,
|
10
|
+
path:,
|
11
|
+
path_variables:,
|
12
|
+
headers:,
|
13
|
+
body:
|
14
|
+
)
|
15
|
+
@base_url = base_url
|
16
|
+
@method = method
|
17
|
+
@path = path
|
18
|
+
@path_variables = path_variables
|
19
|
+
@headers = headers
|
20
|
+
@body = body
|
21
|
+
end
|
22
|
+
|
23
|
+
def send
|
24
|
+
uri = URI(base_url)
|
25
|
+
Net::HTTP.start(
|
26
|
+
uri.host, uri.port, use_ssl: uri.scheme == "https"
|
27
|
+
) do |http|
|
28
|
+
http.send_request(
|
29
|
+
method.to_s.upcase,
|
30
|
+
populated_path,
|
31
|
+
body.to_json,
|
32
|
+
headers
|
33
|
+
)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
attr_reader :base_url, :method, :path, :path_variables, :headers, :body
|
39
|
+
|
40
|
+
def populated_path
|
41
|
+
path_variable_keys.to_a.zip(path_variables).inject(path) do |path, (key, value)|
|
42
|
+
if key && value
|
43
|
+
path.sub(key.to_s, value.to_s)
|
44
|
+
else
|
45
|
+
path
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def path_variable_keys
|
51
|
+
path.scan(/:\w+/)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
require 'dryer_services'
|
2
|
+
require 'dry-monads'
|
3
|
+
|
4
|
+
module Dryer
|
5
|
+
module Clients
|
6
|
+
module GeneratedClients
|
7
|
+
module Requests
|
8
|
+
class Validate < Dryer::Services::ResultService
|
9
|
+
include Dry::Monads[:result, :do]
|
10
|
+
|
11
|
+
def initialize(
|
12
|
+
path_variables:,
|
13
|
+
path:,
|
14
|
+
headers:,
|
15
|
+
headers_contract:,
|
16
|
+
body:,
|
17
|
+
request_contract:,
|
18
|
+
url_parameters:,
|
19
|
+
url_parameters_contract:
|
20
|
+
)
|
21
|
+
@path = path
|
22
|
+
@path_variables = path_variables
|
23
|
+
@headers = headers
|
24
|
+
@headers_contract = headers_contract
|
25
|
+
@body = body
|
26
|
+
@request_contract = request_contract
|
27
|
+
@url_parameters = url_parameters
|
28
|
+
@url_parameters_contract = url_parameters_contract
|
29
|
+
end
|
30
|
+
|
31
|
+
def call
|
32
|
+
yield Paths::Variables::Validate.call(path, path_variables)
|
33
|
+
yield validate(headers, headers_contract)
|
34
|
+
yield validate(body, request_contract)
|
35
|
+
yield validate(url_parameters, url_parameters_contract)
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
def validate(payload, contract)
|
41
|
+
return Success() unless contract
|
42
|
+
|
43
|
+
result = contract.new.call(payload)
|
44
|
+
if result.errors.empty?
|
45
|
+
Success()
|
46
|
+
else
|
47
|
+
Failure(StandardError.new(result.errors.to_h))
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
attr_reader :path_variables,
|
52
|
+
:path,
|
53
|
+
:headers,
|
54
|
+
:headers_contract,
|
55
|
+
:body,
|
56
|
+
:request_contract,
|
57
|
+
:url_parameters,
|
58
|
+
:url_parameters_contract
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,85 @@
|
|
1
|
+
require 'dryer_services'
|
2
|
+
require 'dry-monads'
|
3
|
+
|
4
|
+
module Dryer
|
5
|
+
module Clients
|
6
|
+
module GeneratedClients
|
7
|
+
module Resources
|
8
|
+
class Create < Dryer::Services::SimpleService
|
9
|
+
include Dry::Monads[:result, :do]
|
10
|
+
|
11
|
+
def initialize(config)
|
12
|
+
@config = config
|
13
|
+
end
|
14
|
+
|
15
|
+
def call
|
16
|
+
config[:actions].inject(Class.new(Resource)) do |resource, (action_name, action_config)|
|
17
|
+
|
18
|
+
# if I don't set a variable to the config it is not in scope
|
19
|
+
# for the method definition
|
20
|
+
resource_config = config
|
21
|
+
request_contract = get_contract(action_config[:request_contract])
|
22
|
+
headers_contract = get_contract(action_config[:headers_contract])
|
23
|
+
url_parameters_contract = get_contract(action_config[:url_parameters_contract])
|
24
|
+
response_contracts = get_contracts(action_config[:response_contracts])
|
25
|
+
|
26
|
+
resource.send(
|
27
|
+
:define_method,
|
28
|
+
action_name.to_sym
|
29
|
+
) do |*path_variables, **options|
|
30
|
+
headers = options[:headers] || {}
|
31
|
+
body = options[:body] || {}
|
32
|
+
url_parameters = options[:url_parameters] || {}
|
33
|
+
|
34
|
+
Requests::Validate.call(
|
35
|
+
path_variables: path_variables,
|
36
|
+
headers: headers,
|
37
|
+
body: body,
|
38
|
+
url_parameters: url_parameters,
|
39
|
+
request_contract: request_contract,
|
40
|
+
headers_contract: headers_contract,
|
41
|
+
url_parameters_contract: url_parameters_contract,
|
42
|
+
path: action_config[:url] || resource_config[:url]
|
43
|
+
).bind do |_|
|
44
|
+
raw_response = Request.new(
|
45
|
+
base_url: self.base_url,
|
46
|
+
method: action_config[:method],
|
47
|
+
path: action_config[:url] || resource_config[:url],
|
48
|
+
path_variables: path_variables,
|
49
|
+
headers: headers,
|
50
|
+
body: body,
|
51
|
+
).send
|
52
|
+
|
53
|
+
Responses::Create.call(
|
54
|
+
raw_response: raw_response,
|
55
|
+
response_contracts: action_config[:response_contracts]
|
56
|
+
)
|
57
|
+
rescue URI::InvalidURIError => e
|
58
|
+
Dry::Monads::Failure(e)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
resource
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
attr_reader :config
|
66
|
+
|
67
|
+
def get_contracts(hash)
|
68
|
+
hash.inject({}) do |acc, (k,v)|
|
69
|
+
acc[k] = get_contract(v)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def get_contract(contract)
|
74
|
+
case contract
|
75
|
+
when String
|
76
|
+
Module.const_get(contract)
|
77
|
+
when Class
|
78
|
+
contract
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module Dryer
|
2
|
+
module Clients
|
3
|
+
module GeneratedClients
|
4
|
+
class Response
|
5
|
+
def initialize(raw_response:, errors:)
|
6
|
+
@raw_response = raw_response
|
7
|
+
@errors = errors
|
8
|
+
end
|
9
|
+
|
10
|
+
def code
|
11
|
+
raw_response.code
|
12
|
+
end
|
13
|
+
|
14
|
+
def body
|
15
|
+
raw_response.body
|
16
|
+
end
|
17
|
+
|
18
|
+
attr_reader :raw_response, :errors
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
require 'dryer_services'
|
2
|
+
|
3
|
+
module Dryer
|
4
|
+
module Clients
|
5
|
+
module GeneratedClients
|
6
|
+
module Responses
|
7
|
+
class Create < Dryer::Services::ResultService
|
8
|
+
def initialize(
|
9
|
+
raw_response:,
|
10
|
+
response_contracts:
|
11
|
+
)
|
12
|
+
@raw_response = raw_response
|
13
|
+
@response_contracts = response_contracts
|
14
|
+
end
|
15
|
+
|
16
|
+
def call
|
17
|
+
errors = validation_errors(
|
18
|
+
raw_response.body,
|
19
|
+
response_contracts[raw_response.code]
|
20
|
+
)
|
21
|
+
|
22
|
+
if errors.empty?
|
23
|
+
Success(
|
24
|
+
Response.new(
|
25
|
+
raw_response: raw_response,
|
26
|
+
errors: errors
|
27
|
+
)
|
28
|
+
)
|
29
|
+
else
|
30
|
+
Failure(
|
31
|
+
StandardError.new({
|
32
|
+
code: raw_response.code,
|
33
|
+
body: raw_response.body,
|
34
|
+
errors: errors.to_h
|
35
|
+
})
|
36
|
+
)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
def validation_errors(payload, contract)
|
42
|
+
if contract.nil?
|
43
|
+
[]
|
44
|
+
elsif is_json?(payload)
|
45
|
+
contract.new.call(JSON.parse(payload)).errors
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def is_json?(str)
|
50
|
+
JSON.parse(str)
|
51
|
+
true
|
52
|
+
rescue JSON::ParserError, TypeError => e
|
53
|
+
false
|
54
|
+
end
|
55
|
+
|
56
|
+
attr_reader :raw_response, :response_contracts
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require "zeitwerk"
|
2
|
+
require "rubygems"
|
3
|
+
|
4
|
+
module Dryer
|
5
|
+
module Clients
|
6
|
+
def self.version
|
7
|
+
Gem::Specification::load(
|
8
|
+
"./dryer_clients.gemspec"
|
9
|
+
).version
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.loader
|
13
|
+
@loader ||= Zeitwerk::Loader.new.tap do |loader|
|
14
|
+
root = File.expand_path("..", __dir__)
|
15
|
+
loader.tag = "dryer_clients"
|
16
|
+
loader.inflector = Zeitwerk::GemInflector.new("#{root}/dryer_clients.rb")
|
17
|
+
loader.push_dir(root)
|
18
|
+
loader.ignore(
|
19
|
+
"#{root}/dryer_clients.rb",
|
20
|
+
)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
loader.setup
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
require_relative "./dryer/clients.rb"
|
metadata
ADDED
@@ -0,0 +1,168 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: dryer_clients
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- John Bernier
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 1980-01-01 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: zeitwerk
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '2.6'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '2.6'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: dry-validation
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '1.10'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '1.10'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: dry-monads
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '1.6'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '1.6'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: dryer_services
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '2.0'
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '2.0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rspec
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '3.10'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '3.10'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: webmock
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - "~>"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '3.14'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - "~>"
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '3.14'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: debug
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - "~>"
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '1.8'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - "~>"
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '1.8'
|
111
|
+
description: 'Given a description of an API, generates a ruby client for that API.
|
112
|
+
|
113
|
+
'
|
114
|
+
email:
|
115
|
+
- john.b.bernier@gmail.com
|
116
|
+
executables: []
|
117
|
+
extensions: []
|
118
|
+
extra_rdoc_files: []
|
119
|
+
files:
|
120
|
+
- Gemfile
|
121
|
+
- LICENSE
|
122
|
+
- README.md
|
123
|
+
- dryer_clients.gemspec
|
124
|
+
- lib/dryer/clients.rb
|
125
|
+
- lib/dryer/clients/api_descriptions/description_schema.rb
|
126
|
+
- lib/dryer/clients/api_descriptions/resources/generate_name.rb
|
127
|
+
- lib/dryer/clients/create.rb
|
128
|
+
- lib/dryer/clients/gems/api_description_files/create.rb
|
129
|
+
- lib/dryer/clients/gems/client_files/create.rb
|
130
|
+
- lib/dryer/clients/gems/contract_files/create.rb
|
131
|
+
- lib/dryer/clients/gems/create.rb
|
132
|
+
- lib/dryer/clients/gems/gemfiles/create.rb
|
133
|
+
- lib/dryer/clients/gems/gemspec_files/create.rb
|
134
|
+
- lib/dryer/clients/gems/main_files/create.rb
|
135
|
+
- lib/dryer/clients/generated_client.rb
|
136
|
+
- lib/dryer/clients/generated_clients/create.rb
|
137
|
+
- lib/dryer/clients/generated_clients/paths/variables/validate.rb
|
138
|
+
- lib/dryer/clients/generated_clients/request.rb
|
139
|
+
- lib/dryer/clients/generated_clients/requests/validate.rb
|
140
|
+
- lib/dryer/clients/generated_clients/resource.rb
|
141
|
+
- lib/dryer/clients/generated_clients/resources/create.rb
|
142
|
+
- lib/dryer/clients/generated_clients/response.rb
|
143
|
+
- lib/dryer/clients/generated_clients/responses/create.rb
|
144
|
+
- lib/dryer_clients.rb
|
145
|
+
homepage: https://github.com/jbernie2/dryer_clients
|
146
|
+
licenses:
|
147
|
+
- MIT
|
148
|
+
metadata: {}
|
149
|
+
post_install_message:
|
150
|
+
rdoc_options: []
|
151
|
+
require_paths:
|
152
|
+
- lib
|
153
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
154
|
+
requirements:
|
155
|
+
- - ">="
|
156
|
+
- !ruby/object:Gem::Version
|
157
|
+
version: 3.0.0
|
158
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
159
|
+
requirements:
|
160
|
+
- - ">="
|
161
|
+
- !ruby/object:Gem::Version
|
162
|
+
version: '0'
|
163
|
+
requirements: []
|
164
|
+
rubygems_version: 3.4.22
|
165
|
+
signing_key:
|
166
|
+
specification_version: 4
|
167
|
+
summary: Library that leverages dry contracts to generate API clients
|
168
|
+
test_files: []
|