declare_schema 0.1.3 → 0.3.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 (33) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +28 -1
  3. data/Gemfile +0 -1
  4. data/Gemfile.lock +1 -3
  5. data/README.md +20 -0
  6. data/Rakefile +13 -20
  7. data/gemfiles/rails_4.gemfile +0 -1
  8. data/gemfiles/rails_5.gemfile +0 -1
  9. data/gemfiles/rails_6.gemfile +0 -1
  10. data/lib/declare_schema/model.rb +27 -24
  11. data/lib/declare_schema/model/field_spec.rb +1 -12
  12. data/lib/declare_schema/version.rb +1 -1
  13. data/lib/generators/declare_schema/migration/migration_generator.rb +20 -14
  14. data/lib/generators/declare_schema/migration/migrator.rb +50 -31
  15. data/lib/generators/declare_schema/migration/templates/migration.rb.erb +1 -1
  16. data/lib/generators/declare_schema/support/eval_template.rb +12 -3
  17. data/lib/generators/declare_schema/support/model.rb +77 -2
  18. data/spec/lib/declare_schema/api_spec.rb +125 -0
  19. data/spec/lib/declare_schema/field_declaration_dsl_spec.rb +8 -4
  20. data/spec/lib/declare_schema/generator_spec.rb +57 -0
  21. data/spec/lib/declare_schema/interactive_primary_key_spec.rb +51 -0
  22. data/spec/lib/declare_schema/migration_generator_spec.rb +795 -0
  23. data/spec/lib/declare_schema/prepare_testapp.rb +31 -0
  24. data/spec/lib/generators/declare_schema/migration/migrator_spec.rb +72 -0
  25. data/spec/spec_helper.rb +26 -0
  26. metadata +11 -12
  27. data/lib/generators/declare_schema/model/templates/model_injection.rb.erb +0 -25
  28. data/test/api.rdoctest +0 -136
  29. data/test/generators.rdoctest +0 -62
  30. data/test/interactive_primary_key.rdoctest +0 -56
  31. data/test/migration_generator.rdoctest +0 -846
  32. data/test/migration_generator_comments.rdoctestDISABLED +0 -74
  33. data/test/prepare_testapp.rb +0 -15
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'fileutils'
4
+ require 'tmpdir'
5
+
6
+ TESTAPP_PATH = ENV['TESTAPP_PATH'] || File.join(Dir.tmpdir, 'declare_schema_testapp') unless defined?(TESTAPP_PATH)
7
+ FileUtils.chdir(TESTAPP_PATH)
8
+
9
+ system "rm -rf app/models/ad* app/models/alpha*"
10
+ system "rm -rf test/models/ad* test/models/alpha*"
11
+ system "rm -rf test/fixtures/ad* test/fixtures/alpha*"
12
+ system "rm -rf db/migrate/*"
13
+ system "mkdir -p #{TESTAPP_PATH}/app/assets/config"
14
+ system "echo '' >> #{TESTAPP_PATH}/app/assets/config/manifest.js"
15
+
16
+ require "#{TESTAPP_PATH}/config/environment"
17
+
18
+ require 'rails/generators'
19
+ Rails::Generators.configure!(Rails.application.config.generators)
20
+
21
+ ActiveRecord::Base.connection.schema_cache.clear!
22
+
23
+ (ActiveRecord::Base.connection.tables - Generators::DeclareSchema::Migration::Migrator.always_ignore_tables).each do |table|
24
+ ActiveRecord::Base.connection.execute("DROP TABLE #{ActiveRecord::Base.connection.quote_table_name(table)}")
25
+ end
26
+
27
+ ActiveRecord::Base.send(:descendants).each do |model|
28
+ unless model.name['Active'] || model.name['Application']
29
+ nuke_model_class(model)
30
+ end
31
+ end
@@ -0,0 +1,72 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rails'
4
+ require 'rails/generators'
5
+
6
+ module Generators
7
+ module DeclareSchema
8
+ module Migration
9
+ RSpec.describe Migrator do
10
+ before do
11
+ ActiveRecord::Base.connection.tables
12
+ end
13
+
14
+ subject { described_class.new }
15
+
16
+ describe 'format_options' do
17
+ let(:mysql_longtext_limit) { 0xffff_ffff }
18
+
19
+ context 'MySQL' do
20
+ before do
21
+ expect(::DeclareSchema::Model::FieldSpec).to receive(:mysql_text_limits?).and_return(true)
22
+ end
23
+
24
+ it 'returns text limits' do
25
+ expect(subject.format_options({ limit: mysql_longtext_limit }, :text)).to eq(["limit: #{mysql_longtext_limit}"])
26
+ end
27
+ end
28
+
29
+ context 'non-MySQL' do
30
+ before do
31
+ expect(::DeclareSchema::Model::FieldSpec).to receive(:mysql_text_limits?).and_return(false)
32
+ end
33
+
34
+ it 'returns text limits' do
35
+ expect(subject.format_options({ limit: mysql_longtext_limit }, :text)).to eq([])
36
+ end
37
+ end
38
+ end
39
+
40
+ describe '#before_generating_migration' do
41
+ it 'requires a block be passed' do
42
+ expect { described_class.before_generating_migration }.to raise_error(ArgumentError, 'A block is required when setting the before_generating_migration callback')
43
+ end
44
+ end
45
+
46
+ describe 'load_rails_models' do
47
+ before do
48
+ expect(Rails.application).to receive(:eager_load!)
49
+ expect(Rails::Engine).to receive(:subclasses).and_return([])
50
+ end
51
+
52
+ subject { described_class.new.load_rails_models }
53
+
54
+ context 'when a before_generating_migration callback is configured' do
55
+ let(:dummy_proc) { -> {} }
56
+
57
+ before do
58
+ described_class.before_generating_migration(&dummy_proc)
59
+ expect(dummy_proc).to receive(:call).and_return(true)
60
+ end
61
+
62
+ it { should be_truthy }
63
+ end
64
+
65
+ context 'when no before_generating_migration callback is configured' do
66
+ it { should be_nil }
67
+ end
68
+ end
69
+ end
70
+ end
71
+ end
72
+ end
@@ -22,6 +22,32 @@ RSpec.configure do |config|
22
22
 
