hanami-cli 2.1.1 → 2.2.0.beta2

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 (80) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ci.yml +29 -13
  3. data/.rubocop.yml +2 -0
  4. data/CHANGELOG.md +28 -0
  5. data/Gemfile +6 -1
  6. data/README.md +13 -7
  7. data/docker-compose.yml +14 -0
  8. data/hanami-cli.gemspec +2 -2
  9. data/lib/hanami/cli/command.rb +2 -2
  10. data/lib/hanami/cli/commands/app/command.rb +2 -16
  11. data/lib/hanami/cli/commands/app/db/command.rb +148 -0
  12. data/lib/hanami/cli/commands/app/db/create.rb +21 -11
  13. data/lib/hanami/cli/commands/app/db/drop.rb +21 -10
  14. data/lib/hanami/cli/commands/app/db/migrate.rb +50 -12
  15. data/lib/hanami/cli/commands/app/db/prepare.rb +68 -0
  16. data/lib/hanami/cli/commands/app/db/seed.rb +22 -21
  17. data/lib/hanami/cli/commands/app/db/structure/dump.rb +32 -7
  18. data/lib/hanami/cli/commands/app/db/structure/load.rb +54 -0
  19. data/lib/hanami/cli/commands/app/db/utils/database.rb +100 -75
  20. data/lib/hanami/cli/commands/app/db/utils/mysql.rb +59 -6
  21. data/lib/hanami/cli/commands/app/db/utils/postgres.rb +42 -21
  22. data/lib/hanami/cli/commands/app/db/utils/sqlite.rb +58 -10
  23. data/lib/hanami/cli/commands/app/db/version.rb +14 -8
  24. data/lib/hanami/cli/commands/app/generate/action.rb +4 -3
  25. data/lib/hanami/cli/commands/app/generate/command.rb +60 -0
  26. data/lib/hanami/cli/commands/app/generate/component.rb +49 -0
  27. data/lib/hanami/cli/commands/app/generate/migration.rb +47 -0
  28. data/lib/hanami/cli/commands/app/generate/operation.rb +26 -0
  29. data/lib/hanami/cli/commands/app/generate/part.rb +1 -1
  30. data/lib/hanami/cli/commands/app/generate/relation.rb +29 -0
  31. data/lib/hanami/cli/commands/app/generate/repo.rb +42 -0
  32. data/lib/hanami/cli/commands/app/generate/slice.rb +20 -3
  33. data/lib/hanami/cli/commands/app/generate/struct.rb +27 -0
  34. data/lib/hanami/cli/commands/app/install.rb +1 -1
  35. data/lib/hanami/cli/commands/app/middleware.rb +1 -1
  36. data/lib/hanami/cli/commands/app/server.rb +2 -2
  37. data/lib/hanami/cli/commands/app.rb +21 -2
  38. data/lib/hanami/cli/commands/gem/new.rb +78 -14
  39. data/lib/hanami/cli/errors.rb +28 -0
  40. data/lib/hanami/cli/files.rb +22 -0
  41. data/lib/hanami/cli/generators/app/action_context.rb +5 -13
  42. data/lib/hanami/cli/generators/app/component/component.erb +8 -0
  43. data/lib/hanami/cli/generators/app/component/slice_component.erb +8 -0
  44. data/lib/hanami/cli/generators/app/component.rb +61 -0
  45. data/lib/hanami/cli/generators/app/component_context.rb +82 -0
  46. data/lib/hanami/cli/generators/app/migration.rb +66 -0
  47. data/lib/hanami/cli/generators/app/operation.rb +49 -0
  48. data/lib/hanami/cli/generators/app/part_context.rb +5 -21
  49. data/lib/hanami/cli/generators/app/relation.rb +45 -0
  50. data/lib/hanami/cli/generators/app/repo.rb +41 -0
  51. data/lib/hanami/cli/generators/app/ruby_file_writer.rb +151 -0
  52. data/lib/hanami/cli/generators/app/slice/{entities.erb → operation.erb} +1 -3
  53. data/lib/hanami/cli/generators/app/slice/relation.erb +8 -0
  54. data/lib/hanami/cli/generators/app/slice/{slice.erb → repo.erb} +3 -1
  55. data/lib/hanami/cli/generators/app/slice/struct.erb +8 -0
  56. data/lib/hanami/cli/generators/app/slice.rb +14 -6
  57. data/lib/hanami/cli/generators/app/slice_context.rb +9 -2
  58. data/lib/hanami/cli/generators/app/struct.rb +40 -0
  59. data/lib/hanami/cli/generators/app/view_context.rb +4 -16
  60. data/lib/hanami/cli/generators/constants.rb +39 -0
  61. data/lib/hanami/cli/generators/context.rb +48 -0
  62. data/lib/hanami/cli/generators/gem/app/action.erb +3 -0
  63. data/lib/hanami/cli/generators/gem/app/env.erb +4 -0
  64. data/lib/hanami/cli/generators/gem/app/gemfile.erb +11 -0
  65. data/lib/hanami/cli/generators/gem/app/gitignore.erb +4 -1
  66. data/lib/hanami/cli/generators/gem/app/operation.erb +13 -0
  67. data/lib/hanami/cli/generators/gem/app/relation.erb +10 -0
  68. data/lib/hanami/cli/generators/gem/app/repo.erb +10 -0
  69. data/lib/hanami/cli/generators/gem/app/struct.erb +10 -0
  70. data/lib/hanami/cli/generators/gem/app.rb +19 -0
  71. data/lib/hanami/cli/ruby_file_generator.rb +123 -0
  72. data/lib/hanami/cli/version.rb +1 -1
  73. metadata +39 -17
  74. data/lib/hanami/cli/commands/app/db/create_migration.rb +0 -32
  75. data/lib/hanami/cli/commands/app/db/reset.rb +0 -28
  76. data/lib/hanami/cli/commands/app/db/rollback.rb +0 -81
  77. data/lib/hanami/cli/commands/app/db/sample_data.rb +0 -42
  78. data/lib/hanami/cli/commands/app/db/setup.rb +0 -26
  79. data/lib/hanami/cli/commands/app/db/utils/database_config.rb +0 -60
  80. data/lib/hanami/cli/generators/app/slice/repository.erb +0 -10
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ module <%= camelized_slice_name %>
4
+ module DB
5
+ class Struct < <%= camelized_app_name %>::DB::Struct
6
+ end
7
+ end
8
+ end
@@ -19,18 +19,20 @@ module Hanami
19
19
 
