graphql-rails-schemaker 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/.gitignore +9 -0
- data/CODE_OF_CONDUCT.md +74 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +21 -0
- data/README.md +29 -0
- data/Rakefile +2 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/graphql-rails-schemaker.gemspec +28 -0
- data/lib/.DS_Store +0 -0
- data/lib/graphql/rails/.DS_Store +0 -0
- data/lib/graphql/rails/schemaker.rb +12 -0
- data/lib/graphql/rails/schemaker/camel_case_middleware.erb +36 -0
- data/lib/graphql/rails/schemaker/enum_type.erb +12 -0
- data/lib/graphql/rails/schemaker/mutation_type.erb +6 -0
- data/lib/graphql/rails/schemaker/object_type.erb +71 -0
- data/lib/graphql/rails/schemaker/query_type.erb +13 -0
- data/lib/graphql/rails/schemaker/railtie.rb +11 -0
- data/lib/graphql/rails/schemaker/schema.erb +24 -0
- data/lib/graphql/rails/schemaker/template_renderer.rb +19 -0
- data/lib/graphql/rails/schemaker/union_type.erb +5 -0
- data/lib/graphql/rails/schemaker/version.rb +7 -0
- data/lib/tasks/schemaker.rake +569 -0
- metadata +109 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: dee18b3ddc12dcfeb8a5af7efff3f9bda49765c5
|
4
|
+
data.tar.gz: 11d353b219a8bd9578c45e6d00de5e924964f555
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 8794d320f62f775543c675587177250f0e00af3c7154cf50ff530c279d26c4c89d437c573c63d3fbd021b5776db6bf1a307c6e7e7d539d43f6dbd29305dbd0d3
|
7
|
+
data.tar.gz: 9bedf41247e193fd0ef9ee5f2922c2d39cbfbb5553baca88f37935dd8c5017326b99bc60a5a7953cdef70692ce528e2fce31b5ae97d3fd2b4b38baec09ac478c
|
data/.gitignore
ADDED
data/CODE_OF_CONDUCT.md
ADDED
@@ -0,0 +1,74 @@
|
|
1
|
+
# Contributor Covenant Code of Conduct
|
2
|
+
|
3
|
+
## Our Pledge
|
4
|
+
|
5
|
+
In the interest of fostering an open and welcoming environment, we as
|
6
|
+
contributors and maintainers pledge to making participation in our project and
|
7
|
+
our community a harassment-free experience for everyone, regardless of age, body
|
8
|
+
size, disability, ethnicity, gender identity and expression, level of experience,
|
9
|
+
nationality, personal appearance, race, religion, or sexual identity and
|
10
|
+
orientation.
|
11
|
+
|
12
|
+
## Our Standards
|
13
|
+
|
14
|
+
Examples of behavior that contributes to creating a positive environment
|
15
|
+
include:
|
16
|
+
|
17
|
+
* Using welcoming and inclusive language
|
18
|
+
* Being respectful of differing viewpoints and experiences
|
19
|
+
* Gracefully accepting constructive criticism
|
20
|
+
* Focusing on what is best for the community
|
21
|
+
* Showing empathy towards other community members
|
22
|
+
|
23
|
+
Examples of unacceptable behavior by participants include:
|
24
|
+
|
25
|
+
* The use of sexualized language or imagery and unwelcome sexual attention or
|
26
|
+
advances
|
27
|
+
* Trolling, insulting/derogatory comments, and personal or political attacks
|
28
|
+
* Public or private harassment
|
29
|
+
* Publishing others' private information, such as a physical or electronic
|
30
|
+
address, without explicit permission
|
31
|
+
* Other conduct which could reasonably be considered inappropriate in a
|
32
|
+
professional setting
|
33
|
+
|
34
|
+
## Our Responsibilities
|
35
|
+
|
36
|
+
Project maintainers are responsible for clarifying the standards of acceptable
|
37
|
+
behavior and are expected to take appropriate and fair corrective action in
|
38
|
+
response to any instances of unacceptable behavior.
|
39
|
+
|
40
|
+
Project maintainers have the right and responsibility to remove, edit, or
|
41
|
+
reject comments, commits, code, wiki edits, issues, and other contributions
|
42
|
+
that are not aligned to this Code of Conduct, or to ban temporarily or
|
43
|
+
permanently any contributor for other behaviors that they deem inappropriate,
|
44
|
+
threatening, offensive, or harmful.
|
45
|
+
|
46
|
+
## Scope
|
47
|
+
|
48
|
+
This Code of Conduct applies both within project spaces and in public spaces
|
49
|
+
when an individual is representing the project or its community. Examples of
|
50
|
+
representing a project or community include using an official project e-mail
|
51
|
+
address, posting via an official social media account, or acting as an appointed
|
52
|
+
representative at an online or offline event. Representation of a project may be
|
53
|
+
further defined and clarified by project maintainers.
|
54
|
+
|
55
|
+
## Enforcement
|
56
|
+
|
57
|
+
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
58
|
+
reported by contacting the project team at turner.cole@gmail.com. All
|
59
|
+
complaints will be reviewed and investigated and will result in a response that
|
60
|
+
is deemed necessary and appropriate to the circumstances. The project team is
|
61
|
+
obligated to maintain confidentiality with regard to the reporter of an incident.
|
62
|
+
Further details of specific enforcement policies may be posted separately.
|
63
|
+
|
64
|
+
Project maintainers who do not follow or enforce the Code of Conduct in good
|
65
|
+
faith may face temporary or permanent repercussions as determined by other
|
66
|
+
members of the project's leadership.
|
67
|
+
|
68
|
+
## Attribution
|
69
|
+
|
70
|
+
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
|
71
|
+
available at [http://contributor-covenant.org/version/1/4][version]
|
72
|
+
|
73
|
+
[homepage]: http://contributor-covenant.org
|
74
|
+
[version]: http://contributor-covenant.org/version/1/4/
|
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2016 Cole Turner
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
# graphql-rails-schemaker
|
2
|
+
A rake task to interactive create a GraphQL Schema for Rails Models.
|
3
|
+
|
4
|
+
## To generate a base schema:
|
5
|
+
- Run "rails graphql:generate"
|
6
|
+
- When prompted, enter "c" or "s" for camel case or snake case output respectively.
|
7
|
+
- Follow the prompts to generate the schema.
|
8
|
+
|
9
|
+
|
10
|
+
### Word of Caution
|
11
|
+
This tool is designed to facilitate setup of a GraphQL Schema in Rails 5 Application. It has not been tested in any prior verison of Rails. This task will not run it if detects a previous setup @ `./app/graph/schema.rb` It will overwrite any files in `./app/graph/` if no `schema.rb` exists.
|
12
|
+
|
13
|
+
GraphQL Rails Schemaker is not a one-size-fits all solution. It will create a "base" schema including object types and sub-type dependencies from all models existing in the Rails application. It has been designed to formulate a generic schema to fit a wide variety of applications with support for associations.
|
14
|
+
|
15
|
+
**Do not run this in production environments.**
|
16
|
+
|
17
|
+
|
18
|
+
# Todo
|
19
|
+
- Generate Enum and Union Types
|
20
|
+
- Add Input Type templates
|
21
|
+
- Add Mutation Type templates
|
22
|
+
- Integration with `graphql-rails-resolver` (if installed)
|
23
|
+
|
24
|
+
## Needs Help
|
25
|
+
The `object_type.rb` template is large and cumbersome. The Todo above is planned for action. If you would like to handle any of the above, please file a pull request and add your name to the credits list.
|
26
|
+
|
27
|
+
|
28
|
+
## Credits
|
29
|
+
Cole Turner (http://cole.codes/)
|
data/Rakefile
ADDED
data/bin/console
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/setup"
|
4
|
+
require "graphql/rails/schemaker"
|
5
|
+
|
6
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
7
|
+
# with your gem easier. You can also use a different console, if you like.
|
8
|
+
|
9
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
10
|
+
# require "pry"
|
11
|
+
# Pry.start
|
12
|
+
|
13
|
+
require "irb"
|
14
|
+
IRB.start
|
data/bin/setup
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'graphql/rails/schemaker/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "graphql-rails-schemaker"
|
8
|
+
spec.version = Graphql::Rails::Schemaker::VERSION
|
9
|
+
spec.date = Date.today.to_s
|
10
|
+
spec.authors = ["Cole Turner"]
|
11
|
+
spec.email = ["turner.cole@gmail.com"]
|
12
|
+
|
13
|
+
spec.summary = ""
|
14
|
+
spec.homepage = "https://github.com/colepatrickturner/graphql-rails-schemaker"
|
15
|
+
spec.license = "MIT"
|
16
|
+
|
17
|
+
spec.files = `git ls-files -z`.split("\x0").reject do |f|
|
18
|
+
f.match(%r{^(test|spec|features)/})
|
19
|
+
end
|
20
|
+
spec.bindir = "exe"
|
21
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
22
|
+
spec.require_paths = ["lib"]
|
23
|
+
|
24
|
+
spec.add_runtime_dependency "graphql", ">= 0.19.0"
|
25
|
+
spec.add_development_dependency "bundler", "~> 1.13"
|
26
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
27
|
+
spec.required_ruby_version = '>= 2.2.2'
|
28
|
+
end
|
data/lib/.DS_Store
ADDED
Binary file
|
Binary file
|
@@ -0,0 +1,36 @@
|
|
1
|
+
class CamelCaseMiddleware
|
2
|
+
def call(parent_type, parent_object, field_definition, field_args, query_context, next_middleware)
|
3
|
+
next_middleware.call([parent_type, parent_object, field_definition, transform_arguments(field_args), query_context])
|
4
|
+
end
|
5
|
+
|
6
|
+
def transform_arguments(field_args)
|
7
|
+
transformed_args = {}
|
8
|
+
types = {}
|
9
|
+
|
10
|
+
field_args.each_value do |arg_value|
|
11
|
+
key = arg_value.key.to_s
|
12
|
+
unless key == "clientMutationId"
|
13
|
+
key = key.underscore
|
14
|
+
end
|
15
|
+
|
16
|
+
transformed_args[key] = transform_value(arg_value.value)
|
17
|
+
types[key] = arg_value.definition
|
18
|
+
end
|
19
|
+
|
20
|
+
GraphQL::Query::Arguments.new(transformed_args, argument_definitions: types)
|
21
|
+
end
|
22
|
+
|
23
|
+
def transform_value(value)
|
24
|
+
case value
|
25
|
+
when Array
|
26
|
+
value.map { |v| transform_value(v) }
|
27
|
+
when Hash
|
28
|
+
Hash[value.map { |k, v| [underscore_key(k), convert_hash_keys(v)] }]
|
29
|
+
when GraphQL::Query::Arguments
|
30
|
+
transform_arguments(value)
|
31
|
+
else
|
32
|
+
value
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
<%=name%>Enum = GraphQL::EnumType.define do
|
2
|
+
name "<%=name%>"
|
3
|
+
description "Enumerated values for <%=name%>"
|
4
|
+
|
5
|
+
<%
|
6
|
+
values.each do |key,value|
|
7
|
+
-%>
|
8
|
+
value(<%=key.inspect%>, <%="Value of \"#{value}\"".inspect%>, value: <%=value.inspect%>)
|
9
|
+
<%
|
10
|
+
end
|
11
|
+
-%>
|
12
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
<%=model.name%>Type = GraphQL::ObjectType.define do
|
2
|
+
name "<%=model.name%>"
|
3
|
+
description "Type for <%=model.name%> object"
|
4
|
+
|
5
|
+
interfaces [::GraphQL::Relay::Node.interface]
|
6
|
+
|
7
|
+
<%
|
8
|
+
attributes.each do |name, attribute|
|
9
|
+
association = nil
|
10
|
+
|
11
|
+
if attribute.key? :association
|
12
|
+
association = attribute[:association]
|
13
|
+
elsif model.respond_to? :reflect_on_all_associations
|
14
|
+
|
15
|
+
end
|
16
|
+
|
17
|
+
if model.respond_to? :primary_key and name.to_s == model.primary_key
|
18
|
+
-%>
|
19
|
+
global_id_field :<%=name%>
|
20
|
+
<%
|
21
|
+
elsif association.present?
|
22
|
+
if association.polymorphic?
|
23
|
+
object_model = association.active_record
|
24
|
+
else
|
25
|
+
object_model = association.klass
|
26
|
+
end
|
27
|
+
|
28
|
+
if association.collection?
|
29
|
+
list_or_connection = nil
|
30
|
+
while list_or_connection.nil?
|
31
|
+
STDOUT.puts "Should many type `\e[32m#{name}\e[0m` on \e[32m#{model.name}\e[0m be a list or connection? (\e[34ml = list \e[39m| \e[32mc = connection \e[39m| \e[93msh = help\e[39m)."
|
32
|
+
command = STDIN.gets.chomp.downcase
|
33
|
+
case command
|
34
|
+
when "c", "g"
|
35
|
+
list_or_connection = :connection
|
36
|
+
when "l"
|
37
|
+
list_or_connection = :list
|
38
|
+
when "h"
|
39
|
+
STDOUT.puts "Lists return all objects in the association. Use connections if pagination is necessary."
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
if list_or_connection == :connection
|
44
|
+
-%>
|
45
|
+
connection :<%=association.plural_name%>, <%=object_model.is_a?(model) or object_model == model ? "-> { " : ""%><%=object_model%>Type<%=association.polymorphic? ? "Union" : ""%>.connection_type<%=object_model.is_a?(model) or object_model == model ? " }" : ""%>, "Association to many `<%=association.plural_name%>` on <%=model.name%>"
|
46
|
+
<%
|
47
|
+
else
|
48
|
+
-%>
|
49
|
+
field :<%=association.plural_name%>, <%=object_model.is_a?(model) or object_model == model ? "-> { " : ""%><%=object_model%>Type<%=association.polymorphic? ? "Union" : ""%>.to_list_type<%=object_model.is_a?(model) or object_model == model ? " }" : ""%>, "Association to many `<%=association.plural_name%>` on <%=model.name%>"
|
50
|
+
<%
|
51
|
+
end
|
52
|
+
else
|
53
|
+
-%>
|
54
|
+
field :<%=association.name%>, <%=object_model.is_a?(model) or object_model == model ? "-> { " : ""%><%=object_model%>Type<%=association.polymorphic? ? "Union" : ""%><%=object_model.is_a?(model) or object_model == model ? " }" : ""%>, "Association to one `<%=association.name%>` on <%=model.name%>"
|
55
|
+
<%
|
56
|
+
end
|
57
|
+
else
|
58
|
+
type_str =
|
59
|
+
if attribute.key? :type and attribute[:type].present?
|
60
|
+
attribute[:type]
|
61
|
+
else
|
62
|
+
"types.String"
|
63
|
+
end
|
64
|
+
|
65
|
+
-%>
|
66
|
+
field :<%=name%>, <%=type_str%>, "Property `<%=attribute[:property]%>` for <%=model.name%>"<%=attribute[:property].to_s != name.to_s ? ", property: :#{attribute[:property]}" : ""%>
|
67
|
+
<%
|
68
|
+
end
|
69
|
+
end
|
70
|
+
%>
|
71
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
<%= query_type_name %> = GraphQL::ObjectType.define do
|
2
|
+
name "Query"
|
3
|
+
description "The query root of this schema"
|
4
|
+
|
5
|
+
field :<%=root_type_name.underscore%> do
|
6
|
+
type <%=root_type_name%>Type
|
7
|
+
resolve -> (obj, args, ctx) {
|
8
|
+
ctx[:<%=root_type_name.underscore%>]
|
9
|
+
}
|
10
|
+
end
|
11
|
+
|
12
|
+
field :node, ::GraphQL::Relay::Node.field
|
13
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
Schema = GraphQL::Schema.define do
|
2
|
+
query <%= query_type_name %>
|
3
|
+
mutation <%= mutation_type_name %>
|
4
|
+
|
5
|
+
resolve_type -> (object, ctx) {
|
6
|
+
Schema.types[object.class.name]
|
7
|
+
}
|
8
|
+
|
9
|
+
object_from_id -> (id, ctx) {
|
10
|
+
type_name, object_id = GraphQL::Schema::UniqueWithinType.decode(id)
|
11
|
+
|
12
|
+
unless type_name.safe_constantize.present?
|
13
|
+
raise ArgumentError, "Type of object (#{type_name}) does not exist."
|
14
|
+
end
|
15
|
+
|
16
|
+
type_name.constantize.find(object_id)
|
17
|
+
}
|
18
|
+
|
19
|
+
id_from_object -> (obj, type_defn, ctx) {
|
20
|
+
GraphQL::Schema::UniqueWithinType.encode(type_defn.name, obj.id)
|
21
|
+
}
|
22
|
+
|
23
|
+
<%= middleware %>
|
24
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'erb'
|
2
|
+
|
3
|
+
class TemplateRenderer
|
4
|
+
def self.empty_binding
|
5
|
+
binding
|
6
|
+
end
|
7
|
+
|
8
|
+
def self.render_string(template_content, locals = {})
|
9
|
+
b = empty_binding
|
10
|
+
locals.each { |k, v| b.local_variable_set(k, v) }
|
11
|
+
|
12
|
+
ERB.new(template_content, nil, '-').result(b)
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.render(file, locals = {})
|
16
|
+
path = File.join Graphql::Rails::Schemaker.root, file
|
17
|
+
render_string(File.read(path), locals)
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,5 @@
|
|
1
|
+
<%=polymorphic.name.to_s.camelize%>TypeUnion = GraphQL::UnionType.define do
|
2
|
+
name "<%=polymorphic.name.to_s.camelize%>"
|
3
|
+
description "Objects for `<%=polymorphic.active_record.name.to_s%>`"
|
4
|
+
possible_types [<%=associations.map(&:name).map { |n| "#{n.to_s.camelize}Type" }.join(", ")%>]
|
5
|
+
end
|
@@ -0,0 +1,569 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
require 'set'
|
3
|
+
require 'graphql/rails/schemaker/template_renderer'
|
4
|
+
|
5
|
+
namespace :schemaker do
|
6
|
+
desc "Tasks for operating a GraphQL Schema Server"
|
7
|
+
|
8
|
+
task introspect: :environment do
|
9
|
+
viewer = SystemViewer.new
|
10
|
+
|
11
|
+
query_string = GraphQL::Introspection::INTROSPECTION_QUERY
|
12
|
+
result_hash = Schema.execute(query_string, context: {viewer: viewer})
|
13
|
+
|
14
|
+
File.open("./build/schema.json","w+") do |f|
|
15
|
+
f.write(result_hash.to_json)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
task generate: :environment do
|
20
|
+
if File.exist? "./app/graph/schema.rb"
|
21
|
+
abort "\e[1mAnother schema already exists @ ./app/graph/schema.rb\e[0m"
|
22
|
+
end
|
23
|
+
|
24
|
+
# Ensure directories are available
|
25
|
+
#FileUtils::mkdir_p Rails.root.join("app", "graph", "mutations")
|
26
|
+
#FileUtils::mkdir_p Rails.root.join("app", "graph", "resolvers")
|
27
|
+
FileUtils::mkdir_p Rails.root.join("app", "graph", "types")
|
28
|
+
|
29
|
+
# Load our application
|
30
|
+
Rails.application.eager_load!
|
31
|
+
models = ApplicationRecord.descendants.collect { |type| type }
|
32
|
+
scalar_types = [:string, :integer, :float, :id, :boolean]
|
33
|
+
|
34
|
+
# Determine whether to do snake case or camel case
|
35
|
+
STDOUT.puts "\e[1mUse camelCase or snake_case? Enter (c/S).\e[0m"
|
36
|
+
name_format =
|
37
|
+
if STDIN.gets.chomp.downcase == 'c'
|
38
|
+
:camel
|
39
|
+
else
|
40
|
+
:snake
|
41
|
+
end
|
42
|
+
|
43
|
+
# Function to convert object types to string
|
44
|
+
object_type_to_string = lambda { |model, attributes|
|
45
|
+
TemplateRenderer.render("rails/schemaker/object_type.erb", { model: model, attributes: attributes, all_models: models })
|
46
|
+
}
|
47
|
+
|
48
|
+
# Function to convert enum types to string
|
49
|
+
enum_type_to_string = lambda { |name, values|
|
50
|
+
TemplateRenderer.render("rails/schemaker/enum_type.erb", { name: name, values: values })
|
51
|
+
}
|
52
|
+
|
53
|
+
# Function to write object types
|
54
|
+
put_object_type = lambda { |file, model, attributes|
|
55
|
+
File.open(file, 'w+') { |file| file.write(object_type_to_string.call(model, attributes)) }
|
56
|
+
}
|
57
|
+
|
58
|
+
# Function to write enum types
|
59
|
+
put_enum_type = lambda { |file, name, value|
|
60
|
+
File.open(file, 'w+') { |file| file.write(enum_type_to_string.call(name, value)) }
|
61
|
+
}
|
62
|
+
|
63
|
+
STDOUT.puts "Using #{name_format == :camel ? 'camel case' : 'snake case'}"
|
64
|
+
|
65
|
+
# Schema vars
|
66
|
+
query_type_name = "QueryType"
|
67
|
+
while ApplicationRecord.descendants.map(&:name).include? query_type_name
|
68
|
+
if query_type_name == "QueryType"
|
69
|
+
query_type_name = "QueryRootType"
|
70
|
+
elsif query_type_name == "QueryRootType"
|
71
|
+
query_type_name = "QueryRootObjectType"
|
72
|
+
elsif query_type_name == "QueryRootObjectType"
|
73
|
+
STDOUT.puts "Unable to formulate a query root type name - taken: QueryType, QueryRootType, QueryRootObjectType"
|
74
|
+
abort "Exiting..."
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
mutation_type_name = "MutationType"
|
79
|
+
while ApplicationRecord.descendants.map(&:name).include? mutation_type_name
|
80
|
+
if query_type_name == "MutationType"
|
81
|
+
query_type_name = "MutationRootType"
|
82
|
+
elsif query_type_name == "MutationRootType"
|
83
|
+
query_type_name = "MutationRootObjectType"
|
84
|
+
elsif query_type_name == "MutationRootObjectType"
|
85
|
+
STDOUT.puts "Unable to formulate a mutation root type name - taken: MutationType, MutationRootType, MutationRootObjectType"
|
86
|
+
abort "Exiting..."
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
# The Main Schema entry point
|
91
|
+
schema_rb_file = "./app/graph/schema.rb"
|
92
|
+
unless File.exist? schema_rb_file
|
93
|
+
STDOUT.puts "\e[1m\e[32mGenerating Schema Root...\e[0m"
|
94
|
+
|
95
|
+
middleware = name_format == :camel ? "middleware AuthorizationMiddleware.new" : ""
|
96
|
+
|
97
|
+
src = TemplateRenderer.render("rails/schemaker/schema.erb", { middleware: middleware, query_type_name: query_type_name, mutation_type_name: mutation_type_name })
|
98
|
+
|
99
|
+
File.open(schema_rb_file, 'w+') { |file| file.write(src) }
|
100
|
+
end
|
101
|
+
|
102
|
+
# Camel Case Middleware
|
103
|
+
if name_format == :camel
|
104
|
+
FileUtils::mkdir_p Rails.root.join("app", "graph", "middleware")
|
105
|
+
|
106
|
+
middleware_rb_file = "./app/graph/middleware/camel_case_middleware.rb"
|
107
|
+
unless File.exist? middleware_rb_file
|
108
|
+
src = TemplateRenderer.render("rails/schemaker/camel_case_middleware.erb")
|
109
|
+
|
110
|
+
File.open(middleware_rb_file, 'w+') { |file| file.write(src) }
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
fake_association = Class.new(Object) {
|
115
|
+
def initialize(model, plural_name:, macro: :has_many, polymorphic: false)
|
116
|
+
@model = model
|
117
|
+
@plural_name = plural_name || model.name.pluralize
|
118
|
+
@macro = macro
|
119
|
+
@polymorphic = polymorphic
|
120
|
+
end
|
121
|
+
|
122
|
+
def klass() @model end
|
123
|
+
def macro() @macro end
|
124
|
+
def plural_name() @plural_name end
|
125
|
+
def polymorphic?() @polymorphic end
|
126
|
+
def collection?() [:has_many, :has_and_belongs_to_many].include?(@macro) end
|
127
|
+
}
|
128
|
+
|
129
|
+
scalar_types = { :id => "types.ID", :boolean => "types.Boolean", :integer => "types.Int", :float => "types.Float", :decimal => "types.Float", :string => "types.String"}
|
130
|
+
|
131
|
+
guess_type = lambda { |model, name|
|
132
|
+
return :enum if model.defined_enums.key?(name)
|
133
|
+
matches = model.columns.select { |c| c.name == name }
|
134
|
+
|
135
|
+
return matches.first.type if matches.present?
|
136
|
+
|
137
|
+
:string
|
138
|
+
}
|
139
|
+
|
140
|
+
graphl_field_type = Proc.new { |type, name|
|
141
|
+
graphql_type = nil
|
142
|
+
graphql_type = scalar_types[type.to_sym] if scalar_types.key? type.to_sym
|
143
|
+
|
144
|
+
if type == :enum
|
145
|
+
graphql_type = "#{name.to_s.camelize}Enum"
|
146
|
+
end
|
147
|
+
|
148
|
+
graphql_type = scalar_types[:string] if type.nil?
|
149
|
+
|
150
|
+
graphql_type
|
151
|
+
}
|
152
|
+
|
153
|
+
STDOUT.puts ""
|
154
|
+
STDOUT.puts "\e[1m\e[32mGenerating Object Types...\e[0m"
|
155
|
+
|
156
|
+
active_models = []
|
157
|
+
active_enum = {}
|
158
|
+
active_models_attributes = {}
|
159
|
+
models.each do |model|
|
160
|
+
model.connection
|
161
|
+
skipped = false
|
162
|
+
STDOUT.puts
|
163
|
+
STDOUT.puts "----------------------------------"
|
164
|
+
STDOUT.puts "\e[1mGenerating type for model: \e[32m#{model}\e[0m"
|
165
|
+
attributes = Set.new
|
166
|
+
attribute_types = {}
|
167
|
+
attribute_graphql_types = {}
|
168
|
+
attribute_properties = {}
|
169
|
+
attribute_associations = {}
|
170
|
+
|
171
|
+
# Track all the columns
|
172
|
+
model.columns.each do |column|
|
173
|
+
name = column.name
|
174
|
+
|
175
|
+
type_sym =
|
176
|
+
if model.defined_enums.key? name
|
177
|
+
:enum
|
178
|
+
else
|
179
|
+
column.type
|
180
|
+
end
|
181
|
+
|
182
|
+
graphql_type = graphl_field_type.call(type_sym, name)
|
183
|
+
|
184
|
+
new_name = name_format == :camel ? name.camelize(:lower).to_sym : name.underscore.to_sym
|
185
|
+
attributes.add(new_name)
|
186
|
+
attribute_types[new_name] = type_sym
|
187
|
+
attribute_graphql_types[new_name] = graphql_type
|
188
|
+
attribute_properties[new_name] = name
|
189
|
+
end
|
190
|
+
|
191
|
+
# Track all associations
|
192
|
+
model.reflect_on_all_associations.each do |association|
|
193
|
+
name = association.collection? ? association.plural_name.to_s : association.name.to_s
|
194
|
+
type = :object
|
195
|
+
|
196
|
+
new_name = name_format == :camel ? name.camelize(:lower).to_sym : name.underscore.to_sym
|
197
|
+
attributes.add(new_name)
|
198
|
+
attribute_types[new_name] = type
|
199
|
+
attribute_graphql_types[new_name] = graphl_field_type.call(type, name)
|
200
|
+
attribute_properties[new_name] = name
|
201
|
+
attribute_associations[new_name] = association
|
202
|
+
end
|
203
|
+
|
204
|
+
# Process commands for each model
|
205
|
+
last_input = $_
|
206
|
+
is_repeating = false
|
207
|
+
while last_input != "g"
|
208
|
+
unless is_repeating
|
209
|
+
STDOUT.puts
|
210
|
+
STDOUT.puts "Using attributes: #{attributes.to_a.join(", ")}"
|
211
|
+
STDOUT.puts "To continue, enter one of the following commands: (\e[34mg = generate \e[39m| \e[31mr = remove attribute \e[39m| \e[32ma = add attribute \e[39m| \e[93ms = skip model\e[39m)"
|
212
|
+
command = STDIN.gets.chomp.downcase
|
213
|
+
end
|
214
|
+
|
215
|
+
is_repeating = false
|
216
|
+
|
217
|
+
case command
|
218
|
+
when "s"
|
219
|
+
skipped = true
|
220
|
+
break
|
221
|
+
when "a"
|
222
|
+
STDOUT.puts
|
223
|
+
STDOUT.puts "Enter attribute name and type in following format: \e[32m#{name_format == :snake ? "property_name" : "columName"}\e[39m:(\e[96m#{scalar_types.join("\e[39m|\e[96m")}\e[39m)"
|
224
|
+
raw_attr = STDIN.gets.chomp.downcase
|
225
|
+
new_attr = raw_attr
|
226
|
+
|
227
|
+
if name_format == :camel
|
228
|
+
new_attr = raw_attr.camelize(:lower)
|
229
|
+
else
|
230
|
+
new_attr = raw_attr.underscore
|
231
|
+
end
|
232
|
+
|
233
|
+
unless new_attr === raw_attr
|
234
|
+
STDOUT.puts "Converting to #{name_format == :camel ? 'camelCase' : 'snake_case'} - \"#{new_attr}\""
|
235
|
+
end
|
236
|
+
|
237
|
+
unless new_attr.present?
|
238
|
+
is_repeating = false
|
239
|
+
next
|
240
|
+
end
|
241
|
+
|
242
|
+
unless new_attr.include? ":"
|
243
|
+
last_input = "a"
|
244
|
+
is_repeating = true
|
245
|
+
next
|
246
|
+
end
|
247
|
+
|
248
|
+
name, type = new_attr.split(":")
|
249
|
+
property = name
|
250
|
+
tries = 0;
|
251
|
+
|
252
|
+
if attributes.include? name.to_sym
|
253
|
+
STDOUT.puts "Attribute #{name} already exists. Retrying..."
|
254
|
+
is_repeating = false
|
255
|
+
next
|
256
|
+
end
|
257
|
+
|
258
|
+
until model.column_names.include? property or model.respond_to? property.to_sym
|
259
|
+
if tries >= 3
|
260
|
+
STDOUT.puts "Tried three times. Retrying..."
|
261
|
+
break
|
262
|
+
end
|
263
|
+
|
264
|
+
STDOUT.puts "#{model} does not possess property \"#{property}\", what should \"#{name}\" respond with?"
|
265
|
+
input = STDIN.gets.chomp
|
266
|
+
property = input if input.present?
|
267
|
+
|
268
|
+
tries += 1
|
269
|
+
end
|
270
|
+
|
271
|
+
if property.nil?
|
272
|
+
is_repeating = true
|
273
|
+
next
|
274
|
+
end
|
275
|
+
|
276
|
+
unless name == property
|
277
|
+
attribute_properties[name] = property
|
278
|
+
end
|
279
|
+
|
280
|
+
attributes.add(name.to_sym)
|
281
|
+
attribute_types[name.to_sym] = type
|
282
|
+
attribute_graphql_types[name.to_sym] = graphl_field_type.call(type, name.to_sym)
|
283
|
+
|
284
|
+
when "r"
|
285
|
+
STDOUT.puts "Enter the name of the attribute to remove:"
|
286
|
+
raw_attr = STDIN.gets.chomp.downcase
|
287
|
+
|
288
|
+
if raw_attr.include? ":"
|
289
|
+
raw_attr = raw_attr.split(":").first
|
290
|
+
end
|
291
|
+
|
292
|
+
remove_attr = raw_attr
|
293
|
+
|
294
|
+
if name_format == :camel
|
295
|
+
remove_attr = raw_attr.camelize(:lower)
|
296
|
+
else
|
297
|
+
remove_attr = raw_attr.underscore
|
298
|
+
end
|
299
|
+
|
300
|
+
unless remove_attr === raw_attr
|
301
|
+
STDOUT.puts "Converting to #{name_format == :camel ? 'camelCase' : 'snake_case'} - \"#{remove_attr}\""
|
302
|
+
end
|
303
|
+
|
304
|
+
unless attributes.include? remove_attr.to_sym
|
305
|
+
STDOUT.puts "Attribute \"#{remove_attr}\" does not exist."
|
306
|
+
is_repeating = true
|
307
|
+
next
|
308
|
+
end
|
309
|
+
|
310
|
+
STDOUT.puts "Removing attribute \"#{remove_attr}\"."
|
311
|
+
attributes.delete(remove_attr.to_sym)
|
312
|
+
attribute_types.delete remove_attr.to_sym
|
313
|
+
attribute_graphql_types.delete remove_attr.to_sym
|
314
|
+
attribute_properties.delete remove_attr.to_sym
|
315
|
+
|
316
|
+
is_repeating = false
|
317
|
+
when "g"
|
318
|
+
break
|
319
|
+
else
|
320
|
+
STDOUT.puts "Unrecognized command #{command}"
|
321
|
+
end
|
322
|
+
|
323
|
+
end
|
324
|
+
|
325
|
+
if skipped
|
326
|
+
STDOUT.puts "\e[93mSkipping #{model.name}...\e[39m"
|
327
|
+
next
|
328
|
+
end
|
329
|
+
|
330
|
+
object_type_file = "./app/graph/types/#{model.name.underscore}_type.rb"
|
331
|
+
attr_composed = {}
|
332
|
+
|
333
|
+
attributes.each do |attribute|
|
334
|
+
hash = { :type => attribute_types[attribute], :graphql_type => attribute_graphql_types[attribute], :property => attribute_properties[attribute] }
|
335
|
+
|
336
|
+
if attribute_associations.key? attribute
|
337
|
+
hash[:association] = attribute_associations[attribute]
|
338
|
+
end
|
339
|
+
|
340
|
+
if model.defined_enums.key? hash[:property]
|
341
|
+
active_enum[attribute.to_s.camelize] = model.defined_enums[hash[:property]]
|
342
|
+
end
|
343
|
+
|
344
|
+
attr_composed[attribute] = hash
|
345
|
+
end
|
346
|
+
|
347
|
+
put_object_type.call(object_type_file, model, attr_composed.sort_by { |k,v| [k == :id ? 0 : 1, k] })
|
348
|
+
|
349
|
+
# Save this config for later
|
350
|
+
active_models.push(model)
|
351
|
+
active_models_attributes[model] = attr_composed
|
352
|
+
|
353
|
+
# Todo
|
354
|
+
# 2. Generate input types
|
355
|
+
# 4. Generate generic resolvers (if using graphql-rails-resolver)
|
356
|
+
|
357
|
+
end
|
358
|
+
|
359
|
+
puts "active_enum = #{active_enum}"
|
360
|
+
if active_enum.present?
|
361
|
+
STDOUT.puts ""
|
362
|
+
STDOUT.puts "----------------------------------"
|
363
|
+
STDOUT.puts ""
|
364
|
+
STDOUT.puts "\e[1m\e[32mGenerating Enum Types...\e[0m"
|
365
|
+
|
366
|
+
active_enum.each do |name, values|
|
367
|
+
enum_type_file = "./app/graph/types/#{name.underscore}_enum.rb"
|
368
|
+
|
369
|
+
STDOUT.puts "\e[34m#{name}Enum\e[0m"
|
370
|
+
put_enum_type.call(enum_type_file, name, values)
|
371
|
+
end
|
372
|
+
end
|
373
|
+
|
374
|
+
STDOUT.puts ""
|
375
|
+
STDOUT.puts "----------------------------------"
|
376
|
+
STDOUT.puts ""
|
377
|
+
|
378
|
+
# Generate union types from generated models
|
379
|
+
polymorphics = active_models.map { |m| m.reflect_on_all_associations.select(&:polymorphic?) }.flatten
|
380
|
+
if polymorphics.present?
|
381
|
+
STDOUT.puts "\e[1m\e[32mGenerating Union Types...\e[0m"
|
382
|
+
polymorphics.each do |polymorphic|
|
383
|
+
|
384
|
+
STDOUT.puts "\e[34m#{polymorphic.name.to_s.camelize}Type\e[0m"
|
385
|
+
|
386
|
+
polymorphic_rb_file = "./app/graph/types/#{polymorphic.name}_union.rb"
|
387
|
+
associations = active_models.select { |m| m.reflect_on_all_associations.select{ |j| j.options[:as] == polymorphic.name }.present? }
|
388
|
+
|
389
|
+
src = TemplateRenderer.render("rails/schemaker/union_type.erb", { polymorphic: polymorphic, associations: associations })
|
390
|
+
|
391
|
+
File.open(polymorphic_rb_file, 'w+') { |file| file.write(src) }
|
392
|
+
end
|
393
|
+
end
|
394
|
+
|
395
|
+
STDOUT.puts ""
|
396
|
+
STDOUT.puts "----------------------------------"
|
397
|
+
STDOUT.puts ""
|
398
|
+
|
399
|
+
STDOUT.puts "\e[1m\e[32mGenerating Query Root...\e[0m"
|
400
|
+
STDOUT.puts "A query root is the entry point to your Schema."
|
401
|
+
STDOUT.puts ""
|
402
|
+
STDOUT.puts "If you plan to use Relay v1, your Schema needs a global node to work properly."
|
403
|
+
STDOUT.puts "See https://github.com/facebook/relay/issues/112 for more info."
|
404
|
+
|
405
|
+
STDOUT.puts ""
|
406
|
+
STDOUT.puts "----------------------------------"
|
407
|
+
STDOUT.puts ""
|
408
|
+
|
409
|
+
STDOUT.puts "How would you like to generate your query root?"
|
410
|
+
STDOUT.puts "1 - Use Global Node (default)"
|
411
|
+
STDOUT.puts "2 - Expose all fields on query root"
|
412
|
+
STDOUT.puts ""
|
413
|
+
|
414
|
+
command = STDIN.gets.chomp.downcase
|
415
|
+
until ["1", "2", "", "g"].include? command
|
416
|
+
STDOUT.puts "\"#{command}\" not recognized."
|
417
|
+
command = STDIN.gets.chomp.downcase
|
418
|
+
end
|
419
|
+
|
420
|
+
if ["", "g"].include? command
|
421
|
+
command = "1"
|
422
|
+
end
|
423
|
+
|
424
|
+
# Generate global node for query root
|
425
|
+
if command == "1"
|
426
|
+
root_type_name = nil
|
427
|
+
|
428
|
+
# Check if developers already made a global node model
|
429
|
+
if active_models.map(&:name).include? "Viewer"
|
430
|
+
STDOUT.puts "A model by the name 'Viewer' already exists. Should this model be the global node? (Y/n)"
|
431
|
+
|
432
|
+
command = STDIN.gets.chomp.downcase
|
433
|
+
until ["y", "n", "", "g"].include?(command)
|
434
|
+
STDOUT.puts "\"#{command}\" not recognized."
|
435
|
+
command = STDIN.gets.chomp.downcase
|
436
|
+
end
|
437
|
+
|
438
|
+
if ["", "g"].include? command
|
439
|
+
command = "y"
|
440
|
+
end
|
441
|
+
|
442
|
+
root_type_name = "Viewer"
|
443
|
+
|
444
|
+
# Reconfigure the file
|
445
|
+
model = active_models.select { |m| m.name == "Viewer" }.first
|
446
|
+
attributes = active_models_attributes[model]
|
447
|
+
|
448
|
+
root_type_attr = {}
|
449
|
+
|
450
|
+
active_models.map do |model|
|
451
|
+
key = model.name.pluralize
|
452
|
+
|
453
|
+
if name_format == :camel
|
454
|
+
key = key.camelize(:lower)
|
455
|
+
else
|
456
|
+
key = key.underscore
|
457
|
+
end
|
458
|
+
|
459
|
+
while key.nil? or attributes.key? key or attributes.key? key.to_sym
|
460
|
+
STDOUT.puts "Field `\e[31m#{key}\e[0m` already exists on `\e[32m#{root_type_name}\e[0m`. Enter a new name for the field:"
|
461
|
+
command = STDIN.gets.chomp
|
462
|
+
unless command.present? and command[/[a-zA-Z]+/] == command
|
463
|
+
command = nil
|
464
|
+
next
|
465
|
+
end
|
466
|
+
|
467
|
+
key = command
|
468
|
+
end
|
469
|
+
|
470
|
+
if name_format == :camel
|
471
|
+
key = key.camelize(:lower)
|
472
|
+
else
|
473
|
+
key = key.underscore
|
474
|
+
end
|
475
|
+
|
476
|
+
association = fake_association.new(model, plural_name: key)
|
477
|
+
association.polymorphic?
|
478
|
+
|
479
|
+
root_type_attr[key] = { :type => :id, :association => association}
|
480
|
+
end
|
481
|
+
|
482
|
+
object_type_file = "./app/graph/types/#{model.name.underscore}_type.rb"
|
483
|
+
sorted_fields = Hash[root_type_attr.sort_by{ |k,v| k }]
|
484
|
+
put_object_type.call(object_type_file, model, attributes.merge(sorted_fields))
|
485
|
+
else
|
486
|
+
STDOUT.puts "Define the root type to expose your object types: (letters only) (default = \e[32mViewer\e[0m)"
|
487
|
+
name_command = STDIN.gets.chomp.downcase
|
488
|
+
while root_type_name.nil?
|
489
|
+
if name_command.empty?
|
490
|
+
root_type_name = "Viewer"
|
491
|
+
else
|
492
|
+
unless name_command[/[a-zA-Z]+/] == name_command
|
493
|
+
STDOUT.puts "Root type name must contain only letters. No numbers or special characters."
|
494
|
+
next
|
495
|
+
end
|
496
|
+
|
497
|
+
if models.map(&:name).include?(name_command)
|
498
|
+
STDOUT.puts "A model already exists by that name. Are you sure? (y/N)"
|
499
|
+
command = STDIN.gets.chomp.downcase
|
500
|
+
until ["y", "n", ""].include?(command)
|
501
|
+
STDOUT.puts "\"#{command}\" not recognized."
|
502
|
+
command = STDIN.gets.chomp.downcase
|
503
|
+
end
|
504
|
+
|
505
|
+
if command == ""
|
506
|
+
command = "n"
|
507
|
+
end
|
508
|
+
|
509
|
+
if command == "n"
|
510
|
+
next
|
511
|
+
end
|
512
|
+
end
|
513
|
+
|
514
|
+
root_type_name = name_command.classify
|
515
|
+
end
|
516
|
+
end
|
517
|
+
|
518
|
+
# Generate global node type with generated models
|
519
|
+
Object.const_set(root_type_name, Class.new { def name() root_type_name end })
|
520
|
+
|
521
|
+
root_type_attr = {}
|
522
|
+
active_models.each do |model|
|
523
|
+
key = model.name.pluralize
|
524
|
+
|
525
|
+
if name_format == :camel
|
526
|
+
key = key.camelize(:lower)
|
527
|
+
else
|
528
|
+
key = key.underscore
|
529
|
+
end
|
530
|
+
|
531
|
+
association = fake_association.new(model, plural_name: key)
|
532
|
+
root_type_attr[key] = { :type => :id, :association => association}
|
533
|
+
end
|
534
|
+
|
535
|
+
root_object_type_file = "./app/graph/types/#{root_type_name.underscore}_type.rb"
|
536
|
+
put_object_type.call(root_object_type_file, root_type_name.constantize, root_type_attr)
|
537
|
+
|
538
|
+
end
|
539
|
+
end
|
540
|
+
|
541
|
+
# Generate the Query root type (include)
|
542
|
+
query_type_rb_file = "./app/graph/types/#{query_type_name.underscore}.rb"
|
543
|
+
unless File.exist? query_type_rb_file
|
544
|
+
STDOUT.puts "Generating Query Root Type..."
|
545
|
+
|
546
|
+
src = TemplateRenderer.render("rails/schemaker/query_type.erb", { query_type_name: query_type_name, root_type_name: root_type_name })
|
547
|
+
|
548
|
+
File.open(query_type_rb_file, 'w+') { |file| file.write(src) }
|
549
|
+
end
|
550
|
+
|
551
|
+
|
552
|
+
# Generate the Mutation root type (include)
|
553
|
+
# TODO - Add Mutations
|
554
|
+
mutation_type_rb_file = "./app/graph/types/#{mutation_type_name.underscore}.rb"
|
555
|
+
unless File.exist? mutation_type_rb_file
|
556
|
+
STDOUT.puts "Generating Mutation Root Type..."
|
557
|
+
|
558
|
+
src = TemplateRenderer.render("rails/schemaker/mutation_type.erb", { mutation_type_name: mutation_type_name })
|
559
|
+
|
560
|
+
File.open(mutation_type_rb_file, 'w+') { |file| file.write(src) }
|
561
|
+
end
|
562
|
+
|
563
|
+
|
564
|
+
STDOUT.puts "\e[32mDone...\e[0m"
|
565
|
+
|
566
|
+
|
567
|
+
end
|
568
|
+
|
569
|
+
end
|
metadata
ADDED
@@ -0,0 +1,109 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: graphql-rails-schemaker
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Cole Turner
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2016-10-31 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: graphql
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 0.19.0
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 0.19.0
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: bundler
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '1.13'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '1.13'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rake
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '10.0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '10.0'
|
55
|
+
description:
|
56
|
+
email:
|
57
|
+
- turner.cole@gmail.com
|
58
|
+
executables: []
|
59
|
+
extensions: []
|
60
|
+
extra_rdoc_files: []
|
61
|
+
files:
|
62
|
+
- ".gitignore"
|
63
|
+
- CODE_OF_CONDUCT.md
|
64
|
+
- Gemfile
|
65
|
+
- LICENSE.txt
|
66
|
+
- README.md
|
67
|
+
- Rakefile
|
68
|
+
- bin/console
|
69
|
+
- bin/setup
|
70
|
+
- graphql-rails-schemaker.gemspec
|
71
|
+
- lib/.DS_Store
|
72
|
+
- lib/graphql/rails/.DS_Store
|
73
|
+
- lib/graphql/rails/schemaker.rb
|
74
|
+
- lib/graphql/rails/schemaker/camel_case_middleware.erb
|
75
|
+
- lib/graphql/rails/schemaker/enum_type.erb
|
76
|
+
- lib/graphql/rails/schemaker/mutation_type.erb
|
77
|
+
- lib/graphql/rails/schemaker/object_type.erb
|
78
|
+
- lib/graphql/rails/schemaker/query_type.erb
|
79
|
+
- lib/graphql/rails/schemaker/railtie.rb
|
80
|
+
- lib/graphql/rails/schemaker/schema.erb
|
81
|
+
- lib/graphql/rails/schemaker/template_renderer.rb
|
82
|
+
- lib/graphql/rails/schemaker/union_type.erb
|
83
|
+
- lib/graphql/rails/schemaker/version.rb
|
84
|
+
- lib/tasks/schemaker.rake
|
85
|
+
homepage: https://github.com/colepatrickturner/graphql-rails-schemaker
|
86
|
+
licenses:
|
87
|
+
- MIT
|
88
|
+
metadata: {}
|
89
|
+
post_install_message:
|
90
|
+
rdoc_options: []
|
91
|
+
require_paths:
|
92
|
+
- lib
|
93
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
94
|
+
requirements:
|
95
|
+
- - ">="
|
96
|
+
- !ruby/object:Gem::Version
|
97
|
+
version: 2.2.2
|
98
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
99
|
+
requirements:
|
100
|
+
- - ">="
|
101
|
+
- !ruby/object:Gem::Version
|
102
|
+
version: '0'
|
103
|
+
requirements: []
|
104
|
+
rubyforge_project:
|
105
|
+
rubygems_version: 2.5.1
|
106
|
+
signing_key:
|
107
|
+
specification_version: 4
|
108
|
+
summary: ''
|
109
|
+
test_files: []
|