declare_schema 0.10.1 → 0.12.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 (29) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +23 -0
  3. data/Gemfile.lock +1 -1
  4. data/README.md +16 -6
  5. data/lib/declare_schema.rb +12 -1
  6. data/lib/declare_schema/extensions/active_record/fields_declaration.rb +4 -2
  7. data/lib/declare_schema/model.rb +59 -15
  8. data/lib/declare_schema/model/column.rb +2 -2
  9. data/lib/declare_schema/model/field_spec.rb +4 -4
  10. data/lib/declare_schema/model/foreign_key_definition.rb +2 -3
  11. data/lib/declare_schema/model/habtm_model_shim.rb +2 -2
  12. data/lib/declare_schema/model/index_definition.rb +8 -6
  13. data/lib/declare_schema/schema_change/column_add.rb +3 -3
  14. data/lib/declare_schema/version.rb +1 -1
  15. data/lib/generators/declare_schema/migration/USAGE +14 -24
  16. data/lib/generators/declare_schema/migration/migration_generator.rb +40 -38
  17. data/lib/generators/declare_schema/migration/migrator.rb +18 -14
  18. data/lib/generators/declare_schema/migration/templates/migration.rb.erb +3 -3
  19. data/spec/lib/declare_schema/api_spec.rb +2 -4
  20. data/spec/lib/declare_schema/field_spec_spec.rb +3 -3
  21. data/spec/lib/declare_schema/generator_spec.rb +2 -2
  22. data/spec/lib/declare_schema/interactive_primary_key_spec.rb +8 -11
  23. data/spec/lib/declare_schema/migration_generator_spec.rb +352 -130
  24. data/spec/lib/declare_schema/model/column_spec.rb +2 -6
  25. data/spec/lib/declare_schema/model/foreign_key_definition_spec.rb +32 -8
  26. data/spec/lib/declare_schema/model/habtm_model_shim_spec.rb +4 -6
  27. data/spec/lib/declare_schema/model/index_definition_spec.rb +4 -4
  28. data/spec/spec_helper.rb +1 -1
  29. metadata +2 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4a529991bad5ab16728f11b3f6c165b62853c3b68713e0ec69d6370d7d3c0e5b
4
- data.tar.gz: 6a131f8af82b018b843f639e501371cf0db9a65b91a4acb99aea44d3eb1674d9
3
+ metadata.gz: 741e1030227b2cd6e472d1f3cc9a8f3838c927b3702087428f01b2af09a7c758
4
+ data.tar.gz: 439d95f21fd5e8f677aea5c1ef4bb52fc37c8321b0066876f0970028e75a654a
5
5
  SHA512:
6
- metadata.gz: 655ab291337bf8f11fb249de1b97608e7ff73b14ff543f9248e3f92d9bf1770553b8bc2f962c72e8763d27ae559c35bdff1f12f4b6b460a1d46abfab00e931c0
7
- data.tar.gz: b67d3340bb42b91bddd0940e0a9e5a895bd57f2017ef8d4712e1e4331ba46e78b17d9f7e9b0e60de9f921232897c0edeffe37621060632ecb18267db1ce15dc0
6
+ metadata.gz: b332745b815b6ac442158727c4d6ded6f320144f40b895ff4e303bd0e67a25d305fbed845ab3eedb9d49754078fff0f2b25b58f417fd42e00552b58b4bd67d1a
7
+ data.tar.gz: 600fb3635f8a65defcb0643501553e73befc7548da6a6821840b3a487c80e66a0933f51cbde7a83679a2ac2dc69f7f54e71aab2d878dd03b9742308cb0d845f5
data/CHANGELOG.md CHANGED
@@ -4,6 +4,26 @@ Inspired by [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
4
4
 
5
5
  Note: this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
6
 
7
+ ## [0.12.0] - 2021-04-28
8
+ ### Added
9
+ - `belongs_to` now always infers the `limit:` of the foreign key to match that of the primary key it points to.
10
+ Note: this isn't possible for polymorphic foreign keys, so it assumes `limit: 8` there...unless the schema
11
+ was migrated in the past with `limit: 4`.
12
+
13
+ ## [0.11.1] - 2021-03-26
14
+ ### Fixed
15
+ - Fixed a bug where up and down in generated migration would be empty in Rails 4.
16
+
17
+ ## [0.11.0] - 2021-03-22
18
+ ### Removed
19
+ - Removed `g|m|c` prompt entirely, since it was confusing. Instead, the migration is
20
+ always generated; the user may press ^C at the filename prompt to cancel.
21
+ The migration will be run if `--migrate` is passed; otherwise, the migrate command will be displayed to be run later.
22
+ ### Added
23
+ - Added the new configuration option `DeclareSchema.@db_migrate_command =`.
24
+ ### Fixed
25
+ - Fixed bug where foreign key constraint names are not globally unique
26
+
7
27
  ## [0.10.1] - 2021-03-18
8
28
  ### Fixed
9
29
  - Migration steps are now generated in a defined dependency order, so that--for example--indexes that depend
@@ -154,6 +174,9 @@ using the appropriate Rails configuration attributes.
154
174
  ### Added
155
175
  - Initial version from https://github.com/Invoca/hobo_fields v4.1.0.
156
176
 
177
+ [0.12.0]: https://github.com/Invoca/declare_schema/compare/v0.11.1...v0.12.0
178
+ [0.11.1]: https://github.com/Invoca/declare_schema/compare/v0.11.0...v0.11.1
179
+ [0.11.0]: https://github.com/Invoca/declare_schema/compare/v0.10.1...v0.11.0
157
180
  [0.10.1]: https://github.com/Invoca/declare_schema/compare/v0.10.0...v0.10.1
158
181
  [0.10.0]: https://github.com/Invoca/declare_schema/compare/v0.9.0...v0.10.0
159
182
  [0.9.0]: https://github.com/Invoca/declare_schema/compare/v0.8.0...v0.9.0
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- declare_schema (0.10.1)
4
+ declare_schema (0.12.0)
5
5
  rails (>= 4.2)
6
6
 
7
7
  GEM
data/README.md CHANGED
@@ -4,10 +4,10 @@ Declare your Rails/active_record model schemas and have database migrations gene
4
4
 
5
5
  ## Example
6
6
 
7
- Make a model and declare your schema within a `fields do ... end` block:
7
+ Make a model and declare your schema within a `declare_schema do ... end` block:
8
8
  ```ruby
9
9
  class Company < ActiveRecord::Base
10
- fields do
10
+ declare_schema do
11
11
  company_name :string, limit: 100
12
12
  ticker_symbol :string, limit: 4, null: true, index: true, unique: true
13
13
  employee_count :integer
@@ -57,7 +57,7 @@ during the initialization of your Rails application.
57
57
 
58
58
  ### before_generating_migration callback
59
59
 
60
- During the initializtion process for generating migrations, `DeclareSchema` will
60
+ During the initialization process for generating migrations, `DeclareSchema` will
61
61
  trigger the `eager_load!` on the `Rails` application and all `Rails::Engine`s loaded
62
62
  into scope. If you need to generate migrations for models that aren't automatically loaded by `eager_load!`,
63
63
  load them in the `before_generating_migration` block.
@@ -163,6 +163,16 @@ turn all tables into `utf8mb4` supporting tables:
163
163
  DeclareSchema.default_charset = "utf8mb4"
164
164
  DeclareSchema.default_collation = "utf8mb4_bin"
165
165
  ```
166
+ #### db:migrate Command
167
+ `declare_schema` can run the migration once it is generated, if the `--migrate` option is passed.
168
+ If not, it will display the command to run later. By default this command is
169
+ ```
170
+ bundle exec rails db:migrate
171
+ ```
172
+ If your repo has a different command to run for migrations, you can configure it like this:
173
+ ```ruby
174
+ `DeclareSchema.db_migrate_command = "bundle exec rails db:migrate_immediate"`
175
+ ```
166
176
 
167
177
  ## Declaring Character Set and Collation
168
178
  _Note: This feature currently only works for MySQL database configurations._
@@ -177,7 +187,7 @@ at three separate levels
177
187
 
178
188
  ### Table Configuration
179
189
  In order to configure a table's default character set and collation, the `charset` and
180
- `collation` arguments can be added to the `fields` block.
190
+ `collation` arguments can be added to the `declare_schema` block.
181
191
 
182
192
  For example, if you have a comments model that needs `utf8mb4` support, it would look
183
193
  like the following:
@@ -187,7 +197,7 @@ like the following:
187
197
  # frozen_string_literal: true
188
198
 
189
199
  class Comment < ActiveRecord::Base
190
- fields charset: "utf8mb4", collation: "utf8mb4_bin" do
200
+ declare_schema charset: "utf8mb4", collation: "utf8mb4_bin" do
191
201
  subject :string, limit: 255
192
202
  content :text, limit: 0xffff_ffff
193
203
  end
@@ -207,7 +217,7 @@ look like the following:
207
217
  # frozen_string_literal: true
208
218
 
209
219
  class Comment < ActiveRecord::Base
210
- fields do
220
+ declare_schema do
211
221
  subject :string, limit: 255
212
222
  context :text, limit: 0xffff_ffff, charset: "utf8mb4", collation: "utf8mb4_bin"
213
223
  end
@@ -28,10 +28,16 @@ module DeclareSchema
28
28
  @default_null = false
29
29
  @default_generate_foreign_keys = true
30
30
  @default_generate_indexing = true
31
+ @db_migrate_command =
32
+ if ActiveSupport::VERSION::MAJOR < 5
33
+ "bundle exec rake db:migrate"
34
+ else
35
+ "bundle exec rails db:migrate"
36
+ end
31
37
 
32
38
  class << self
33
39
  attr_reader :default_charset, :default_collation, :default_text_limit, :default_string_limit, :default_null,
34
- :default_generate_foreign_keys, :default_generate_indexing
40
+ :default_generate_foreign_keys, :default_generate_indexing, :db_migrate_command
35
41
 
36
42
  def to_class(type)
37
43
  case type
@@ -78,6 +84,11 @@ module DeclareSchema
78
84
  generate_indexing.in?([true, false]) or raise ArgumentError, "generate_indexing must be either true or false (got #{generate_indexing.inspect})"
79
85
  @default_generate_indexing = generate_indexing
80
86
  end
87
+
88
+ def db_migrate_command=(db_migrate_command)
89
+ db_migrate_command.is_a?(String) or raise ArgumentError, "db_migrate_command must be a string (got #{db_migrate_command.inspect})"
90
+ @db_migrate_command = db_migrate_command
91
+ end
81
92
  end
82
93
  end
83
94
 
@@ -7,12 +7,14 @@ require 'declare_schema/field_declaration_dsl'
7
7
 
8
8
  module DeclareSchema
9
9
  module Macros
10
+ attr_reader :_table_options
11
+
10
12
  def fields(table_options = {}, &block)
11
13
  # Any model that calls 'fields' gets DeclareSchema::Model behavior
12
14
  DeclareSchema::Model.mix_in(self)
13
15
 
14
16
  @include_in_migration = true
15
- @table_options = table_options
17
+ @_table_options = table_options
16
18
 
17
19
  if block
18
20
  dsl = DeclareSchema::FieldDeclarationDsl.new(self)
@@ -31,7 +33,7 @@ module DeclareSchema
31
33
 
32
34
  # @include_in_migration = false #||= options.fetch(:include_in_migration, true); options.delete(:include_in_migration)
33
35
  @include_in_migration = true # TODO: Add back or delete the include_in_migration feature
34
- @table_options = table_options
36
+ @_table_options = table_options
35
37
 
36
38
  if block
37
39
  dsl = DeclareSchema::Dsl.new(self, null: false)
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'rails'
4
-
5
3
  require 'declare_schema/extensions/module'
6
4
 
7
5
  module DeclareSchema
@@ -101,7 +99,10 @@ module DeclareSchema
101
99
  end
102
100
  end
103
101
 
104
- # Extend belongs_to so that it creates a FieldSpec for the foreign key
102
+ # Extend belongs_to so that it
103
+ # 1. creates a FieldSpec for the foreign key
104
+ # 2. declares an index on the foreign key
105
+ # 3. declares a foreign_key constraint
105
106
  def belongs_to(name, scope = nil, **options)
106
107
  column_options = {}
107
108
 
@@ -111,7 +112,10 @@ module DeclareSchema
111
112
  options[:optional] # infer :null from :optional
112
113
  end || false
113
114
  column_options[:default] = options.delete(:default) if options.has_key?(:default)
114
- column_options[:limit] = options.delete(:limit) if options.has_key?(:limit)
115
+ if options.has_key?(:limit)
116
+ options.delete(:limit)
117
+ ActiveSupport::Deprecation.warn("belongs_to limit: is deprecated since it is now inferred")
118
+ end
115
119
 
116
120
  index_options = {}
117
121
  index_options[:name] = options.delete(:index) if options.has_key?(:index)
@@ -130,7 +134,7 @@ module DeclareSchema
130
134
 
131
135
  fk_options[:dependent] = options.delete(:far_end_dependent) if options.has_key?(:far_end_dependent)
132
136
 
133
- if Rails::VERSION::MAJOR >= 5
137
+ if ActiveSupport::VERSION::MAJOR >= 5
134
138
  super
135
139
  else
136
140
  super(name, scope, options.except(:optional))
@@ -138,7 +142,25 @@ module DeclareSchema
138
142
 
139
143
  refl = reflections[name.to_s] or raise "Couldn't find reflection #{name} in #{reflections.keys}"
140
144
  fkey = refl.foreign_key or raise "Couldn't find foreign_key for #{name} in #{refl.inspect}"
141
- declare_field(fkey.to_sym, :integer, column_options)
145
+ fkey_id_column_options = column_options.dup
146
+
147
+ # Note: the foreign key limit: should match the primary key limit:. (If there is a foreign key constraint,
148
+ # those limits _must_ match.) We'd like to call _infer_fk_limit and get the limit right from the PK.
149
+ # But we can't here, because that will mess up the autoloader to follow every belongs_to association right
150
+ # when it is declared. So instead we assume :bigint (integer limit: 8) below, while also registering this
151
+ # pre_migration: callback to double-check that assumption Just In Time--right before we generate a migration.
152
+ #
153
+ # The one downside of this approach is that application code that asks the field_spec for the declared
154
+ # foreign key limit: will always get 8 back even if this is a grandfathered foreign key that points to
155
+ # a limit: 4 primary key. It seems unlikely that any application code would do this.
156
+ fkey_id_column_options[:pre_migration] = ->(field_spec) do
157
+ if (inferred_limit = _infer_fk_limit(fkey, refl))
158
+ field_spec.sql_options[:limit] = inferred_limit
159
+ end
160
+ end
161
+
162
+ declare_field(fkey.to_sym, :bigint, fkey_id_column_options)
163
+
142
164
  if refl.options[:polymorphic]
143
165
  foreign_type = options[:foreign_type] || "#{name}_type"
144
166
  _declare_polymorphic_type_field(foreign_type, column_options)
@@ -149,7 +171,29 @@ module DeclareSchema
149
171
  end
150
172
  end
151
173
 
152
- if ::Rails::VERSION::MAJOR < 5
174
+ def _infer_fk_limit(fkey, refl)
175
+ if refl.options[:polymorphic]
176
+ if (fkey_column = columns_hash[fkey.to_s]) && fkey_column.type == :integer
177
+ fkey_column.limit
178
+ end
179
+ else
180
+ klass = refl.klass or raise "Couldn't find belongs_to klass for #{name} in #{refl.inspect}"
181
+ if (pk_id_type = klass._table_options&.[](:id))
182
+ if pk_id_type == :integer
183
+ 4
184
+ end
185
+ else
186
+ if klass.table_exists? && (pk_column = klass.columns_hash[klass._declared_primary_key])
187
+ pk_id_type = pk_column.type
188
+ if pk_id_type == :integer
189
+ pk_column.limit
190
+ end
191
+ end
192
+ end
193
+ end
194
+ end
195
+
196
+ if ::ActiveSupport::VERSION::MAJOR < 5
153
197
  def primary_key
154
198
  super || 'id'
155
199
  end
@@ -157,27 +201,27 @@ module DeclareSchema
157
201
 
158
202
  # returns the primary key (String) as declared with primary_key =
159
203
  # unlike the `primary_key` method, DOES NOT query the database to find the actual primary key in use right now
160
- # if no explicit primary key set, returns the default_defined_primary_key
161
- def _defined_primary_key
204
+ # if no explicit primary key set, returns the _default_declared_primary_key
205
+ def _declared_primary_key
162
206
  if defined?(@primary_key)
163
207
  @primary_key&.to_s
164
- end || _default_defined_primary_key
208
+ end || _default_declared_primary_key
165
209
  end
166
210
 
167
211
  private
168
212
 
169
- # if this is a derived class, returns the base class's _defined_primary_key
213
+ # if this is a derived class, returns the base class's _declared_primary_key
170
214
  # otherwise, returns 'id'
171
- def _default_defined_primary_key
215
+ def _default_declared_primary_key
172
216
  if self == base_class
173
217
  'id'
174
218
  else
175
- base_class._defined_primary_key
219
+ base_class._declared_primary_key
176
220
  end
177
221
  end
178
222
 
179
223
  def _rails_default_primary_key
180
- ::DeclareSchema::Model::IndexDefinition.new(self, [_defined_primary_key.to_sym], unique: true, name: DeclareSchema::Model::IndexDefinition::PRIMARY_KEY_NAME)
224
+ ::DeclareSchema::Model::IndexDefinition.new(self, [_declared_primary_key.to_sym], unique: true, name: DeclareSchema::Model::IndexDefinition::PRIMARY_KEY_NAME)
181
225
  end
182
226
 
183
227
  # Declares the "foo_type" field that accompanies the "foo_id"
@@ -227,7 +271,7 @@ module DeclareSchema
227
271
  ActiveRecord::Coders::JSON
228
272
  elsif [:load, :dump].all? { |x| class_name_or_coder.respond_to?(x) }
229
273
  class_name_or_coder
230
- elsif Rails::VERSION::MAJOR >= 5
274
+ elsif ActiveSupport::VERSION::MAJOR >= 5
231
275
  ActiveRecord::Coders::YAMLColumn.new(attr_name, class_name_or_coder)
232
276
  else
233
277
  ActiveRecord::Coders::YAMLColumn.new(class_name_or_coder)
@@ -53,13 +53,13 @@ module DeclareSchema
53
53
  def deserialize_default_value(column, type, default_value)
54
54
  type or raise ArgumentError, "must pass type; got #{type.inspect}"
55
55
 
56
- case Rails::VERSION::MAJOR
56
+ case ActiveSupport::VERSION::MAJOR
57
57
  when 4
58
58
  # TODO: Delete this Rails 4 support ASAP! This could be wrong, since it's using the type of the old column...which
59
59
  # might be getting migrated to a new type. We should be using just type as below. -Colin
60
60
  column.type_cast_from_database(default_value)
61
61
  else
62
- cast_type = ActiveRecord::Base.connection.send(:lookup_cast_type, type) or
62
+ cast_type = ActiveRecord::Base.connection.send(:lookup_cast_type, type.to_s) or
63
63
  raise "cast_type not found for #{type}"
64
64
  cast_type.deserialize(default_value)
65
65
  end
@@ -47,9 +47,9 @@ module DeclareSchema
47
47
  end
48
48
 
49
49
  def initialize(model, name, type, position: 0, **options)
50
- _defined_primary_key = model._defined_primary_key
50
+ _declared_primary_key = model._declared_primary_key
51
51
 
52
- name.to_s == _defined_primary_key and raise ArgumentError, "you may not provide a field spec for the primary key #{name.inspect}"
52
+ name.to_s == _declared_primary_key and raise ArgumentError, "you may not provide a field spec for the primary key #{name.inspect}"
53
53
 
54
54
  @model = model
55
55
  @name = name.to_sym
@@ -99,8 +99,8 @@ module DeclareSchema
99
99
 
100
100
  if @type.in?([:text, :string])
101
101
  if ActiveRecord::Base.connection.class.name.match?(/mysql/i)
102
- @options[:charset] ||= model.table_options[:charset] || ::DeclareSchema.default_charset
103
- @options[:collation] ||= model.table_options[:collation] || ::DeclareSchema.default_collation
102
+ @options[:charset] ||= model._table_options&.[](:charset) || ::DeclareSchema.default_charset
103
+ @options[:collation] ||= model._table_options&.[](:collation) || ::DeclareSchema.default_collation
104
104
  else
105
105
  @options.delete(:charset)
106
106
  @options.delete(:collation)
@@ -19,9 +19,8 @@ module DeclareSchema
19
19
  @parent_table_name = options[:parent_table]&.to_s
20
20
  @foreign_key_name = options[:foreign_key]&.to_s || @foreign_key
21
21
 
22
- @constraint_name = options[:constraint_name]&.to_s ||
23
- options[:index_name]&.to_s ||
24
- IndexDefinition.index_name(@foreign_key_name)
22
+ @constraint_name = options[:constraint_name]&.to_s.presence ||
23
+ model.connection.index_name(model.table_name, column: @foreign_key_name)
25
24
  @on_delete_cascade = options[:dependent] == :delete
26
25
  end
27
26
 
@@ -29,7 +29,7 @@ module DeclareSchema
29
29
  @connection = connection
30
30
  end
31
31
 
32
- def table_options
32
+ def _table_options
33
33
  {}
34
34
  end
35
35
 
@@ -47,7 +47,7 @@ module DeclareSchema
47
47
  false # no single-column primary key in database
48
48
  end
49
49
 
50
- def _defined_primary_key
50
+ def _declared_primary_key
51
51
  false # no single-column primary key declared
52
52
  end
53
53
 
@@ -37,7 +37,7 @@ module DeclareSchema
37
37
  def for_model(model, old_table_name = nil)
38
38
  t = old_table_name || model.table_name
39
39
 
40
- primary_key_columns = Array(model.connection.primary_key(t)).presence || sqlite_compound_primary_key(model, t) or
40
+ primary_key_columns = Array(model.connection.primary_key(t)).presence || fallback_find_primary_key(model, t) or
41
41
  raise "could not find primary key for table #{t} in #{model.connection.columns(t).inspect}"
42
42
 
43
43
  primary_key_found = false
@@ -67,8 +67,8 @@ module DeclareSchema
67
67
  private
68
68
 
69
69
  # This is the old approach which is still needed for MySQL in Rails 4 and SQLite
70
- def sqlite_compound_primary_key(model, table)
71
- ActiveRecord::Base.connection.class.name.match?(/SQLite3Adapter/) || Rails::VERSION::MAJOR < 5 or return nil
70
+ def fallback_find_primary_key(model, table)
71
+ ActiveRecord::Base.connection.class.name.match?(/SQLite3Adapter/) || ActiveSupport::VERSION::MAJOR < 5 or return nil
72
72
 
73
73
  connection = model.connection.dup
74
74
 
@@ -83,9 +83,11 @@ module DeclareSchema
83
83
  end
84
84
  end
85
85
 
86
- pk_index = connection.indexes(table).find { |index| index.name.to_s == PRIMARY_KEY_NAME } or return nil
87
-
88
- Array(pk_index.columns)
86
+ if (pk_index = connection.indexes(table).find { |index| index.name.to_s == PRIMARY_KEY_NAME })
87
+ Array(pk_index.columns)
88
+ elsif model.connection.columns(table).any? { |col| col.name == 'id' }
89
+ ['id']
90
+ end
89
91
  end
90
92
  end
91
93
 
@@ -6,9 +6,9 @@ module DeclareSchema
6
6
  module SchemaChange
7
7
  class ColumnAdd < Base
8
8
  def initialize(table_name, column_name, column_type, **column_options)
9
- @table_name = table_name
10
- @column_name = column_name
11
- @column_type = column_type
9
+ @table_name = table_name or raise ArgumentError, "must provide table_name"
10
+ @column_name = column_name or raise ArgumentError, "must provide column_name"
11
+ @column_type = column_type or raise ArgumentError, "must provide column_type"
12
12
  @column_options = column_options
13
13
  end
14
14
 
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module DeclareSchema
4
- VERSION = "0.10.1"
4
+ VERSION = "0.12.0"
5
5
  end