declare_schema 0.1.3 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
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
- => ""