kanji-web 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.
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