declare_schema 0.1.1 → 0.3.0.pre.1

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 (35) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +37 -0
  3. data/CHANGELOG.md +36 -4
  4. data/Gemfile +0 -2
  5. data/Gemfile.lock +1 -4
  6. data/Rakefile +13 -20
  7. data/gemfiles/rails_4.gemfile +4 -7
  8. data/gemfiles/rails_5.gemfile +4 -7
  9. data/gemfiles/rails_6.gemfile +4 -7
  10. data/lib/declare_schema/model.rb +21 -23
  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 -13
  14. data/lib/generators/declare_schema/migration/migrator.rb +57 -33
  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 +735 -0
  23. data/spec/lib/declare_schema/prepare_testapp.rb +31 -0
  24. data/spec/lib/generators/declare_schema/migration/migrator_spec.rb +42 -0
  25. data/spec/spec_helper.rb +26 -0
  26. metadata +9 -11
  27. data/.jenkins/Jenkinsfile +0 -72
  28. data/.jenkins/ruby_build_pod.yml +0 -19
  29. data/lib/generators/declare_schema/model/templates/model_injection.rb.erb +0 -25
  30. data/test/api.rdoctest +0 -136
  31. data/test/generators.rdoctest +0 -60
  32. data/test/interactive_primary_key.rdoctest +0 -56
  33. data/test/migration_generator.rdoctest +0 -846
  34. data/test/migration_generator_comments.rdoctestDISABLED +0 -74
  35. 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,42 @@
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
+ end
40
+ end
41
+ end
42
+ 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.1
4
+ version: 0.3.0.pre.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Invoca Development adapted from hobo_fields by Tom Locke
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-09-24 00:00:00.000000000 Z
11
+ date: 2020-10-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -35,11 +35,10 @@ files:
35
35
  - ".dependabot/config.yml"
36
36
  - ".github/workflows/gem_release.yml"
37
37
  - ".gitignore"
38
- - ".jenkins/Jenkinsfile"
39
- - ".jenkins/ruby_build_pod.yml"
40
38
  - ".rspec"
41
39
  - ".rubocop.yml"
42
40
  - ".ruby-version"
41
+ - ".travis.yml"
43
42
  - Appraisals
44
43
  - CHANGELOG.md
45
44
  - Gemfile
@@ -69,18 +68,17 @@ files:
69
68
  - lib/generators/declare_schema/migration/templates/migration.rb.erb
70
69
  - lib/generators/declare_schema/model/USAGE
71
70
  - lib/generators/declare_schema/model/model_generator.rb
72
- - lib/generators/declare_schema/model/templates/model_injection.rb.erb
73
71
  - lib/generators/declare_schema/support/eval_template.rb
74
72
  - lib/generators/declare_schema/support/model.rb
75
73
  - lib/generators/declare_schema/support/thor_shell.rb
74
+ - spec/lib/declare_schema/api_spec.rb
76
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
77
81
  - spec/spec_helper.rb
78
- - test/api.rdoctest
79
- - test/generators.rdoctest
80
- - test/interactive_primary_key.rdoctest
81
- - test/migration_generator.rdoctest
82
- - test/migration_generator_comments.rdoctestDISABLED
83
- - test/prepare_testapp.rb
84
82
  - test_responses.txt
85
83
  homepage: https://github.com/Invoca/declare_schema
86
84
  licenses: []
@@ -1,72 +0,0 @@
1
- #!/usr/bin/groovy
2
- @Library('jenkins-pipeline@v0.5.1')
3
- import com.invoca.ci.*;
4
-
5
- pipeline {
6
- agent {
7
- kubernetes {
8
- defaultContainer 'ruby'
9
- yamlFile '.jenkins/ruby_build_pod.yml'
10
- }
11
- }
12
-
13
- environment {
14
- GITHUB_TOKEN = credentials('github_token')
15
- BUNDLE_GEM__FURY__IO = credentials('gemfury_deploy_token')
16
- }
17
-
18
- stages {
19
- stage('Setup') {
20
- steps {
21
- updateGitHubStatus('clean-build', 'pending', "Running unit tests")
22
- sh 'bundle install'
23
- sh 'bundle exec appraisal install'
24
- }
25
- }
26
-
27
- stage("Current Unit Tests") {
28
- steps {
29
- sh 'bundle exec rake test:prepare_testapp[force]'
30
- sh 'bundle exec rake test:all < test_responses.txt'
31
- }
32
- }
33
-
34
- stage("Rails 4 Appraisal") {
35
- steps {
36
- sh 'bundle exec appraisal rails-4 rake test:prepare_testapp[force]'
37
- sh 'bundle exec appraisal rails-4 rake test:all < test_responses.txt'
38
- }
39
- }
40
-
41
- stage("Rails 5 Appraisal") {
42
- steps {
43
- sh 'bundle exec appraisal rails-5 rake test:prepare_testapp[force]'
44
- sh 'bundle exec appraisal rails-5 rake test:all < test_responses.txt'
45
- }
46
- }
47
-
48
- stage("Rails 6 Appraisal") {
49
- steps {
50
- sh 'bundle exec appraisal rails-6 rake test:prepare_testapp[force]'
51
- sh 'bundle exec appraisal rails-6 rake test:all < test_responses.txt'
52
- }
53
- }
54
- }
55
-
56
- post {
57
- success { updateGitHubStatus('clean-build', 'success', "Unit tests passed") }
58
- failure { updateGitHubStatus('clean-build', 'failure', "Unit tests failed") }
59
- }
60
- }
61
-
62
- void updateGitHubStatus(String context, String status, String description) {
63
- gitHubStatus([
64
- repoSlug: 'Invoca/declare_schema',
65
- sha: env.GIT_COMMIT,
66
- description: description,
67
- context: context,
68
- targetURL: env.RUN_DISPLAY_URL,
69
- token: env.GITHUB_TOKEN,
70
- status: status
71
- ])
72
- }
@@ -1,19 +0,0 @@
1
-
2
- ---
3
- apiVersion: v1
4
- kind: Pod
5
- metadata:
6
- labels:
7
- jenkins/declare_schema: 'true'
8
- namespace: jenkins
9
- name: declare_schema
10
- spec:
11
- containers:
12
- - name: ruby
13
- image: ruby:2.6.5
14
- tty: true
15
- resources:
16
- requests:
17
- memory: "100Mi"
18
- command:
19
- - cat
@@ -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,60 +0,0 @@
1
- doctest: prepare testapp environment
2
- doctest_require: 'prepare_testapp'
3
-
4
- doctest: generate declare_schema:model
5
- >> Rails::Generators.invoke 'declare_schema:model', %w(alpha/beta one:string two:integer)
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
- >> require_relative "#{Rails.root}/app/models/alpha.rb" if Rails::VERSION::MAJOR > 5
47
- >> require_relative "#{Rails.root}/app/models/alpha/beta.rb" if Rails::VERSION::MAJOR > 5
48
- >> Rails::Generators.invoke 'declare_schema:migration', %w(-n -m)
49
-
50
- doctest: schema.rb file exists
51
- >> File.exist? 'db/schema.rb'
52
- => true
53
-
54
- doctest: db file exists
55
- >> File.exist? 'db/development.sqlite3'
56
- => true
57
-
58
- doctest: Alpha::Beta class exists
59
- >> Alpha::Beta
60
- # will error if class doesn't exist