20
20
  # @since 2.0.0
21
21
  # @api private
22
- def call(app, slice, url, context: SliceContext.new(inflector, app, slice, url)) # rubocop:disable Metrics/AbcSize
22
+ def call(app, slice, url, context: nil, **opts)
23
+ context ||= SliceContext.new(inflector, app, slice, url, **opts)
24
+
23
25
  fs.inject_line_at_class_bottom(
24
26
  fs.join("config", "routes.rb"), "class Routes", t("routes.erb", context).chomp
25
27
  )
26
28
 
27
29
  fs.mkdir(directory = "slices/#{slice}")
28
30
 
29
- # fs.write("#{directory}/config/slice.rb", t("slice.erb", context))
30
31
  fs.write(fs.join(directory, "action.rb"), t("action.erb", context))
31
32
  fs.write(fs.join(directory, "view.rb"), t("view.erb", context))
32
33
  fs.write(fs.join(directory, "views", "helpers.rb"), t("helpers.erb", context))
33
34
  fs.write(fs.join(directory, "templates", "layouts", "app.html.erb"), t("app_layout.erb", context))
35
+ fs.write(fs.join(directory, "operation.rb"), t("operation.erb", context))
34
36
 
35
37
  if context.bundled_assets?
36
38
  fs.write(fs.join(directory, "assets", "js", "app.js"), t("app_js.erb", context))
@@ -38,15 +40,21 @@ module Hanami
38
40
  fs.write(fs.join(directory, "assets", "images", "favicon.ico"), file("favicon.ico"))
39
41
  end
40
42
 