23
23
  RSpec::Support::ObjectFormatter.default_instance.max_formatted_output_length = 2_000
24
24
 
25
+ def active_record_base_class
26
+ if Rails::VERSION::MAJOR == 4
27
+ 'ActiveRecord::Base'
28
+ else
29
+ 'ApplicationRecord'
30
+ end
31
+ end
32
+
33
+ def migrate(renames = {})
34
+ up, down = Generators::DeclareSchema::Migration::Migrator.run(renames)
35
+ ActiveRecord::Migration.class_eval(up)
36
+ ActiveRecord::Base.send(:descendants).each { |model| model.reset_column_information }
37
+ [up, down]
38
+ end
39
+
40
+ def nuke_model_class(klass)
41
+ ActiveSupport::DescendantsTracker.instance_eval do
42
+ direct_descendants = class_variable_get('@@direct_descendants')
43
+ direct_descendants[ActiveRecord::Base] = direct_descendants[ActiveRecord::Base].to_a.reject { |descendant| descendant == klass }
44
+ if defined?(ApplicationRecord)
45
+ direct_descendants[ApplicationRecord] = direct_descendants[ApplicationRecord].to_a.reject { |descendant| descendant == klass }
46
+ end
47
+ end
48
+ Object.instance_eval { remove_const(klass.name.to_sym) rescue nil }
49
+ end
50
+
25
51
  def with_modified_env(options, &block)
26
52
  ClimateControl.modify(options, &block)
27
53
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: declare_schema
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.3
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Invoca Development adapted from hobo_fields by Tom Locke
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-10-08 00:00:00.000000000 Z
11
+ date: 2020-11-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -68,24 +68,23 @@ files:
68
68
  - lib/generators/declare_schema/migration/templates/migration.rb.erb
