gutsy 0.1.1 → 1.0.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 +4 -4
- data/CHANGELOG.md +21 -0
- data/Gemfile.lock +8 -9
- data/README.md +4 -2
- data/examples/config.yml +17 -0
- data/lib/gutsy.rb +7 -59
- data/lib/gutsy/cli.rb +73 -3
- data/lib/gutsy/configuration.rb +17 -0
- data/lib/gutsy/generator.rb +48 -110
- data/lib/gutsy/generator/api_version_state.rb +37 -0
- data/lib/gutsy/generator/gem_state.rb +64 -0
- data/lib/gutsy/generator/heroics.rb +38 -0
- data/lib/gutsy/generator/resource_state.rb +23 -0
- data/lib/gutsy/schema.rb +36 -0
- data/lib/gutsy/version.rb +1 -1
- data/templates/app_client/README.md.erb +16 -8
- data/templates/app_client/app_client.gemspec.erb +8 -2
- data/templates/app_client/lib/app_client.rb.erb +11 -3
- data/templates/app_client/lib/app_client/{v1 → api_version}/adapter.rb.erb +9 -3
- data/templates/app_client/lib/app_client/{v1 → api_version}/adapters/.gitkeep +0 -0
- data/templates/app_client/lib/app_client/{v1 → api_version}/resource.rb.erb +1 -1
- data/templates/app_client/lib/app_client/version.rb.erb +1 -1
- metadata +13 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a3cacfdafb8ce58f27fe22fb41bd170512edc36c
|
4
|
+
data.tar.gz: f0dde3a28b3c519a8bed2e71c567f32f911d48aa
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6b44d4dadc00b9bc395f28e5fbae3271800a3ae8bac1b0121c5e4c7358112ebb06b38bcc5c8aa4e0f679cef35a8e237692c5e6dc149e7e08d64d0faab339a2df
|
7
|
+
data.tar.gz: cccc382d21b5f94a5edfb6c1c1092db43753857bd1be3fadbf770c1cf050f5412c1403a4b5fa0c62c26da0036d299df2fe1fbb843a142e3ecb19fa36551635fc
|
data/CHANGELOG.md
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
# Gutsy Changelog
|
2
|
+
|
3
|
+
## 1.0.0
|
4
|
+
|
5
|
+
* Support multiple API versions and apps in one configuration file, allow configuring gem metadata. (#1)
|
6
|
+
|
7
|
+
### Breaking Changes
|
8
|
+
|
9
|
+
* The CLI API for `gutsy generate` has changed.
|
10
|
+
|
11
|
+
In 0.1.0, you could do `gutsy generate AppName /path/to/schema.json /path/for/output/`.
|
12
|
+
|
13
|
+
As of 1.0.0, gutsy now allows a much greater degree of customization, through a YAML configuration file.
|
14
|
+
The interface is now `gutsy generate /path/to/gutsy/config.yml /path/for/output/`.
|
15
|
+
|
16
|
+
See [`examples/config.yml`](examples/config.yml) for an example of a Gutsy configuration file.
|
17
|
+
|
18
|
+
## 0.1.0
|
19
|
+
|
20
|
+
* Initial release
|
21
|
+
|
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
gutsy (
|
4
|
+
gutsy (1.0.0)
|
5
5
|
activesupport (>= 3.2)
|
6
6
|
heroics (~> 0.0.17)
|
7
7
|
json_schema (~> 0.13)
|
@@ -9,15 +9,15 @@ PATH
|
|
9
9
|
GEM
|
10
10
|
remote: https://rubygems.org/
|
11
11
|
specs:
|
12
|
-
activesupport (
|
13
|
-
|
14
|
-
|
12
|
+
activesupport (5.0.0.1)
|
13
|
+
concurrent-ruby (~> 1.0, >= 1.0.2)
|
14
|
+
i18n (~> 0.7)
|
15
15
|
minitest (~> 5.1)
|
16
|
-
thread_safe (~> 0.1)
|
17
16
|
tzinfo (~> 1.1)
|
17
|
+
concurrent-ruby (1.0.2)
|
18
18
|
diff-lcs (1.2.5)
|
19
19
|
erubis (2.7.0)
|
20
|
-
excon (0.
|
20
|
+
excon (0.52.0)
|
21
21
|
heroics (0.0.17)
|
22
22
|
erubis (~> 2.0)
|
23
23
|
excon
|
@@ -25,9 +25,8 @@ GEM
|
|
25
25
|
multi_json (>= 1.9.2)
|
26
26
|
netrc
|
27
27
|
i18n (0.7.0)
|
28
|
-
|
29
|
-
|
30
|
-
minitest (5.8.3)
|
28
|
+
json_schema (0.13.3)
|
29
|
+
minitest (5.9.0)
|
31
30
|
moneta (0.8.0)
|
32
31
|
multi_json (1.12.1)
|
33
32
|
netrc (0.11.0)
|
data/README.md
CHANGED
@@ -48,10 +48,12 @@ Gutsy generates RubyGem wrappers and documentation for [heroics](https://github.
|
|
48
48
|
|
49
49
|
```bash
|
50
50
|
$ gem install gutsy
|
51
|
-
$ gutsy generate
|
51
|
+
$ gutsy generate /path/to/gutsy/config.yml /path/for/output/
|
52
52
|
```
|
53
53
|
|
54
|
-
|
54
|
+
See [`examples/config.yml`](examples/config.yml) for an example of a Gutsy configuration file.
|
55
|
+
|
56
|
+
Check out your generated API gem!
|
55
57
|
|
56
58
|
## License
|
57
59
|
|
data/examples/config.yml
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
---
|
2
|
+
gutsy:
|
3
|
+
feature_toggles:
|
4
|
+
name: FeatureToggles
|
5
|
+
base_url: 'http://features.dev' # App base URL (no trailing slash)
|
6
|
+
description: | # Description, optional
|
7
|
+
FeatureToggles toggles features. This gem provides a wrapper around an HTTP
|
8
|
+
Client generated from FeatureToggles's JSON Schema using
|
9
|
+
[heroics](https://github.com/interagent/heroics).
|
10
|
+
author: # Gem author
|
11
|
+
name: Iora Health
|
12
|
+
email: rubygems@iorahealth.com
|
13
|
+
github: IoraHealth
|
14
|
+
version: 0.2.0 # Gem version
|
15
|
+
versions:
|
16
|
+
- name: v1
|
17
|
+
schema_path: docs/api/v1/schema.json
|
data/lib/gutsy.rb
CHANGED
@@ -1,73 +1,21 @@
|
|
1
1
|
require 'active_support'
|
2
|
+
require 'active_support/core_ext/hash/keys'
|
2
3
|
require 'active_support/core_ext/object/try'
|
3
4
|
require 'active_support/core_ext/string/inflections'
|
4
5
|
require 'erb'
|
5
6
|
require 'forwardable'
|
6
7
|
require 'json_schema'
|
7
8
|
require 'open-uri'
|
9
|
+
require 'yaml'
|
10
|
+
|
11
|
+
require 'gutsy/configuration'
|
12
|
+
require 'gutsy/schema'
|
13
|
+
require 'gutsy/generator'
|
8
14
|
require 'gutsy/version'
|
9
15
|
require 'gutsy/cli'
|
10
16
|
|
11
17
|
module Gutsy
|
12
18
|
def self.initialize!
|
13
|
-
|
14
|
-
|
15
|
-
command = args[0]
|
16
|
-
|
17
|
-
case command
|
18
|
-
when "generate"
|
19
|
-
unless args.length == 4
|
20
|
-
puts <<-TEXT
|
21
|
-
Error: Not enough arguments for command 'generate'
|
22
|
-
|
23
|
-
Usage: gutsy generate [app_name] [schema_path] [output_path]
|
24
|
-
|
25
|
-
DESCRIPTION
|
26
|
-
Generates a gem scaffold and resource API clients on top of a heroics-generated client.
|
27
|
-
|
28
|
-
ARGUMENTS
|
29
|
-
[app_name] - CamelCased name of your application
|
30
|
-
[schema_path] - Path to your JSON Schema file
|
31
|
-
[output_path] - Path to output generated API client gem.
|
32
|
-
(Will be created if it doesn't exist)
|
33
|
-
TEXT
|
34
|
-
exit 1
|
35
|
-
end
|
36
|
-
app_name = args[1]
|
37
|
-
schema_path = File.expand_path(args[2])
|
38
|
-
output_path = File.expand_path(args[3])
|
39
|
-
|
40
|
-
generator = Gutsy::Cli::Generator.new(app_name, schema_path, output_path)
|
41
|
-
|
42
|
-
begin
|
43
|
-
generator.generate!
|
44
|
-
rescue => e
|
45
|
-
puts "FAIL"
|
46
|
-
puts e.message
|
47
|
-
puts e.backtrace.join("\n")
|
48
|
-
exit 1
|
49
|
-
end
|
50
|
-
|
51
|
-
exit 0
|
52
|
-
when "version"
|
53
|
-
puts "Gutsy version #{Gutsy::VERSION}"
|
54
|
-
exit 0
|
55
|
-
else
|
56
|
-
puts <<-TEXT
|
57
|
-
Usage: gutsy [command] [options]
|
58
|
-
|
59
|
-
DESCRIPTION
|
60
|
-
Generates gem wrappers around heroics-generated API clients
|
61
|
-
built with JSON Schema. (Enough layers of generation for ya?)
|
62
|
-
|
63
|
-
COMMANDS
|
64
|
-
generate scaffolds out an API client
|
65
|
-
version returns the gutsy version
|
66
|
-
help displays this message
|
67
|
-
|
68
|
-
Shouts out Mr. Gutsy. Keep on plugging in the Wasteland.
|
69
|
-
TEXT
|
70
|
-
exit 0
|
71
|
-
end
|
19
|
+
Gutsy::Cli.parse!(ARGV)
|
72
20
|
end
|
73
21
|
end
|
data/lib/gutsy/cli.rb
CHANGED
@@ -1,7 +1,77 @@
|
|
1
1
|
module Gutsy
|
2
2
|
module Cli
|
3
|
-
|
3
|
+
def self.parse!(args)
|
4
|
+
command = args[0]
|
5
|
+
|
6
|
+
case command
|
7
|
+
when "generate"
|
8
|
+
generate(args[1..-1])
|
9
|
+
when "version"
|
10
|
+
version
|
11
|
+
else
|
12
|
+
help
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.generate(args)
|
17
|
+
unless args.length == 2
|
18
|
+
puts <<-TEXT
|
19
|
+
Error: Not enough arguments for command 'generate'
|
20
|
+
|
21
|
+
Usage: gutsy generate [config_path] [output_path]
|
22
|
+
|
23
|
+
DESCRIPTION
|
24
|
+
Generates a gem scaffold and resource API clients on top of a heroics-generated client.
|
25
|
+
|
26
|
+
ARGUMENTS
|
27
|
+
[config_path] - Path to gutsy configuration file
|
28
|
+
[output_path] - Path to output generated API client gem(s).
|
29
|
+
(Will be created if it doesn't exist)
|
30
|
+
TEXT
|
31
|
+
exit 1
|
32
|
+
end
|
33
|
+
|
34
|
+
config_path = File.expand_path(args[0])
|
35
|
+
output_path = File.expand_path(args[1])
|
36
|
+
|
37
|
+
config = Gutsy::Configuration.load_from_file!(config_path)
|
38
|
+
|
39
|
+
config.apps.each do |app_config|
|
40
|
+
generator = Gutsy::Cli::Generator.new(app_config, output_path)
|
41
|
+
begin
|
42
|
+
generator.generate!
|
43
|
+
rescue => e
|
44
|
+
puts "FAIL"
|
45
|
+
puts e.message
|
46
|
+
puts e.backtrace.join("\n")
|
47
|
+
exit 1
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
exit 0
|
52
|
+
end
|
53
|
+
|
54
|
+
def self.version
|
55
|
+
puts "Gutsy version #{Gutsy::VERSION}"
|
56
|
+
exit 0
|
57
|
+
end
|
58
|
+
|
59
|
+
def self.help
|
60
|
+
puts <<-TEXT
|
61
|
+
Usage: gutsy [command] [options]
|
62
|
+
|
63
|
+
DESCRIPTION
|
64
|
+
Generates gem wrappers around heroics-generated API clients
|
65
|
+
built with JSON Schema. (Enough layers of generation for ya?)
|
66
|
+
|
67
|
+
COMMANDS
|
68
|
+
generate scaffolds out an API client
|
69
|
+
version returns the gutsy version
|
70
|
+
help displays this message
|
71
|
+
|
72
|
+
Shouts out Mr. Gutsy. Keep on plugging in the Wasteland.
|
73
|
+
TEXT
|
74
|
+
exit 0
|
75
|
+
end
|
4
76
|
end
|
5
77
|
end
|
6
|
-
|
7
|
-
require 'gutsy/generator'
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Gutsy
|
2
|
+
class Configuration
|
3
|
+
def self.load_from_file!(config_file_path)
|
4
|
+
yaml_config = YAML.load_file(config_file_path).deep_symbolize_keys
|
5
|
+
raise "Not a valid gutsy configration file" unless yaml_config[:gutsy]
|
6
|
+
new(yaml_config[:gutsy])
|
7
|
+
end
|
8
|
+
|
9
|
+
def initialize(config)
|
10
|
+
@config = config
|
11
|
+
end
|
12
|
+
|
13
|
+
def apps
|
14
|
+
@config.values
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
data/lib/gutsy/generator.rb
CHANGED
@@ -1,81 +1,29 @@
|
|
1
|
+
require 'gutsy/generator/api_version_state'
|
2
|
+
require 'gutsy/generator/gem_state'
|
3
|
+
require 'gutsy/generator/resource_state'
|
4
|
+
require 'gutsy/generator/heroics'
|
5
|
+
|
1
6
|
module Gutsy
|
2
7
|
module Cli
|
3
8
|
class Generator
|
4
9
|
extend Forwardable
|
5
10
|
|
6
|
-
|
7
|
-
|
8
|
-
attr_accessor :resources
|
9
|
-
|
10
|
-
def initialize(app_name, resources=[])
|
11
|
-
@app_name = app_name
|
12
|
-
@resources = resources
|
13
|
-
end
|
14
|
-
|
15
|
-
def gem_name
|
16
|
-
@gem_name_snake ||= "#{app_name.underscore}_client"
|
17
|
-
end
|
18
|
-
|
19
|
-
def gem_name_snake
|
20
|
-
gem_name
|
21
|
-
end
|
22
|
-
|
23
|
-
def gem_name_pascal
|
24
|
-
@gem_name_pascal ||= gem_name.camelize(:upper)
|
25
|
-
end
|
26
|
-
|
27
|
-
def copyright_year
|
28
|
-
@copyright_year ||= Time.now.year
|
29
|
-
end
|
30
|
-
|
31
|
-
def copyright_owner
|
32
|
-
@copyright_owner ||= "YOUR_NAME_HERE"
|
33
|
-
end
|
34
|
-
|
35
|
-
def twine
|
36
|
-
binding
|
37
|
-
end
|
38
|
-
end
|
39
|
-
|
40
|
-
class ResourceState
|
41
|
-
attr_reader :resource_name, :gem_name_pascal
|
42
|
-
|
43
|
-
def initialize(resource_name, gem_name_pascal)
|
44
|
-
@resource_name = resource_name
|
45
|
-
@gem_name_pascal = gem_name_pascal
|
46
|
-
end
|
47
|
-
|
48
|
-
def twine
|
49
|
-
binding
|
50
|
-
end
|
51
|
-
end
|
52
|
-
|
53
|
-
attr_reader :app_name
|
54
|
-
|
55
|
-
def initialize(app_name, schema_path, output_path)
|
56
|
-
@state = State.new(app_name)
|
57
|
-
@schema_path = schema_path
|
11
|
+
def initialize(app_config, output_path)
|
12
|
+
@state = Gutsy::Generator::GemState.new(app_config)
|
58
13
|
@output_path = output_path
|
59
14
|
end
|
60
15
|
|
61
16
|
def generate!
|
62
17
|
create_output_dir
|
63
18
|
|
64
|
-
|
65
|
-
|
66
|
-
state.resources = map_schema_to_resources(schema)
|
67
|
-
|
68
|
-
scaffold_gem
|
69
|
-
|
70
|
-
generate_heroics_client
|
19
|
+
build_gem
|
71
20
|
|
72
21
|
puts "Generated client gem can be found in... #{output_path}"
|
73
22
|
end
|
74
23
|
|
75
24
|
private
|
76
25
|
|
77
|
-
attr_reader :state, :
|
78
|
-
attr_accessor :schema
|
26
|
+
attr_reader :state, :output_path
|
79
27
|
def_delegators :state, :app_name, :gem_name_snake, :gem_name_pascal
|
80
28
|
|
81
29
|
def create_output_dir
|
@@ -84,43 +32,35 @@ module Gutsy
|
|
84
32
|
puts "OK"
|
85
33
|
end
|
86
34
|
|
87
|
-
def
|
88
|
-
print "
|
89
|
-
|
90
|
-
draft04 = JsonSchema.parse!(JSON.parse(draft04_uri.read))
|
91
|
-
|
92
|
-
schema_json = JSON.parse(File.read(schema_path))
|
93
|
-
|
94
|
-
schema = JsonSchema.parse!(schema_json)
|
95
|
-
schema.expand_references!
|
96
|
-
|
97
|
-
draft04.validate!(schema)
|
35
|
+
def build_gem
|
36
|
+
print "Creating gem directory structure..."
|
37
|
+
build_gem_directory_tree
|
98
38
|
puts "OK"
|
99
39
|
|
100
|
-
|
101
|
-
|
40
|
+
print "Creating gem metadata..."
|
41
|
+
generate_gem_metadata
|
42
|
+
puts "OK"
|
102
43
|
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
link.schema.expand_references! if link.schema
|
107
|
-
properties = link.schema.try(:properties) || {}
|
108
|
-
[link.title.downcase.to_sym, OpenStruct.new(properties: properties)]
|
109
|
-
end]
|
110
|
-
[key.to_sym, OpenStruct.new(title: key.camelize, links: links)]
|
111
|
-
end]
|
112
|
-
resources
|
44
|
+
print "Generating API clients for each API version..."
|
45
|
+
generate_api_clients
|
46
|
+
puts "OK"
|
113
47
|
end
|
114
48
|
|
115
|
-
def
|
116
|
-
|
117
|
-
template_dirs.each do |dir|
|
49
|
+
def build_gem_directory_tree
|
50
|
+
template_dirs.flat_map do |dir|
|
118
51
|
dir = dir.gsub('app_client', gem_name_snake)
|
52
|
+
if dir =~ /api_version/
|
53
|
+
state.api_versions.map { |v| dir.gsub('api_version', v.name) }
|
54
|
+
else
|
55
|
+
[dir]
|
56
|
+
end
|
57
|
+
end.each do |dir|
|
119
58
|
dir_path = File.join(output_path, dir)
|
120
59
|
Dir.mkdir(dir_path, 0755) unless Dir.exist?(dir_path)
|
121
60
|
end
|
122
|
-
|
61
|
+
end
|
123
62
|
|
63
|
+
def generate_gem_metadata
|
124
64
|
[
|
125
65
|
".gitignore",
|
126
66
|
"Gemfile",
|
@@ -131,34 +71,32 @@ module Gutsy
|
|
131
71
|
copy_file file
|
132
72
|
end
|
133
73
|
|
134
|
-
copy_file "app_client.gemspec",
|
135
|
-
|
74
|
+
copy_file "app_client.gemspec", as: "#{gem_name_snake}.gemspec"
|
75
|
+
copy_file "lib/app_client.rb", as: "lib/#{gem_name_snake}.rb"
|
76
|
+
copy_file "lib/app_client/version.rb", as: "lib/#{gem_name_snake}/version.rb"
|
77
|
+
end
|
136
78
|
|
137
|
-
|
138
|
-
|
79
|
+
def generate_api_clients
|
80
|
+
state.api_versions.each do |api_version|
|
81
|
+
copy_file "lib/app_client/api_version/adapter.rb",
|
82
|
+
as: "lib/#{gem_name_snake}/#{api_version.name}/adapter.rb",
|
83
|
+
binding: api_version.twine
|
139
84
|
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
85
|
+
api_version.resources.each do |key, resource|
|
86
|
+
resource_state = Gutsy::Generator::ResourceState.new(key.to_s, api_version)
|
87
|
+
|
88
|
+
copy_file "lib/app_client/api_version/resource.rb",
|
89
|
+
as: "lib/#{gem_name_snake}/#{api_version.name}/#{key.to_s.underscore}.rb",
|
90
|
+
binding: resource_state.twine
|
91
|
+
end
|
147
92
|
|
148
|
-
|
149
|
-
copy_file "lib/app_client/v1/resource.rb",
|
150
|
-
as: "lib/#{gem_name_snake}/v1/#{key.to_s.underscore}.rb",
|
151
|
-
binding: ResourceState.new(key.to_s, gem_name_pascal).twine
|
93
|
+
generate_heroics_client(api_version)
|
152
94
|
end
|
153
95
|
end
|
154
96
|
|
155
|
-
def generate_heroics_client
|
156
|
-
print "Generating Heroics client for JSON Schema..."
|
157
|
-
unless
|
158
|
-
#{gem_name_pascal}::V1::Adapters::Http \
|
159
|
-
#{schema_path} \
|
160
|
-
http://#{app_name.downcase}/api/v1 > \
|
161
|
-
#{output_path}/lib/#{gem_name_snake}/v1/adapters/http.rb"
|
97
|
+
def generate_heroics_client(api_version)
|
98
|
+
print "Generating Heroics client for #{api_version.name} JSON Schema..."
|
99
|
+
unless Gutsy::Generator::Heroics.generate(api_version, output_path)
|
162
100
|
puts "FAIL"
|
163
101
|
puts "Please see stacktrace or heroics errors"
|
164
102
|
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module Gutsy
|
2
|
+
module Generator
|
3
|
+
class ApiVersionState
|
4
|
+
extend Forwardable
|
5
|
+
|
6
|
+
attr_reader :name, :schema, :schema_path
|
7
|
+
|
8
|
+
def_delegators :gem_state, :gem_name_pascal, :gem_name_snake, :app_name, :base_url
|
9
|
+
|
10
|
+
def initialize(api_version_config, gem_state)
|
11
|
+
@name = api_version_config[:name]
|
12
|
+
@schema_path = api_version_config[:schema_path]
|
13
|
+
@gem_state = gem_state
|
14
|
+
end
|
15
|
+
|
16
|
+
def module_name
|
17
|
+
@module_name ||= name.upcase
|
18
|
+
end
|
19
|
+
|
20
|
+
def schema
|
21
|
+
@schema ||= Gutsy::Schema.load_from_file!(schema_path)
|
22
|
+
end
|
23
|
+
|
24
|
+
def resources
|
25
|
+
schema.resources
|
26
|
+
end
|
27
|
+
|
28
|
+
def twine
|
29
|
+
binding
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
attr_reader :gem_state
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
module Gutsy
|
2
|
+
module Generator
|
3
|
+
class GemState
|
4
|
+
attr_reader :app_name, :base_url, :description
|
5
|
+
|
6
|
+
def initialize(app_config)
|
7
|
+
@app_name = app_config[:name]
|
8
|
+
@base_url = app_config[:base_url]
|
9
|
+
@description = app_config[:description]
|
10
|
+
@app_config = app_config
|
11
|
+
end
|
12
|
+
|
13
|
+
def api_versions
|
14
|
+
@api_versions ||= app_config[:versions].map do |api_version_config|
|
15
|
+
Gutsy::Generator::ApiVersionState.new(api_version_config, self)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def gem_name
|
20
|
+
@gem_name_snake ||= "#{app_name.underscore}_client"
|
21
|
+
end
|
22
|
+
|
23
|
+
def gem_name_snake
|
24
|
+
gem_name
|
25
|
+
end
|
26
|
+
|
27
|
+
def gem_name_pascal
|
28
|
+
@gem_name_pascal ||= gem_name.camelize(:upper)
|
29
|
+
end
|
30
|
+
|
31
|
+
def gem_version
|
32
|
+
@gem_version ||= app_config[:gem_version] || '0.1.0'
|
33
|
+
end
|
34
|
+
|
35
|
+
def copyright_year
|
36
|
+
@copyright_year ||= Time.now.year
|
37
|
+
end
|
38
|
+
|
39
|
+
def copyright_owner
|
40
|
+
@copyright_owner ||= author.name
|
41
|
+
end
|
42
|
+
|
43
|
+
def author
|
44
|
+
@author ||= OpenStruct.new(author_config)
|
45
|
+
end
|
46
|
+
|
47
|
+
def twine
|
48
|
+
binding
|
49
|
+
end
|
50
|
+
|
51
|
+
private
|
52
|
+
|
53
|
+
attr_reader :app_config
|
54
|
+
|
55
|
+
def author_config
|
56
|
+
app_config[:author] || {
|
57
|
+
name: "YOUR_NAME_HERE",
|
58
|
+
email: "YOUR_EMAIL_ADDRESS",
|
59
|
+
github: "GITHUB_USER"
|
60
|
+
}
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module Gutsy
|
2
|
+
module Generator
|
3
|
+
class Heroics
|
4
|
+
def self.generate(api_version_state, output_path)
|
5
|
+
new(api_version_state, output_path).generate
|
6
|
+
end
|
7
|
+
|
8
|
+
def initialize(api_version_state, output_path)
|
9
|
+
@api_version_state = api_version_state
|
10
|
+
@output_path = output_path
|
11
|
+
end
|
12
|
+
|
13
|
+
def generate
|
14
|
+
system "heroics-generate \
|
15
|
+
#{module_name} \
|
16
|
+
#{api_version_state.schema_path} \
|
17
|
+
#{api_url} > \
|
18
|
+
#{client_output_path}"
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
attr_reader :api_version_state, :output_path
|
24
|
+
|
25
|
+
def module_name
|
26
|
+
@module_name ||= "#{api_version_state.gem_name_pascal}::#{api_version_state.module_name}::Adapters::Http"
|
27
|
+
end
|
28
|
+
|
29
|
+
def api_url
|
30
|
+
@api_url ||= "#{api_version_state.base_url}/api/#{api_version_state.name.downcase}"
|
31
|
+
end
|
32
|
+
|
33
|
+
def client_output_path
|
34
|
+
@client_output_path ||= "#{output_path}/lib/#{api_version_state.gem_name_snake}/#{api_version_state.name.downcase}/adapters/http.rb"
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Gutsy
|
2
|
+
module Generator
|
3
|
+
class ResourceState
|
4
|
+
extend Forwardable
|
5
|
+
|
6
|
+
attr_reader :resource_name
|
7
|
+
def_delegators :version_state, :gem_name_pascal, :app_name, :module_name
|
8
|
+
|
9
|
+
def initialize(resource_name, version_state)
|
10
|
+
@resource_name = resource_name
|
11
|
+
@version_state = version_state
|
12
|
+
end
|
13
|
+
|
14
|
+
def twine
|
15
|
+
binding
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
attr_reader :version_state
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
data/lib/gutsy/schema.rb
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
module Gutsy
|
2
|
+
class Schema
|
3
|
+
def self.load_from_file!(schema_path)
|
4
|
+
draft04_uri = URI.parse("http://json-schema.org/draft-04/hyper-schema")
|
5
|
+
draft04 = JsonSchema.parse!(JSON.parse(draft04_uri.read))
|
6
|
+
|
7
|
+
schema_json = JSON.parse(File.read(schema_path))
|
8
|
+
|
9
|
+
schema = JsonSchema.parse!(schema_json)
|
10
|
+
schema.expand_references!
|
11
|
+
|
12
|
+
draft04.validate!(schema)
|
13
|
+
|
14
|
+
new(schema)
|
15
|
+
end
|
16
|
+
|
17
|
+
def initialize(json_schema)
|
18
|
+
@schema = json_schema
|
19
|
+
end
|
20
|
+
|
21
|
+
def resources
|
22
|
+
@resources ||= Hash[schema.definitions.map do |key, resource|
|
23
|
+
links = Hash[resource.links.map do |link|
|
24
|
+
link.schema.expand_references! if link.schema
|
25
|
+
properties = link.schema.try(:properties) || {}
|
26
|
+
[link.title.downcase.to_sym, OpenStruct.new(properties: properties)]
|
27
|
+
end]
|
28
|
+
[key.to_sym, OpenStruct.new(title: key.camelize, links: links)]
|
29
|
+
end]
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
attr_reader :schema
|
35
|
+
end
|
36
|
+
end
|
data/lib/gutsy/version.rb
CHANGED
@@ -1,14 +1,19 @@
|
|
1
1
|
# <%= app_name %> Ruby Client
|
2
2
|
|
3
|
+
<% if description -%>
|
4
|
+
<%= description -%>
|
5
|
+
<% else -%>
|
3
6
|
<%= app_name %> is an application that does things. This gem provides a wrapper around an HTTP Client generated from <%= app_name %>'s JSON Schema using [heroics](https://github.com/interagent/heroics).
|
4
|
-
|
7
|
+
<% end -%>
|
5
8
|
|
6
9
|
## Usage
|
7
10
|
|
8
11
|
Add this to your Gemfile
|
9
12
|
|
10
13
|
```
|
11
|
-
gem '<%= gem_name_snake %>'
|
14
|
+
gem '<%= gem_name_snake %>', git: 'git@github.com:<%= author.github %>/<%= gem_name_snake %>.git', tag: 'v<%= gem_version %>'
|
15
|
+
# or, depending on how cool your API is...
|
16
|
+
gem '<%= gem_name_snake %>', '~> <%= gem_version %>'
|
12
17
|
```
|
13
18
|
|
14
19
|
### Rails Setup
|
@@ -17,11 +22,11 @@ gem '<%= gem_name_snake %>' #, git: 'git@github.com:USER/REPO.git', tag: 'v0.1.0
|
|
17
22
|
|
18
23
|
```ruby
|
19
24
|
<%= gem_name_pascal %>.configure do |config|
|
20
|
-
config.base_url = "
|
21
|
-
config.api_key = "i-am-api-user"
|
22
|
-
config.api_secret = "very-secret-sssshhh"
|
25
|
+
config.base_url = "<%= base_url %>"
|
26
|
+
config.api_key = "i-am-api-user" # HTTP Basic Auth User
|
27
|
+
config.api_secret = "very-secret-sssshhh" # HTTP Basic Auth Pass
|
23
28
|
# or OAuth access token
|
24
|
-
# config.access_token =
|
29
|
+
# config.access_token = ENV['<%= gem_name_snake.upcase %>_ACCESS_TOKEN']
|
25
30
|
end
|
26
31
|
```
|
27
32
|
|
@@ -47,14 +52,16 @@ class SomeResourceLister
|
|
47
52
|
end
|
48
53
|
```
|
49
54
|
|
50
|
-
|
55
|
+
# API
|
51
56
|
|
52
57
|
All Client and Resource API methods return an Object mirroring the JSON response of the <%= app_name.capitalize %> API call, with the added method `ok?`, indicating whether the call was a success (`2xx`), or whether the call was invalid (`422`). Other failures will raise an `Excon::Errors::Error` such as an `Excon::Errors::HTTPStatusError`.
|
53
58
|
|
54
59
|
The methods supported by each Resource API are generated by heroics and are determined by the JSON schema. In most cases, the Resource APIs found in `lib/<%= gem_name_snake %>` just proxy method calls to the API adapter (by default the heroics-generated API adapter).
|
55
60
|
|
56
|
-
<%
|
61
|
+
<% api_versions.each do |api_version| %>
|
62
|
+
## <%= app_name %> API <%= api_version.name %>
|
57
63
|
|
64
|
+
<% api_version.resources.each do |key, resource| -%>
|
58
65
|
### <%= resource.title.camelize %>
|
59
66
|
|
60
67
|
#### `::new(client=nil, access_token: nil, api_key: nil, api_secret: nil, options: {})`
|
@@ -88,4 +95,5 @@ Called with no arguments, `client` defaults to a newly created heroics client in
|
|
88
95
|
<% end -%>
|
89
96
|
<% end -%>
|
90
97
|
<% end -%>
|
98
|
+
<% end -%>
|
91
99
|
<% end -%>
|
@@ -5,10 +5,16 @@ require "./lib/<%= gem_name_snake %>/version"
|
|
5
5
|
Gem::Specification.new do |s|
|
6
6
|
s.name = '<%= gem_name_snake %>'
|
7
7
|
s.version = <%= gem_name_pascal %>::VERSION
|
8
|
-
s.authors = ["
|
9
|
-
s.email = "author
|
8
|
+
s.authors = ["<%= author.name %>"]
|
9
|
+
s.email = "<%= author.email %>"
|
10
10
|
s.summary = "Gutsy-generated gem for <%= app_name %> client"
|
11
|
+
<% if description -%>
|
12
|
+
s.description = <<-DESCRIPTION
|
13
|
+
<%= description -%>
|
14
|
+
DESCRIPTION
|
15
|
+
<% else -%>
|
11
16
|
s.description = "<%= app_name %> API client generated by gutsy from JSON Schema"
|
17
|
+
<% end -%>
|
12
18
|
|
13
19
|
s.files = `git ls-files`.split "\n"
|
14
20
|
s.test_files = `git ls-files -- {test,spec,features}/*`.split "\n"
|
@@ -1,6 +1,14 @@
|
|
1
|
+
#
|
2
|
+
# HEADS UP: Do not edit by hand (or do, I'm not your parent)
|
3
|
+
# This file was generated by Gutsy:
|
4
|
+
# https://github.com/IoraHealth/gutsy
|
5
|
+
#
|
6
|
+
|
1
7
|
require 'multi_json'
|
2
8
|
require 'recursive-open-struct'
|
3
|
-
|
9
|
+
<% api_versions.each do |version| -%>
|
10
|
+
require '<%= gem_name_snake %>/<%= version.name %>/adapter'
|
11
|
+
<% end -%>
|
4
12
|
|
5
13
|
Dir.glob(File.join(File.dirname(__FILE__), "<%= gem_name_snake %>", '**', '*.rb')).each do |file|
|
6
14
|
require file
|
@@ -16,7 +24,7 @@ module <%= gem_name_pascal %>
|
|
16
24
|
#
|
17
25
|
# @example
|
18
26
|
# <%= gem_name_pascal %>.configure do |config|
|
19
|
-
# config.base_url = '
|
27
|
+
# config.base_url = '<%= base_url %>'
|
20
28
|
# # Specify credentials for OAuth browser-flow
|
21
29
|
# config.access_token = 'randomness'
|
22
30
|
# # or server-side flow
|
@@ -38,7 +46,7 @@ module <%= gem_name_pascal %>
|
|
38
46
|
end
|
39
47
|
|
40
48
|
def api_version
|
41
|
-
@api_version ||= '
|
49
|
+
@api_version ||= '<%= api_versions.first.name %>'
|
42
50
|
end
|
43
51
|
|
44
52
|
def api_version=(version)
|
@@ -1,5 +1,11 @@
|
|
1
|
+
#
|
2
|
+
# HEADS UP: Do not edit by hand (or do, I'm not your parent)
|
3
|
+
# This file was generated by Gutsy:
|
4
|
+
# https://github.com/IoraHealth/gutsy
|
5
|
+
#
|
6
|
+
|
1
7
|
module <%= gem_name_pascal %>
|
2
|
-
module
|
8
|
+
module <%= module_name %>
|
3
9
|
# Empty namespace, needed for heroics-generated HTTP client
|
4
10
|
module Adapters; end
|
5
11
|
|
@@ -25,7 +31,7 @@ module <%= gem_name_pascal %>
|
|
25
31
|
user: config.api_key
|
26
32
|
}))
|
27
33
|
else
|
28
|
-
raise
|
34
|
+
raise "access_token or API key & secret are required to connect to <%= app_name %> <%= module_name %> API"
|
29
35
|
end
|
30
36
|
end
|
31
37
|
end
|
@@ -42,7 +48,7 @@ module <%= gem_name_pascal %>
|
|
42
48
|
|
43
49
|
RecursiveOpenStruct.new(response, recurse_over_arrays: true)
|
44
50
|
else
|
45
|
-
raise NoMethodError.new("'#{resource_name}' API adapter '#{to_s}' does not respond to ##{name}")
|
51
|
+
raise NoMethodError.new("<%= app_name %> <%= module_name%> '#{resource_name}' API adapter '#{to_s}' does not respond to ##{name}")
|
46
52
|
end
|
47
53
|
end
|
48
54
|
|
File without changes
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: gutsy
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 1.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Iora Health
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2017-02-14 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: heroics
|
@@ -105,6 +105,7 @@ files:
|
|
105
105
|
- ".gitignore"
|
106
106
|
- ".rspec"
|
107
107
|
- ".travis.yml"
|
108
|
+
- CHANGELOG.md
|
108
109
|
- CODE_OF_CONDUCT.md
|
109
110
|
- Gemfile
|
110
111
|
- Gemfile.lock
|
@@ -114,10 +115,17 @@ files:
|
|
114
115
|
- bin/console
|
115
116
|
- bin/gutsy
|
116
117
|
- bin/setup
|
118
|
+
- examples/config.yml
|
117
119
|
- gutsy.gemspec
|
118
120
|
- lib/gutsy.rb
|
119
121
|
- lib/gutsy/cli.rb
|
122
|
+
- lib/gutsy/configuration.rb
|
120
123
|
- lib/gutsy/generator.rb
|
124
|
+
- lib/gutsy/generator/api_version_state.rb
|
125
|
+
- lib/gutsy/generator/gem_state.rb
|
126
|
+
- lib/gutsy/generator/heroics.rb
|
127
|
+
- lib/gutsy/generator/resource_state.rb
|
128
|
+
- lib/gutsy/schema.rb
|
121
129
|
- lib/gutsy/version.rb
|
122
130
|
- templates/app_client/.gitignore.erb
|
123
131
|
- templates/app_client/Gemfile.erb
|
@@ -126,9 +134,9 @@ files:
|
|
126
134
|
- templates/app_client/Rakefile.erb
|
127
135
|
- templates/app_client/app_client.gemspec.erb
|
128
136
|
- templates/app_client/lib/app_client.rb.erb
|
129
|
-
- templates/app_client/lib/app_client/
|
130
|
-
- templates/app_client/lib/app_client/
|
131
|
-
- templates/app_client/lib/app_client/
|
137
|
+
- templates/app_client/lib/app_client/api_version/adapter.rb.erb
|
138
|
+
- templates/app_client/lib/app_client/api_version/adapters/.gitkeep
|
139
|
+
- templates/app_client/lib/app_client/api_version/resource.rb.erb
|
132
140
|
- templates/app_client/lib/app_client/version.rb.erb
|
133
141
|
homepage: https://github.com/IoraHealth/gutsy
|
134
142
|
licenses:
|