41
- # fs.write(fs.join(directory, "/entities.rb"), t("entities.erb", context))
42
- # fs.write(fs.join(directory, "/repository.rb"), t("repository.erb", context))
43
+ if context.generate_db?
44
+ fs.write(fs.join(directory, "db", "relation.rb"), t("relation.erb", context))
45
+ fs.write(fs.join(directory, "relations", ".keep"), t("keep.erb", context))
46
+
47
+ fs.write(fs.join(directory, "db", "repo.rb"), t("repo.erb", context))
48
+ fs.write(fs.join(directory, "repos", ".keep"), t("keep.erb", context))
49
+
50
+ fs.write(fs.join(directory, "db", "struct.rb"), t("struct.erb", context))
51
+ fs.write(fs.join(directory, "structs", ".keep"), t("keep.erb", context))
52
+ end
43
53
 
44
54
  fs.write(fs.join(directory, "actions/.keep"), t("keep.erb", context))
45
55
  fs.write(fs.join(directory, "views/.keep"), t("keep.erb", context))
46
56
  fs.write(fs.join(directory, "templates/.keep"), t("keep.erb", context))
47
57
  fs.write(fs.join(directory, "templates/layouts/.keep"), t("keep.erb", context))
48
- # fs.write(fs.join(directory, entities/.keep"), t("keep.erb", context))
49
- # fs.write(fs.join(directory, repositories/.keep"), t("keep.erb", context))
50
58
  end
51
59
 
52
60
  private
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require_relative "../context"
4
+ require_relative "../constants"
4
5
 
5
6
  module Hanami
6
7
  module CLI
@@ -11,10 +12,10 @@ module Hanami
11
12
  class SliceContext < Generators::Context
12
13
  # @since 2.0.0
13
14
  # @api private
14
- def initialize(inflector, app, slice, url)
15
+ def initialize(inflector, app, slice, url, **options)
15
16
  @slice = slice
16
17
  @url = url
17
- super(inflector, app)
18
+ super(inflector, app, **options)
18
19
  end
19
20
 
20
21
  # @since 2.0.0
@@ -47,6 +48,12 @@ module Hanami
47
48
  %(<%= javascript_tag "app" %>)
48
49
  end
49
50
 
51
+ # @since 2.2.0
52
+ # @api private
53
+ def generate_db?
54
+ !options.fetch(:skip_db, false)
55
+ end
56
+
50
57
  private
51
58
 
52
59
  attr_reader :slice
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Hanami
4
+ module CLI
5
+ module Generators
6
+ module App
7
+ # @since 2.2.0
8
+ # @api private
9
+ class Struct
10
+ # @since 2.2.0
11
+ # @api private
12
+ def initialize(fs:, inflector:, out: $stdout)
13
+ @fs = fs
14
+ @inflector = inflector
15
+ @out = out
16
+ end
17
+
18
+ # @since 2.2.0
19
+ # @api private
20
+ def call(key:, namespace:, base_path:)
21
+ RubyFileWriter.new(
22
+ fs: fs,
23
+ inflector: inflector,
24
+ ).call(
25
+ key: key,
26
+ namespace: namespace,
27
+ base_path: base_path,
28
+ extra_namespace: "Structs",
29
+ relative_parent_class: "DB::Struct",
30
+ )
31
+ end
32
+
33
+ private
34
+
35
+ attr_reader :fs, :inflector, :out
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
@@ -2,6 +2,7 @@
2
2
 
3
3
  require_relative "slice_context"
4
4
  require "dry/files/path"
5
+ require_relative "../constants"
5
6
 
6
7
  module Hanami
7
8
  module CLI
@@ -12,19 +13,6 @@ module Hanami
12
13
  # @since 2.1.0
13
14
  # @api private
14
15
  class ViewContext < SliceContext
15
- # TODO: move these constants somewhere that will let us reuse them
16
- KEY_SEPARATOR = "."
17
- private_constant :KEY_SEPARATOR
18
-
19
- NAMESPACE_SEPARATOR = "::"
20
- private_constant :NAMESPACE_SEPARATOR
21
-
22
- INDENTATION = " "
23
- private_constant :INDENTATION
24
-
25
- OFFSET = INDENTATION * 2
26
- private_constant :OFFSET
27
-
28
16
  # @since 2.1.0
