declare_schema 0.1.1 → 0.3.0.pre.1

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