69
69
  - lib/generators/declare_schema/model/USAGE
70
70
  - lib/generators/declare_schema/model/model_generator.rb
71
- - lib/generators/declare_schema/model/templates/model_injection.rb.erb
72
71
  - lib/generators/declare_schema/support/eval_template.rb
73
72
  - lib/generators/declare_schema/support/model.rb
74
73
  - lib/generators/declare_schema/support/thor_shell.rb
74
+ - spec/lib/declare_schema/api_spec.rb
75
75
  - spec/lib/declare_schema/field_declaration_dsl_spec.rb
76
+ - spec/lib/declare_schema/generator_spec.rb
77
+ - spec/lib/declare_schema/interactive_primary_key_spec.rb
78
+ - spec/lib/declare_schema/migration_generator_spec.rb
79
+ - spec/lib/declare_schema/prepare_testapp.rb
80
+ - spec/lib/generators/declare_schema/migration/migrator_spec.rb
76
81
  - spec/spec_helper.rb
77
- - test/api.rdoctest
78
- - test/generators.rdoctest
79
- - test/interactive_primary_key.rdoctest
80
- - test/migration_generator.rdoctest
81
- - test/migration_generator_comments.rdoctestDISABLED
82
- - test/prepare_testapp.rb
83
82
  - test_responses.txt
84
83
  homepage: https://github.com/Invoca/declare_schema
85
84
  licenses: []
86
85
  metadata:
87
86
  allowed_push_host: https://rubygems.org
88
- post_install_message:
87
+ post_install_message:
89
88
  rdoc_options: []
90
89
  require_paths:
91
90
  - lib
@@ -101,7 +100,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
101
100
  version: 1.3.6
102
101
  requirements: []
103
102
  rubygems_version: 3.0.3
104
- signing_key:
103
+ signing_key:
105
104
  specification_version: 4
106
105
  summary: Database migration generator for Rails
107
106
  test_files: []