29
17
  # @api private
30
18
  attr_reader :key
@@ -76,7 +64,7 @@ module Hanami
76
64
  # @api private
77
65
  def module_namespace_declaration
78
66
  namespaces.each_with_index.map { |token, i|
79
- "#{OFFSET}#{INDENTATION * i}module #{inflector.camelize(token)}"
67
+ "#{NESTED_OFFSET}#{INDENTATION * i}module #{inflector.camelize(token)}"
80
68
  }.join($/)
81
69
  end
82
70
 
@@ -84,14 +72,14 @@ module Hanami
84
72
  # @api private
85
73
  def module_namespace_end
86
74
  namespaces.each_with_index.map { |_, i|
87
- "#{OFFSET}#{INDENTATION * i}end"
75
+ "#{NESTED_OFFSET}#{INDENTATION * i}end"
88
76
  }.reverse.join($/)
89
77
  end
90
78
 
91
79
  # @since 2.1.0
92
80
  # @api private
93
81
  def module_namespace_offset
94
- "#{OFFSET}#{INDENTATION * namespaces.count}"
82
+ "#{NESTED_OFFSET}#{INDENTATION * namespaces.count}"
95
83
  end
96
84
  end
97
85
  end
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Hanami
4
+ module CLI
5
+ # @since 2.2.0
6
+ # @api private
7
+ module Generators
8
+ # @since 2.2.0
9
+ # @api private
10
+ INDENTATION = " "
11
+ private_constant :INDENTATION
12
+
13
+ # @since 2.2.0
14
+ # @api private
15
+ OFFSET = INDENTATION
16
+ private_constant :OFFSET
17
+
18
+ # @since 2.2.0
19
+ # @api private
20
+ NESTED_OFFSET = INDENTATION * 2
21
+ private_constant :OFFSET
22
+
23
+ # @since 2.2.0
24
+ # @api private
25
+ KEY_SEPARATOR = %r{[.\/]}
26
+ private_constant :KEY_SEPARATOR
27
+
28
+ # @since 2.2.0
29
+ # @api private
30
+ MATCHER_PATTERN = /::|\./
31
+ private_constant :MATCHER_PATTERN
32
+
33
+ # @since 2.2.0
34
+ # @api private
35
+ NAMESPACE_SEPARATOR = "::"
36
+ private_constant :NAMESPACE_SEPARATOR
37
+ end
38
+ end
39
+ end
@@ -80,6 +80,44 @@ module Hanami
80
80
  !options.fetch(:skip_assets, false)
81
81
  end
82
82
 
83
+ # @since 2.2.0
84
+ # @api private
85
+ def generate_db?
86
+ !options.fetch(:skip_db, false)
87
+ end
88
+
89
+ # @since 2.2.0
90
+ # @api private
91
+ def generate_sqlite?
92
+ generate_db? && database_option == Commands::Gem::New::DATABASE_SQLITE
93
+ end
94
+
95
+ # @since 2.2.0
96
+ # @api private
97
+ def generate_postgres?
98
+ generate_db? && database_option == Commands::Gem::New::DATABASE_POSTGRES
99
+ end
100
+
101
+ # @since 2.2.0
102
+ # @api private
103
+ def generate_mysql?
104
+ generate_db? && database_option == Commands::Gem::New::DATABASE_MYSQL
105
+ end
106
+
107
+ # @since 2.2.0
108
+ # @api private
109
+ def database_url
110
+ if generate_sqlite?
111
+ "sqlite://db/#{app}.sqlite"
112
+ elsif generate_postgres?
113
+ "postgres://localhost/#{app}"
114
+ elsif generate_mysql?
115
+ "mysql2://localhost/#{app}"
116
+ else
117
+ raise "Unknown database option: #{database_option}"
118
+ end
119
+ end
120
+
83
121
  # @since 2.1.0
84
122
  # @api private
85
123
  def bundled_views?
@@ -92,6 +130,12 @@ module Hanami
92
130
  Hanami.bundled?("hanami-assets")
93
131
  end
94
132
 
