kanji-web 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (73) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +21 -0
  3. data/Rakefile +1 -0
  4. data/bin/kanji +6 -0
  5. data/lib/kanji.rb +5 -0
  6. data/lib/kanji/application.rb +37 -0
  7. data/lib/kanji/cli.rb +36 -0
  8. data/lib/kanji/cli/generate.rb +13 -0
  9. data/lib/kanji/container.rb +12 -0
  10. data/lib/kanji/errors.rb +10 -0
  11. data/lib/kanji/generate.rb +48 -0
  12. data/lib/kanji/generators/abstract_generator.rb +50 -0
  13. data/lib/kanji/generators/project.rb +155 -0
  14. data/lib/kanji/generators/type.rb +110 -0
  15. data/lib/kanji/graph.rb +1 -0
  16. data/lib/kanji/graph/coerce_type.rb +66 -0
  17. data/lib/kanji/graph/container.rb +18 -0
  18. data/lib/kanji/graph/helpers.rb +27 -0
  19. data/lib/kanji/graph/import.rb +8 -0
  20. data/lib/kanji/graph/query.rb +16 -0
  21. data/lib/kanji/graph/register_mutation.rb +43 -0
  22. data/lib/kanji/graph/register_object.rb +40 -0
  23. data/lib/kanji/graph/schema.rb +17 -0
  24. data/lib/kanji/import.rb +5 -0
  25. data/lib/kanji/instance_define.rb +11 -0
  26. data/lib/kanji/logger.rb +10 -0
  27. data/lib/kanji/repository.rb +53 -0
  28. data/lib/kanji/templates/.gitignore +11 -0
  29. data/lib/kanji/templates/.keep +0 -0
  30. data/lib/kanji/templates/.rspec +2 -0
  31. data/lib/kanji/templates/Gemfile +14 -0
  32. data/lib/kanji/templates/README.md.tt +12 -0
  33. data/lib/kanji/templates/Rakefile.tt +113 -0
  34. data/lib/kanji/templates/app/mutation_type.rb.tt +14 -0
  35. data/lib/kanji/templates/app/query_type.rb.tt +13 -0
  36. data/lib/kanji/templates/app/repositories/repo.rb.tt +7 -0
  37. data/lib/kanji/templates/app/schema.rb.tt +21 -0
  38. data/lib/kanji/templates/app/types.rb.tt +5 -0
  39. data/lib/kanji/templates/app/types/type.rb.tt +26 -0
  40. data/lib/kanji/templates/app/views/graphiql.html.erb +24 -0
  41. data/lib/kanji/templates/bin/console.tt +7 -0
  42. data/lib/kanji/templates/bin/setup +7 -0
  43. data/lib/kanji/templates/config.ru.tt +2 -0
  44. data/lib/kanji/templates/db/sample_data.rb +1 -0
  45. data/lib/kanji/templates/db/seed.rb +1 -0
  46. data/lib/kanji/templates/migration.rb.tt +10 -0
  47. data/lib/kanji/templates/spec/db_spec_helper.rb.tt +23 -0
  48. data/lib/kanji/templates/spec/factories/example.rb +9 -0
  49. data/lib/kanji/templates/spec/spec_helper.rb +61 -0
  50. data/lib/kanji/templates/spec/support/db/factory.rb +8 -0
  51. data/lib/kanji/templates/spec/support/db/helpers.rb.tt +13 -0
  52. data/lib/kanji/templates/system/boot.rb.tt +13 -0
  53. data/lib/kanji/templates/system/boot/graph.rb.tt +11 -0
  54. data/lib/kanji/templates/system/boot/monitor.rb.tt +9 -0
  55. data/lib/kanji/templates/system/boot/repos.rb.tt +23 -0
  56. data/lib/kanji/templates/system/boot/rom.rb.tt +37 -0
  57. data/lib/kanji/templates/system/boot/settings.rb.tt +10 -0
  58. data/lib/kanji/templates/system/project/application.rb.tt +35 -0
  59. data/lib/kanji/templates/system/project/container.rb.tt +13 -0
  60. data/lib/kanji/templates/system/project/import.rb.tt +5 -0
  61. data/lib/kanji/templates/system/project/settings.rb.tt +8 -0
  62. data/lib/kanji/type.rb +62 -0
  63. data/lib/kanji/type/argument.rb +12 -0
  64. data/lib/kanji/type/attribute.rb +14 -0
  65. data/lib/kanji/type/attribute_definer.rb +33 -0
  66. data/lib/kanji/type/class_interface.rb +156 -0
  67. data/lib/kanji/type/mutation.rb +13 -0
  68. data/lib/kanji/type/mutation_definer.rb +43 -0
  69. data/lib/kanji/types.rb +11 -0
  70. data/lib/kanji/types/callable.rb +30 -0
  71. data/lib/kanji/types/type_interface.rb +43 -0
  72. data/lib/kanji/version.rb +3 -0
  73. metadata +538 -0
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 864b99448c021a5a6e386c1be615540b1a0094bb
4
+ data.tar.gz: 11fcc22cf234333a3ffb229a71483cebb0233d84
5
+ SHA512:
6
+ metadata.gz: 109cb177d81512bef482275367e962ce5b04715bb7737ee9e9c2db7c86e4afacf26d9c691d8088ce29171ebc28d1a27e9e3c2fbca82d8b48c8d2818703b73ac6
7
+ data.tar.gz: 36d8b79e6d993098a966ab3d3aaaba29aa90cb146802bcf8876acaa06a4d5c65b6714d716ad805c616e704e83239fa2bf35554ec3824376a8e228c311c74a100
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2016 Darin Haener
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 all
13
+ 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 THE
21
+ SOFTWARE.
@@ -0,0 +1 @@
1
+ Dir.glob('lib/tasks/*.rake').each { |r| load r }
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "kanji/cli"
5
+
6
+ Kanji::CLI.start ARGV
@@ -0,0 +1,5 @@
1
+ require "kanji/container"
2
+
3
+ module Kanji
4
+
5
+ end
@@ -0,0 +1,37 @@
1
+ require "roda"
2
+ require "roda/plugins/flow"
3
+ require "dry-configurable"
4
+
5
+ module Kanji
6
+ class Application < ::Roda
7
+ extend Dry::Configurable
8
+
9
+ setting :container, reader: true
10
+
11
+ plugin :render, views: "app/views"
12
+ plugin :error_handler
13
+ plugin :flow
14
+
15
+ def self.configure(&block)
16
+ super.tap do
17
+ use(container[:rack_monitor]) if container.config.listeners
18
+ end
19
+ end
20
+
21
+ def self.resolve(name)
22
+ container[name]
23
+ end
24
+
25
+ def self.[](name)
26
+ container[name]
27
+ end
28
+
29
+ def self.root
30
+ container.config.root
31
+ end
32
+
33
+ def notifications
34
+ self.class[:notifications]
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,36 @@
1
+ require "thor"
2
+
3
+ module Kanji
4
+ class CLI < Thor
5
+ desc "new APP", "Generate a new Kanji project"
6
+ def new(app_name)
7
+ require "kanji/generators/project"
8
+ Generators::Project.new(app_name).call
9
+ end
10
+
11
+ map "n" => "new"
12
+
13
+ desc "generate GENERATOR", "Generate a new item for this project"
14
+ require "kanji/cli/generate"
15
+ subcommand "generate", CLI::Generate
16
+
17
+ map "g" => "generate"
18
+
19
+ desc "server", "Start the application server"
20
+ def server
21
+ `shotgun config.ru > stdout`
22
+ end
23
+
24
+ map "s" => "server"
25
+
26
+ desc "console", "Open up the application console"
27
+ def console
28
+ require "bundler/setup"
29
+ require "dry/web/console"
30
+ require_relative "#{Dir.pwd}/system/boot"
31
+ Dry::Web::Console.start
32
+ end
33
+
34
+ map "c" => "console"
35
+ end
36
+ end
@@ -0,0 +1,13 @@
1
+ require "thor"
2
+
3
+ module Kanji
4
+ class CLI < Thor
5
+ class Generate < Thor
6
+ desc "type NAME ATTRIBUTES", "Generate a new type and all of it's dependencies"
7
+ def type(name, *attributes)
8
+ require "kanji/generators/type"
9
+ Generators::Type.new(name, attributes).call
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,12 @@
1
+ require "dry/system/container"
2
+ require "kanji/graph/container"
3
+
4
+ module Kanji
5
+ class Container < Dry::System::Container
6
+ configure do |config|
7
+ config.root = Pathname.new("./")
8
+ end
9
+
10
+ load_paths!("lib/kanji/type", "lib/kanji/graph")
11
+ end
12
+ end
@@ -0,0 +1,10 @@
1
+ module Kanji
2
+ class AttributeError < StandardError
3
+ end
4
+
5
+ class ValidationError < StandardError
6
+ end
7
+
8
+ class ArgumentError < StandardError
9
+ end
10
+ end
@@ -0,0 +1,48 @@
1
+ require "pathname"
2
+ require "thor"
3
+
4
+ module Kanji
5
+ class Generate
6
+ TEMPLATES_DIR = "templates".freeze
7
+ SOURCE_DIR = Pathname(__FILE__).dirname.join(TEMPLATES_DIR)
8
+
9
+ attr_reader :target_dir, :template_scope, :template_files, :processor
10
+
11
+ def initialize(target_dir, template_scope)
12
+ @target_dir = target_dir
13
+ @template_scope = template_scope
14
+ @template_files = Dir[SOURCE_DIR.join('**/{.,}*')]
15
+
16
+ @processor = Class.new(Thor) do
17
+ include Thor::Actions
18
+ end.new
19
+ @processor.class.source_root SOURCE_DIR
20
+ end
21
+
22
+ def call(source, target)
23
+ source = Pathname(source)
24
+ aboslute_source_path = source.expand_path(SOURCE_DIR)
25
+ target_file = get_target_file(target)
26
+ template_file = template_files.find { |f| f == aboslute_source_path.to_s } or raise "missing template file +#{source}+"
27
+ template_file = Pathname(template_file)
28
+
29
+ processor.template template_file, target_file, template_scope
30
+
31
+ create_executable(target_file) if executable?(template_file)
32
+ end
33
+
34
+ private
35
+
36
+ def get_target_file(target)
37
+ Pathname.getwd.join(target_dir, target)
38
+ end
39
+
40
+ def create_executable(file)
41
+ FileUtils.chmod "a+x", file
42
+ end
43
+
44
+ def executable?(file)
45
+ file.file? && file.executable?
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,50 @@
1
+ require "kanji/generate"
2
+ require "dry/core/inflector"
3
+
4
+ module Kanji
5
+ module Generators
6
+ class AbstractGenerator
7
+ def initialize(target_dir)
8
+ @target_dir = target_dir
9
+ @templates = []
10
+ populate_templates
11
+ @templates.freeze
12
+ end
13
+
14
+ def call
15
+ templates.each do |source, target|
16
+ generator.(source, target)
17
+ end
18
+
19
+ post_process_callback
20
+ end
21
+
22
+ private
23
+ attr_reader :target_dir, :templates
24
+
25
+ def populate_templates
26
+ fail NotImplementedError
27
+ end
28
+
29
+ def post_process_callback
30
+
31
+ end
32
+
33
+ def add_template(source, target)
34
+ templates << [source, target]
35
+ end
36
+
37
+ def generator
38
+ @generator ||= Generate.new(destination, template_scope)
39
+ end
40
+
41
+ def destination
42
+ fail NotImplementedError
43
+ end
44
+
45
+ def template_scope
46
+ fail NotImplementedError
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,155 @@
1
+ require "kanji/generate"
2
+ require "kanji/generators/abstract_generator"
3
+ require "dry/core/inflector"
4
+
5
+ module Kanji
6
+ module Generators
7
+ class Project < AbstractGenerator
8
+ def initialize(app_name, options = {})
9
+ @app_name = app_name
10
+ super(underscored_project_name)
11
+ end
12
+
13
+ def populate_templates
14
+ add_bin
15
+ add_config
16
+ add_db
17
+ add_log
18
+ add_spec
19
+ add_app
20
+ add_lib
21
+ add_system
22
+ add_config_files
23
+ end
24
+
25
+ private
26
+ attr_reader :app_name
27
+
28
+ def post_process_callback
29
+ message = <<-TEXT
30
+ \n
31
+ You're now ready to start writing your Kanji app! Congratulations!
32
+ Because this is a data driven API application, you can't do much
33
+ with it until you create some types! Get started by using a generator:
34
+ `kanji g type User email:string`
35
+
36
+ This will generate a type and some mutations for you! Then you can:
37
+ `rake db:create && rake db:migrate`
38
+
39
+ After that open up `app/query_type.rb` and add a field to your root query
40
+ type:
41
+
42
+ field :users do
43
+ type -> { types[Types::User[:graphql_type]] }
44
+ description "All of the users for this app"
45
+
46
+ resolve -> (obj, args, ctx) { Types::User[:repo].all }
47
+ end
48
+
49
+ Now open up `app/schema.rb` and uncomment the lines that add the
50
+ query and mutation types.
51
+
52
+ Start your server: `kanji s` and visit `localhost:9393/graphiql` and
53
+ start exploring!
54
+ TEXT
55
+
56
+ generator.processor.say(message, :cyan)
57
+ end
58
+
59
+ def destination
60
+ underscored_project_name
61
+ end
62
+
63
+ def template_scope
64
+ {
65
+ underscored_project_name: underscored_project_name,
66
+ camel_cased_app_name: camel_cased_app_name
67
+ }
68
+ end
69
+
70
+ def underscored_project_name
71
+ Dry::Core::Inflector.underscore(app_name)
72
+ end
73
+
74
+ def camel_cased_app_name
75
+ Dry::Core::Inflector.camelize(app_name)
76
+ end
77
+
78
+ def add_bin
79
+ add_template("bin/console.tt", "bin/console")
80
+ add_template("bin/setup", "bin/setup")
81
+ end
82
+
83
+ def add_config
84
+ add_template(".env.tt", ".env")
85
+ add_template(".env.test.tt", ".env.test")
86
+ end
87
+
88
+ def add_db
89
+ add_template("db/sample_data.rb", "db/sample_data.rb")
90
+ add_template("db/seed.rb", "db/seed.rb")
91
+ end
92
+
93
+ def add_app
94
+ add_template("app/types.rb.tt", "app/types.rb")
95
+ add_template("app/schema.rb.tt", "app/schema.rb")
96
+ add_template("app/query_type.rb.tt", "app/query_type.rb")
97
+ add_template("app/mutation_type.rb.tt", "app/mutation_type.rb")
98
+ add_template("app/views/graphiql.html.erb", "app/views/graphiql.html.erb")
99
+ add_template(".keep", "app/repositories/.keep")
100
+ add_template(".keep", "app/types/.keep")
101
+ add_template(".keep", "client/.keep")
102
+ end
103
+
104
+ def add_lib
105
+ add_template(".keep", "lib/.keep")
106
+ end
107
+
108
+ def add_log
109
+ add_template(".keep", "log/.keep")
110
+ end
111
+
112
+ def add_spec
113
+ add_template(".rspec", ".rspec")
114
+
115
+ # Base spec helpers
116
+ add_template("spec/db_spec_helper.rb.tt", "spec/db_spec_helper.rb")
117
+ add_template("spec/spec_helper.rb", "spec/spec_helper.rb")
118
+
119
+ # DB support
120
+ add_template("spec/support/db/factory.rb", "spec/support/db/factory.rb")
121
+ add_template("spec/support/db/helpers.rb.tt", "spec/support/db/helpers.rb")
122
+ add_template("spec/factories/example.rb", "spec/factories/example.rb")
123
+ end
124
+
125
+ def add_system
126
+ add_system_lib
127
+ add_system_boot
128
+ end
129
+
130
+ def add_system_lib
131
+ add_template("system/project/container.rb.tt", "system/#{underscored_project_name}/container.rb")
132
+ add_template("system/project/import.rb.tt", "system/#{underscored_project_name}/import.rb")
133
+ add_template("system/project/settings.rb.tt", "system/#{underscored_project_name}/settings.rb")
134
+ add_template("system/project/application.rb.tt", "system/#{underscored_project_name}/application.rb")
135
+ end
136
+
137
+ def add_system_boot
138
+ add_template("system/boot.rb.tt", "system/boot.rb")
139
+ add_template("system/boot/monitor.rb.tt", "system/boot/monitor.rb")
140
+ add_template("system/boot/rom.rb.tt", "system/boot/rom.rb")
141
+ add_template("system/boot/settings.rb.tt", "system/boot/settings.rb")
142
+ add_template("system/boot/graph.rb.tt", "system/boot/graph.rb")
143
+ add_template("system/boot/repos.rb.tt", "system/boot/repos.rb")
144
+ end
145
+
146
+ def add_config_files
147
+ add_template(".gitignore", ".gitignore")
148
+ add_template("Gemfile", "Gemfile")
149
+ add_template("Rakefile.tt", "Rakefile")
150
+ add_template("config.ru.tt", "config.ru")
151
+ add_template("README.md.tt", "README.md")
152
+ end
153
+ end
154
+ end
155
+ end
@@ -0,0 +1,110 @@
1
+ require "thor"
2
+ require "dry/core/inflector"
3
+ require "kanji/generators/abstract_generator"
4
+
5
+ module Kanji
6
+ module Generators
7
+ class Type < AbstractGenerator
8
+ def initialize(name, attributes)
9
+ @name = name
10
+ @attributes = attributes.map { |attr| attr.split(":") }
11
+ super(destination)
12
+ end
13
+
14
+ def populate_templates
15
+ add_type
16
+ add_repository
17
+ add_mutations
18
+ add_migration
19
+ end
20
+
21
+ private
22
+ attr_reader :name, :attributes
23
+
24
+ def template_scope
25
+ {
26
+ type_name: type_name,
27
+ pluralized_type_name: pluralized_type_name,
28
+ class_name: class_name,
29
+ pluralized_class_name: pluralized_class_name,
30
+ attributes: attributes,
31
+ application_class: application_class,
32
+ lookup_type: -> (name) { lookup_type(name) },
33
+ lookup_column_type: -> (name) { lookup_column_type(name) }
34
+ }
35
+ end
36
+
37
+ def add_type
38
+ add_template("app/types/type.rb.tt", "app/types/#{type_name}.rb")
39
+ end
40
+
41
+ def add_repository
42
+ add_template("app/repositories/repo.rb.tt", "app/repositories/#{pluralized_type_name}.rb")
43
+ end
44
+
45
+ def destination
46
+ "./"
47
+ end
48
+
49
+ def add_mutations
50
+ fields = "\n\n field :create#{class_name}, Types::#{class_name}[:create_mutation]\n" +
51
+ " field :update#{class_name}, Types::#{class_name}[:update_mutation]\n" +
52
+ " field :destroy#{class_name}, Types::#{class_name}[:destroy_mutation]\n"
53
+
54
+ generator.processor.insert_into_file "./app/mutation_type.rb", fields, after: /description ".*"/
55
+ end
56
+
57
+ def add_migration
58
+ add_template("migration.rb.tt", "db/migrate/#{Time.now.strftime("%Y%m%d%H%M%S")}_create_#{pluralized_type_name}.rb")
59
+ end
60
+
61
+ def application_class
62
+ @_application_class ||= Dry::Core::Inflector.camelize(File.basename(Dir.pwd))
63
+ end
64
+
65
+ def type_name
66
+ @_type_name ||= Dry::Core::Inflector.underscore(name)
67
+ end
68
+
69
+ def pluralized_type_name
70
+ @_pluralized_type_name ||= Dry::Core::Inflector.pluralize(type_name)
71
+ end
72
+
73
+ def class_name
74
+ @_class_name ||= Dry::Core::Inflector.camelize(name)
75
+ end
76
+
77
+ def pluralized_class_name
78
+ @_pluralized_class_name ||= Dry::Core::Inflector.pluralize(class_name)
79
+ end
80
+
81
+ def lookup_type(type_name)
82
+ map = {
83
+ "string" => "Kanji::Types::String",
84
+ "integer" => "Kanji::Types::Int",
85
+ "decimal" => "Kanji::Types::Decimal",
86
+ "text" => "Kanji::Types::String",
87
+ "boolean" => "Kanji::Types::Bool",
88
+ "float" => "Kanji::Types::Float",
89
+ "datetime" => "Kanji::Types::DateTime"
90
+ }
91
+
92
+ map.fetch(type_name, "Kanji::Types::Any")
93
+ end
94
+
95
+ def lookup_column_type(type_name)
96
+ map = {
97
+ "string" => "varchar(255)",
98
+ "integer" => "integer",
99
+ "decimal" => "numeric",
100
+ "text" => "text",
101
+ "boolean" => "boolean",
102
+ "datetime" => "timestamp",
103
+ "float" => "double precision"
104
+ }
105
+
106
+ map.fetch(type_name, nil)
107
+ end
108
+ end
109
+ end
110
+ end