@@ -1,25 +0,0 @@
1
-
2
- fields do
3
- <% for attribute in field_attributes -%>
4
- <%= "%-#{max_attribute_length}s" % attribute.name %> :<%= attribute.type %><%=
5
- case attribute.type.to_s
6
- when 'string'
7
- ', limit: 255'
8
- else
9
- ''
10
- end
11
- %>
12
- <% end -%>
13
- <% if options[:timestamps] -%>
14
- timestamps
15
- <% end -%>
16
- end
17
-
18
- <% for bt in bts -%>
19
- belongs_to :<%= bt %>
20
- <% end -%>
21
- <%= "\n" unless bts.empty? -%>
22
- <% for hm in hms -%>
23
- has_many :<%= hm %>, dependent: :destroy
24
- <% end -%>
25
- <%= "\n" unless hms.empty? -%>
@@ -1,136 +0,0 @@
1
- # DeclareSchema API
2
-
3
- In order for the API examples to run we need to load the rails generators of our testapp:
4
- {.hidden}
5
-
6
- doctest: prepare testapp environment
7
- doctest_require: 'prepare_testapp'
8
- {.hidden}
9
-
10
- ## Example Models
11
-
12
- Let's define some example models that we can use to demonstrate the API. With DeclareSchema we can use the 'declare_schema:model' generator like so:
13
-
14
- $ rails generate declare_schema:model advert title:string body:text
15
-
16
- This will generate the test, fixture and a model file like this:
17
-
18
- >> Rails::Generators.invoke 'declare_schema:model', %w(advert title:string body:text)
19
- {.hidden}
20
-
21
- class Advert < ActiveRecord::Base
22
- fields do
23
- title :string
24
- body :text, limit: 0xffff, null: true
25
- end
26
- end
27
-
28
- The migration generator uses this information to create a migration. The following creates and runs the migration so we're ready to go.
29
-
30
- $ rails generate declare_schema:migration -n -m
31
-
32
- We're now ready to start demonstrating the API
33
-
34
- >> require_relative "#{Rails.root}/app/models/advert.rb" if Rails::VERSION::MAJOR > 5
35
- >> Rails::Generators.invoke 'declare_schema:migration', %w(-n -m)
36
- >> Rails::Generators.invoke 'declare_schema:migration', %w(-n -m)
37
- {.hidden}
38
-
39
- ## The Basics
40
-
41
- The main feature of DeclareSchema, aside from the migration generator, is the ability to declare rich types for your fields. For example, you can declare that a field is an email address, and the field will be automatically validated for correct email address syntax.
42
-
43
- ### Field Types
44
-
45
- Field values are returned as the type you specify.
46
-
47
- >> a = Advert.new :body => "This is the body", id: 1, title: "title"
48
- >> a.body.class
49
- => String
50
-
51
- This also works after a round-trip to the database
52
-
53
- >> a.save
54
- >> b = Advert.find(a.id)
55
- >> b.body.class
56
- => String
57
-
58
- ## Names vs. Classes
59
-
60
- The full set of available symbolic names is
61
-
62
- * `:integer`
63
- * `:float`
64
- * `:decimal`
65
- * `:string`
66
- * `:text`
67
- * `:boolean`
68
- * `:date`
69
- * `:datetime`
70
- * `:html`
71
- * `:textile`
72
- * `:markdown`
73
- * `:password`
74
-
75
- You can add your own types too. More on that later.
76
-
77
-
78
- ## Model extensions
79
-
80
- DeclareSchema adds a few features to your models.
81
-
82
- ### `Model.attr_type`
83
-
84
- Returns the type (i.e. class) declared for a given field or attribute
85
-
86
- >> Advert.connection.schema_cache.clear!
87
- >> Advert.reset_column_information
88
- >> Advert.attr_type :title
89
- => String
90
- >> Advert.attr_type :body
91
- => String
92
-
93
- ## Field validations
94
-
95
- DeclareSchema gives you some shorthands for declaring some common validations right in the field declaration
96
-
97
- ### Required fields
98
-
99
- The `:required` argument to a field gives a `validates_presence_of`:
100
-
101
- >>
102
- class Advert
103
- fields do
104
- title :string, :required, limit: 255
105
- end
106
- end
107
- >> a = Advert.new
108
- >> a.valid?
109
- => false
110
- >> a.errors.full_messages
111
- => ["Title can't be blank"]
112
- >> a.id = 2
113
- >> a.body = "hello"
114
- >> a.title = "Jimbo"
115
- >> a.save
116
- => true
117
-
118
-
119
- ### Unique fields
120
-
121
- The `:unique` argument in a field declaration gives `validates_uniqueness_of`:
122
-
123
- >>
124
- class Advert
125
- fields do
126
- title :string, :unique, limit: 255
127
- end
128
- end
129
- >> a = Advert.new :title => "Jimbo", id: 3, body: "hello"
130
- >> a.valid?
131
- => false
132
- >> a.errors.full_messages
133
- => ["Title has already been taken"]
134
- >> a.title = "Sambo"
135
- >> a.save
136
- => true
@@ -1,62 +0,0 @@
1
- doctest: prepare testapp environment
2
- doctest_require: 'prepare_testapp'
3
-
4
- doctest: generate declare_schema:model
5
- >> begin; Rails::Generators.invoke 'declare_schema:model', %w(alpha/beta one:string two:integer); rescue => ex; $stderr.puts "#{ex.class}: #{ex}\n#{ex.backtrace.join("\n")}"; end
6
-
7
-
8
- doctest: model file exists
9
- >> File.exist? 'app/models/alpha/beta.rb'
10
- => true
11
-
12
- doctest: model content matches
13
- >> File.read 'app/models/alpha/beta.rb'
14
- => "class Alpha::Beta < #{Rails::VERSION::MAJOR > 4 ? 'ApplicationRecord' : 'ActiveRecord::Base'}\n\n fields do\n one :string, limit: 255\n two :integer\n end\n\nend\n"
15
-
16
- doctest: module file exists
17
- >> File.exist? 'app/models/alpha.rb'
18
- => true
19
-
20
- doctest: module content matches
21
- >> File.read 'app/models/alpha.rb'
22
- => "module Alpha\n def self.table_name_prefix\n 'alpha_'\n end\nend\n"
23
-
24
-
25
- doctest: test file exists
26
- >> File.exist? 'test/models/alpha/beta_test.rb'
27
- => true
28
-
29
- doctest: test content matches
30
- >> File.read 'test/models/alpha/beta_test.rb'
31
- =>
32
- require 'test_helper'
33
-
34
- class Alpha::BetaTest < ActiveSupport::TestCase
35
- # test "the truth" do
36
- # assert true
37
- # end
38
- end
39
-
40
- doctest: fixture file exists
41
- >> File.exist? 'test/fixtures/alpha/beta.yml'
42
- => true
43
-
44
-
45
- doctest: generate declare_schema:migration
46
- >> puts "#{Rails.root}/app/models/alpha.rb"
47
- >> require "#{Rails.root}/app/models/alpha.rb" if Rails::VERSION::MAJOR > 4
48
- >> require "#{Rails.root}/app/models/alpha/beta.rb" if Rails::VERSION::MAJOR > 4
49
- >> Rails::Generators.invoke 'declare_schema:migration', %w(-n -m)
50
-
51
- doctest: schema.rb file exists
52
- >> system("ls -al db")
53
- >> File.exist? 'db/schema.rb'
54
- => true
55
-
56
- doctest: db file exists
57
- >> File.exist?("db/development.sqlite3") || File.exist?("db/test.sqlite3")
58
- => true
59
-
60
- doctest: Alpha::Beta class exists
61
- >> Alpha::Beta
62
- # will error if class doesn't exist
@@ -1,56 +0,0 @@
1
- -*- indent-tabs-mode:nil; -*-
2
-
3
- # DeclareSchema - Migration Generator
4
-
5
- Our test requires to prepare the testapp:
6
- {.hidden}
7
-
8
- doctest_require: 'prepare_testapp'
9
-
10
- {.hidden}
11
-
12
- And requires also that you enter the right choice when prompted. OK we're ready to get going.
13
-
14
- ## Alternate Primary Keys
15
-
16
- ### create
17
- doctest: create table with custom primary_key
18
- >>
19
- class Foo < ActiveRecord::Base
20
- fields do
21
- end
22
- self.primary_key="foo_id"
23
- end
24
- >> Rails::Generators.invoke 'declare_schema:migration', %w(-n -m)
25
- >> Foo.primary_key
26
- => 'foo_id'
27
-
28
- ### migrate from
29
- doctest: rename from custom primary_key
30
- >>
31
- class Foo < ActiveRecord::Base
32
- self.primary_key="id"
33
- end
34
- puts "\n\e[45m Please enter 'id' (no quotes) at the next prompt \e[0m"
35
- >> Rails::Generators.invoke 'declare_schema:migration', %w(-n -m)
36
- >> Foo.primary_key
37
- => 'id'
38
-
39
- ### migrate to
40
-
41
- doctest: rename to custom primary_key
42
- >>
43
- class Foo < ActiveRecord::Base
44
- self.primary_key="foo_id"
45
- end
46
- puts "\n\e[45m Please enter 'drop id' (no quotes) at the next prompt \e[0m"
47
- >> Rails::Generators.invoke 'declare_schema:migration', %w(-n -m)
48
- >> Foo.primary_key
49
- => 'foo_id'
50
-
51
- ### ensure it doesn't cause further migrations
52
-
53
- doctest: check no further migrations
54
- >> up, down = Generators::DeclareSchema::Migration::Migrator.run
55
- >> up
56
- => ""