133
+ # @since 2.2.0
134
+ # @api private
135
+ def bundled_dry_monads?
136
+ Hanami.bundled?("dry-monads")
137
+ end
138
+
95
139
  # @since 2.1.0
96
140
  # @api private
97
141
  #
@@ -102,6 +146,10 @@ module Hanami
102
146
 
103
147
  private
104
148
 
149
+ def database_option
150
+ options.fetch(:database, Commands::Gem::New::DATABASE_SQLITE)
151
+ end
152
+
105
153
  # @since 2.0.0
106
154
  # @api private
107
155
  attr_reader :inflector
@@ -2,8 +2,11 @@
2
2
  # frozen_string_literal: true
3
3
 
4
4
  require "hanami/action"
5
+ require "dry/monads"
5
6
 
6
7
  module <%= camelized_app_name %>
7
8
  class Action < Hanami::Action
9
+ # Provide `Success` and `Failure` for pattern matching on operation results
10
+ include Dry::Monads[:result]
8
11
  end
9
12
  end
@@ -0,0 +1,4 @@
1
+ # This is checked into source control, so put sensitive values into `.env.local`
2
+ <%- if generate_db? -%>
3
+ DATABASE_URL=<%= database_url %>
4
+ <%- end -%>
@@ -7,13 +7,24 @@ source "https://rubygems.org"
7
7
  <%= hanami_gem("assets") %>
8
8
  <%- end -%>
9
9
  <%= hanami_gem("controller") %>
10
+ <%- if generate_db? -%>
11
+ <%= hanami_gem("db") %>
12
+ <%- end -%>
10
13
  <%= hanami_gem("router") %>
11
14
  <%= hanami_gem("validations") %>
12
15
  <%= hanami_gem("view") %>
13
16
 
14
17
  gem "dry-types", "~> 1.0", ">= 1.6.1"
18
+ gem "dry-operation", github: "dry-rb/dry-operation"
15
19
  gem "puma"
16
20
  gem "rake"
21
+ <%- if generate_sqlite? -%>
22
+ gem "sqlite3"
23
+ <%- elsif generate_postgres? -%>
24
+ gem "pg"
25
+ <%- elsif generate_mysql? -%>
26
+ gem "mysql2"
27
+ <%- end -%>
17
28
 
18
29
  group :development do
19
30
  <%= hanami_gem("webconsole") %>
@@ -1,6 +1,9 @@
1
- .env
1
+ .env*.local
2
2
  log/*
3
3
  <%- if generate_assets? -%>
4
4
  public/
5
5
  node_modules/
6
6
  <%- end -%>
7
+ <%- if generate_sqlite? -%>
8
+ db/*.sqlite
9
+ <%- end -%>
@@ -0,0 +1,13 @@
1
+ # auto_register: false
2
+ # frozen_string_literal: true
3
+
4
+ require "dry/operation"
5
+
6
+ module <%= camelized_app_name %>
7
+ class Operation < Dry::Operation
8
+ <%- if generate_db? -%>
9
+ # Provide `transaction do ... end` method for database transactions
10
+ include Dry::Operation::Extensions::ROM
11
+ <%- end -%>
12
+ end
13
+ end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "hanami/db/relation"
4
+
5
+ module <%= camelized_app_name %>
6
+ module DB
7
+ class Relation < Hanami::DB::Relation
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "hanami/db/repo"
4
+
5
+ module <%= camelized_app_name %>
6
+ module DB
7
+ class Repo < Hanami::DB::Repo
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "hanami/db/struct"
4
+
5
+ module <%= camelized_app_name %>
6
+ module DB
7
+ class Struct < Hanami::DB::Struct
8
+ end
9
+ end
10
+ end
@@ -68,6 +68,25 @@ module Hanami
68
68
  fs.write("app/assets/images/favicon.ico", file("favicon.ico"))
69
69
  end
70
70
 
71
+ if context.generate_db?
72
+ fs.write("app/db/relation.rb", t("relation.erb", context))
73
+ fs.write("app/relations/.keep", t("keep.erb", context))
74
+
75
+ fs.write("app/db/repo.rb", t("repo.erb", context))
76
+ fs.write("app/repos/.keep", t("keep.erb", context))
77
+
78
+ fs.write("app/db/struct.rb", t("struct.erb", context))
79
+ fs.write("app/structs/.keep", t("keep.erb", context))
80
+
81
+ fs.write("config/db/migrate/.keep" , t("keep.erb", context))
82
+
83
+ if context.generate_sqlite?
84
+ fs.write("db/.keep" , t("keep.erb", context))
85
+ end
86
+ end
87
+
88
+ fs.write("app/operation.rb", t("operation.erb", context))
89
+
71
90
  fs.write("public/404.html", file("404.html"))
72
91
  fs.write("public/500.html", file("500.html"))
73
92
  end
@@ -0,0 +1,123 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "ripper"
4
+
5
+ module Hanami
6
+ module CLI
7
+ class RubyFileGenerator
8
+ # @api private
9
+ # @since 2.2.0
10
+ class GeneratedUnparseableCodeError < Error
11
+ def initialize(source_code)
12
+ super(
13
+ <<~ERROR_MESSAGE
14
+ Sorry, the code we generated is not valid Ruby.
15
+
16
+ Here's what we got:
17
+
18
+ #{source_code}
19
+
20
+ Please fix the errors and try again.
21
+ ERROR_MESSAGE
22
+ )
23
+ end
24
+ end
25
+
26
+ INDENT = " "
27
+
28
+ def self.class(class_name, **args)
29
+ new(class_name: class_name, **args).to_s
30
+ end
31
+
32
+ def self.module(*names, **args)
33
+ module_names = if names.first.is_a?(Array)
34
+ names.first
35
+ else
36
+ names
37
+ end
38
+
39
+ new(modules: module_names, class_name: nil, parent_class: nil, **args).to_s
40
+ end
41
+
42
+ def initialize(
43
+ class_name: nil,
44
+ parent_class: nil,
45
+ modules: [],
46
+ header: [],
47
+ body: []
48
+ )
49
+ @class_name = class_name
50
+ @parent_class = parent_class
51
+ @modules = modules
52
+ @header = header.any? ? (header + [""]) : []
53
+ @body = body
54
+ end
55
+
56
+ def to_s
57
+ definition = lines(modules).map { |line| "#{line}\n" }.join
58
+ source_code = [header, definition].flatten.join("\n")
59
+ ensure_parseable!(source_code)
60
+ source_code
61
+ end
62
+
63
+ private
64
+
65
+ attr_reader(
66
+ :class_name,
67
+ :parent_class,
68
+ :modules,
69
+ :header,
70
+ :body
71
+ )
72
+
73
+ def lines(remaining_modules)
74
+ this_module, *rest_modules = remaining_modules
75
+ if this_module
76
+ with_module_lines(this_module, lines(rest_modules))
77
+ elsif class_name
78
+ class_lines
79
+ else
80
+ body
81
+ end
82
+ end
83
+
84
+ def with_module_lines(module_name, contents_lines)
85
+ [
86
+ "module #{module_name}",
87
+ *contents_lines.map { |line| indent(line) },
88
+ "end"
89
+ ]
90
+ end
91
+
92
+ def class_lines
93
+ [
94
+ class_definition,
95
+ *body.map { |line| indent(line) },
96
+ "end"
97
+ ].compact
98
+ end
99
+
100
+ def class_definition
101
+ if parent_class
102
+ "class #{class_name} < #{parent_class}"
103
+ else
104
+ "class #{class_name}"
105
+ end
106
+ end
107
+
108
+ def indent(line)
109
+ if line.strip.empty?
110
+ ""
111
+ else
112
+ INDENT + line
113
+ end
114
+ end
115
+
116
+ def ensure_parseable!(source_code)
117
+ unless Ripper.sexp(source_code)
118
+ raise GeneratedUnparseableCodeError.new(source_code)
119
+ end
120
+ end
121
+ end
122
+ end
123
+ end
@@ -6,6 +6,6 @@ module Hanami
6
6
  #
7
7
  # @api public
8
8
  # @since 2.0.0
9
- VERSION = "2.1.1"
9
+ VERSION = "2.2.0.beta2"
10
10
  end
11
11
  end