whiteprint 0.1.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.
- checksums.yaml +7 -0
 - data/README.md +251 -0
 - data/Rakefile +55 -0
 - data/lib/tasks/blueprint.rake +5 -0
 - data/lib/whiteprint.rb +99 -0
 - data/lib/whiteprint/adapters/active_record.rb +193 -0
 - data/lib/whiteprint/adapters/active_record/has_and_belongs_to_many.rb +22 -0
 - data/lib/whiteprint/adapters/active_record/migration.rb +17 -0
 - data/lib/whiteprint/adapters/test.rb +20 -0
 - data/lib/whiteprint/attributes.rb +207 -0
 - data/lib/whiteprint/base.rb +95 -0
 - data/lib/whiteprint/config.rb +19 -0
 - data/lib/whiteprint/explanation.rb +73 -0
 - data/lib/whiteprint/has_whiteprint.rb +7 -0
 - data/lib/whiteprint/migrator.rb +66 -0
 - data/lib/whiteprint/model.rb +25 -0
 - data/lib/whiteprint/railtie.rb +24 -0
 - data/lib/whiteprint/transform.rb +35 -0
 - data/lib/whiteprint/version.rb +3 -0
 - data/test/cases/active_record_test.rb +13 -0
 - data/test/cases/attributes_test.rb +62 -0
 - data/test/cases/blueprint_test.rb +125 -0
 - data/test/cases/changes_tree_test.rb +51 -0
 - data/test/cases/explanation_test.rb +32 -0
 - data/test/cases/migrator_test.rb +70 -0
 - data/test/models/car.rb +8 -0
 - data/test/models/user.rb +8 -0
 - data/test/schema.rb +11 -0
 - data/test/test_helper.rb +21 -0
 - data/vendor/active_support/concern.rb +142 -0
 - metadata +270 -0
 
| 
         @@ -0,0 +1,66 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module Whiteprint
         
     | 
| 
      
 2 
     | 
    
         
            +
              module Migrator
         
     | 
| 
      
 3 
     | 
    
         
            +
                class << self
         
     | 
| 
      
 4 
     | 
    
         
            +
                  def eager_load!
         
     | 
| 
      
 5 
     | 
    
         
            +
                    return unless Whiteprint.config.eager_load
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
                    Rails.application.eager_load! if defined?(Rails)
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
                    [*Whiteprint.config.eager_load_paths.uniq].each do |path|
         
     | 
| 
      
 10 
     | 
    
         
            +
                      Gem.find_files(path).each do |file|
         
     | 
| 
      
 11 
     | 
    
         
            +
                        load file
         
     | 
| 
      
 12 
     | 
    
         
            +
                      end
         
     | 
| 
      
 13 
     | 
    
         
            +
                    end
         
     | 
| 
      
 14 
     | 
    
         
            +
                  end
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
                  def explanations
         
     | 
| 
      
 17 
     | 
    
         
            +
                    Whiteprint.changed_whiteprints.map.with_index do |whiteprint, index|
         
     | 
| 
      
 18 
     | 
    
         
            +
                      whiteprint.explanation(index + 1)
         
     | 
| 
      
 19 
     | 
    
         
            +
                    end
         
     | 
| 
      
 20 
     | 
    
         
            +
                  end
         
     | 
| 
      
 21 
     | 
    
         
            +
             
     | 
| 
      
 22 
     | 
    
         
            +
                  def interactive(input: $stdin, output: $stdout, migrate_input: $stdin, migrate_output: $stdout)
         
     | 
| 
      
 23 
     | 
    
         
            +
                    # TODO: Clean up
         
     | 
| 
      
 24 
     | 
    
         
            +
             
     | 
| 
      
 25 
     | 
    
         
            +
                    eager_load!
         
     | 
| 
      
 26 
     | 
    
         
            +
                    cli = HighLine.new input, output
         
     | 
| 
      
 27 
     | 
    
         
            +
             
     | 
| 
      
 28 
     | 
    
         
            +
                    if number_of_changes == 0
         
     | 
| 
      
 29 
     | 
    
         
            +
                      cli.say('Whiteprint detected no changes')
         
     | 
| 
      
 30 
     | 
    
         
            +
                      return
         
     | 
| 
      
 31 
     | 
    
         
            +
                    end
         
     | 
| 
      
 32 
     | 
    
         
            +
             
     | 
| 
      
 33 
     | 
    
         
            +
                    cli.say "Whiteprint has detected <%= color('#{number_of_changes}', :bold, :white) %> changes to your models."
         
     | 
| 
      
 34 
     | 
    
         
            +
                    explanations.each do |explanation|
         
     | 
| 
      
 35 
     | 
    
         
            +
                      cli.say explanation
         
     | 
| 
      
 36 
     | 
    
         
            +
                    end
         
     | 
| 
      
 37 
     | 
    
         
            +
             
     | 
| 
      
 38 
     | 
    
         
            +
                    cli.choose do |menu|
         
     | 
| 
      
 39 
     | 
    
         
            +
                      menu.header = 'Migrations'
         
     | 
| 
      
 40 
     | 
    
         
            +
                      menu.prompt = 'How would you like to process these changes?'
         
     | 
| 
      
 41 
     | 
    
         
            +
                      menu.choice('In one migration')       { migrate_at_once(input: migrate_input, output: migrate_output) }
         
     | 
| 
      
 42 
     | 
    
         
            +
                      menu.choice('In separate migrations') { cli.say 'Bar' }
         
     | 
| 
      
 43 
     | 
    
         
            +
                    end
         
     | 
| 
      
 44 
     | 
    
         
            +
                  end
         
     | 
| 
      
 45 
     | 
    
         
            +
             
     | 
| 
      
 46 
     | 
    
         
            +
                  def migrate_at_once(input: $stdin, output: $stdout)
         
     | 
| 
      
 47 
     | 
    
         
            +
                    # TODO: Clean up
         
     | 
| 
      
 48 
     | 
    
         
            +
             
     | 
| 
      
 49 
     | 
    
         
            +
                    cli = HighLine.new input, output
         
     | 
| 
      
 50 
     | 
    
         
            +
                    name = cli.ask 'How would you like to name this migration?'
         
     | 
| 
      
 51 
     | 
    
         
            +
                    Whiteprint.changed_whiteprints
         
     | 
| 
      
 52 
     | 
    
         
            +
                             .group_by(&:transformer)
         
     | 
| 
      
 53 
     | 
    
         
            +
                             .map do |adapter, whiteprints|
         
     | 
| 
      
 54 
     | 
    
         
            +
                               adapter.generate_migration(name, whiteprints.map(&:changes_tree))
         
     | 
| 
      
 55 
     | 
    
         
            +
                             end
         
     | 
| 
      
 56 
     | 
    
         
            +
             
     | 
| 
      
 57 
     | 
    
         
            +
                    ActiveRecord::Migration.verbose = true
         
     | 
| 
      
 58 
     | 
    
         
            +
                    ActiveRecord::Migrator.migrate(ActiveRecord::Migrator.migrations_paths)
         
     | 
| 
      
 59 
     | 
    
         
            +
                  end
         
     | 
| 
      
 60 
     | 
    
         
            +
             
     | 
| 
      
 61 
     | 
    
         
            +
                  def number_of_changes
         
     | 
| 
      
 62 
     | 
    
         
            +
                    Whiteprint.changed_whiteprints.size
         
     | 
| 
      
 63 
     | 
    
         
            +
                  end
         
     | 
| 
      
 64 
     | 
    
         
            +
                end
         
     | 
| 
      
 65 
     | 
    
         
            +
              end
         
     | 
| 
      
 66 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,25 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module Whiteprint
         
     | 
| 
      
 2 
     | 
    
         
            +
              module Model
         
     | 
| 
      
 3 
     | 
    
         
            +
                extend ActiveSupport::Concern
         
     | 
| 
      
 4 
     | 
    
         
            +
             
     | 
| 
      
 5 
     | 
    
         
            +
                class_methods do
         
     | 
| 
      
 6 
     | 
    
         
            +
                  def whiteprint(**options, &block)
         
     | 
| 
      
 7 
     | 
    
         
            +
                    return @_whiteprint unless block
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
                    @_whiteprint ||= ::Whiteprint.new(self, **options)
         
     | 
| 
      
 10 
     | 
    
         
            +
                    @_whiteprint.execute(&block)
         
     | 
| 
      
 11 
     | 
    
         
            +
                  end
         
     | 
| 
      
 12 
     | 
    
         
            +
                  alias_method :schema, :whiteprint
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
                  def inherited(base)
         
     | 
| 
      
 15 
     | 
    
         
            +
                    whiteprint.clone_to(base) if whiteprint
         
     | 
| 
      
 16 
     | 
    
         
            +
                    super
         
     | 
| 
      
 17 
     | 
    
         
            +
                  end
         
     | 
| 
      
 18 
     | 
    
         
            +
                end
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
      
 20 
     | 
    
         
            +
                def self.included(model)
         
     | 
| 
      
 21 
     | 
    
         
            +
                  Whiteprint.models += [model]
         
     | 
| 
      
 22 
     | 
    
         
            +
                  super
         
     | 
| 
      
 23 
     | 
    
         
            +
                end
         
     | 
| 
      
 24 
     | 
    
         
            +
              end
         
     | 
| 
      
 25 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,24 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module Whiteprint
         
     | 
| 
      
 2 
     | 
    
         
            +
              class Railtie < Rails::Railtie
         
     | 
| 
      
 3 
     | 
    
         
            +
                class << self
         
     | 
| 
      
 4 
     | 
    
         
            +
                  def whiteprint_config
         
     | 
| 
      
 5 
     | 
    
         
            +
                    ::Whiteprint.config do |c|
         
     | 
| 
      
 6 
     | 
    
         
            +
                      c.eager_load        = true
         
     | 
| 
      
 7 
     | 
    
         
            +
                      c.migration_path    = Rails.root.join(ActiveRecord::Migrator.migrations_path)
         
     | 
| 
      
 8 
     | 
    
         
            +
                    end
         
     | 
| 
      
 9 
     | 
    
         
            +
                  end
         
     | 
| 
      
 10 
     | 
    
         
            +
                end
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
                initializer "whiteprint.config_for_rails" do
         
     | 
| 
      
 13 
     | 
    
         
            +
                  ::Whiteprint.config do |c|
         
     | 
| 
      
 14 
     | 
    
         
            +
                    c.eager_load        = true
         
     | 
| 
      
 15 
     | 
    
         
            +
                    c.migration_path    = Rails.root.join(ActiveRecord::Migrator.migrations_path)
         
     | 
| 
      
 16 
     | 
    
         
            +
                  end
         
     | 
| 
      
 17 
     | 
    
         
            +
                end
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
                rake_tasks do
         
     | 
| 
      
 20 
     | 
    
         
            +
                  # whiteprint_config
         
     | 
| 
      
 21 
     | 
    
         
            +
                  load "tasks/whiteprint.rake"
         
     | 
| 
      
 22 
     | 
    
         
            +
                end
         
     | 
| 
      
 23 
     | 
    
         
            +
              end
         
     | 
| 
      
 24 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,35 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module Whiteprint
         
     | 
| 
      
 2 
     | 
    
         
            +
              class Transform < Parslet::Transform
         
     | 
| 
      
 3 
     | 
    
         
            +
                class << self
         
     | 
| 
      
 4 
     | 
    
         
            +
                  def create_rule(name, **expression)
         
     | 
| 
      
 5 
     | 
    
         
            +
                    define_singleton_method name do |&block|
         
     | 
| 
      
 6 
     | 
    
         
            +
                      rule(expression, &block)
         
     | 
| 
      
 7 
     | 
    
         
            +
                    end
         
     | 
| 
      
 8 
     | 
    
         
            +
                  end
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
                  def table_expression
         
     | 
| 
      
 11 
     | 
    
         
            +
                    {
         
     | 
| 
      
 12 
     | 
    
         
            +
                      table_name: simple(:table_name),
         
     | 
| 
      
 13 
     | 
    
         
            +
                      attributes: subtree(:attributes)
         
     | 
| 
      
 14 
     | 
    
         
            +
                    }
         
     | 
| 
      
 15 
     | 
    
         
            +
                  end
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
                  def attribute_expression
         
     | 
| 
      
 18 
     | 
    
         
            +
                    {
         
     | 
| 
      
 19 
     | 
    
         
            +
                      name: simple(:name),
         
     | 
| 
      
 20 
     | 
    
         
            +
                      type: simple(:type),
         
     | 
| 
      
 21 
     | 
    
         
            +
                      options: subtree(:options)
         
     | 
| 
      
 22 
     | 
    
         
            +
                    }
         
     | 
| 
      
 23 
     | 
    
         
            +
                  end
         
     | 
| 
      
 24 
     | 
    
         
            +
                end
         
     | 
| 
      
 25 
     | 
    
         
            +
             
     | 
| 
      
 26 
     | 
    
         
            +
                create_rule :create_table,             table_exists: false, has_id: true,  **table_expression
         
     | 
| 
      
 27 
     | 
    
         
            +
                create_rule :create_table_without_id,  table_exists: false, has_id: false, **table_expression
         
     | 
| 
      
 28 
     | 
    
         
            +
                create_rule :change_table,             table_exists: true,                 **table_expression
         
     | 
| 
      
 29 
     | 
    
         
            +
             
     | 
| 
      
 30 
     | 
    
         
            +
                create_rule :added_attribute,          kind: :added,   **attribute_expression
         
     | 
| 
      
 31 
     | 
    
         
            +
                create_rule :changed_attribute,        kind: :changed, **attribute_expression
         
     | 
| 
      
 32 
     | 
    
         
            +
                create_rule :removed_attribute,        kind: :removed, **attribute_expression
         
     | 
| 
      
 33 
     | 
    
         
            +
                create_rule :added_timestamps,         kind: :added,   type: :timestamps
         
     | 
| 
      
 34 
     | 
    
         
            +
              end
         
     | 
| 
      
 35 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,13 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'test_helper'
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            class ActiveRecordTest < ActiveSupport::TestCase
         
     | 
| 
      
 4 
     | 
    
         
            +
              def setup
         
     | 
| 
      
 5 
     | 
    
         
            +
                @persisted_attributes = User.whiteprint.persisted_attributes
         
     | 
| 
      
 6 
     | 
    
         
            +
              end
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
              test 'the active_record adapter can read the persisted attributes from the database' do
         
     | 
| 
      
 9 
     | 
    
         
            +
                assert_equal Whiteprint::Attribute.new(name: :name, type: :string, default: 'John').for_persisted,   @persisted_attributes.name
         
     | 
| 
      
 10 
     | 
    
         
            +
                assert_equal Whiteprint::Attribute.new(name: :age, type: :integer, default: 0).for_persisted,        @persisted_attributes.age
         
     | 
| 
      
 11 
     | 
    
         
            +
                assert_equal Whiteprint::Attribute.new(name: :date_of_birth, type: :date).for_persisted,             @persisted_attributes.date_of_birth
         
     | 
| 
      
 12 
     | 
    
         
            +
              end
         
     | 
| 
      
 13 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,62 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'test_helper'
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            class AttributesTest < ActiveSupport::TestCase
         
     | 
| 
      
 4 
     | 
    
         
            +
              def setup
         
     | 
| 
      
 5 
     | 
    
         
            +
                @attribute  = Whiteprint::Attribute.new type: :integer, default: 10
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
                @attributes = Whiteprint::Attributes.new
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
                @attributes.add name: 'name',           type: :string,  default: 'John'
         
     | 
| 
      
 10 
     | 
    
         
            +
                @attributes.add name: 'age',            type: :integer
         
     | 
| 
      
 11 
     | 
    
         
            +
                @attributes.add name: 'height',         type: :integer, default: 180
         
     | 
| 
      
 12 
     | 
    
         
            +
                @attributes.add name: 'date_of_birth',  type: :date
         
     | 
| 
      
 13 
     | 
    
         
            +
              end
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
              test 'an attribute can be asked whether it has a certain key or keys' do
         
     | 
| 
      
 16 
     | 
    
         
            +
                assert_equal true,  @attribute.has?(:type)
         
     | 
| 
      
 17 
     | 
    
         
            +
                assert_equal true,  @attribute.has?(:type, :default)
         
     | 
| 
      
 18 
     | 
    
         
            +
                assert_equal false, @attribute.has?(:type, :foo)
         
     | 
| 
      
 19 
     | 
    
         
            +
              end
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
      
 21 
     | 
    
         
            +
              test 'an attribute can be asked whether it has a certain values' do
         
     | 
| 
      
 22 
     | 
    
         
            +
                assert_equal true,  @attribute.has?(type: :integer)
         
     | 
| 
      
 23 
     | 
    
         
            +
                assert_equal false, @attribute.has?(type: :string)
         
     | 
| 
      
 24 
     | 
    
         
            +
                assert_equal true,  @attribute.has?(type: :integer, default: 10)
         
     | 
| 
      
 25 
     | 
    
         
            +
                assert_equal true,  @attribute.has?(:type, default: 10)
         
     | 
| 
      
 26 
     | 
    
         
            +
                assert_equal false, @attribute.has?(:type, default: 11)
         
     | 
| 
      
 27 
     | 
    
         
            +
              end
         
     | 
| 
      
 28 
     | 
    
         
            +
             
     | 
| 
      
 29 
     | 
    
         
            +
              test 'attributes can be queried' do
         
     | 
| 
      
 30 
     | 
    
         
            +
                assert_equal @attributes.to_h.slice(:name, :height),        @attributes.where(:default).to_h
         
     | 
| 
      
 31 
     | 
    
         
            +
                assert_equal @attributes.to_h.slice(:name),                 @attributes.where(default: 'John').to_h
         
     | 
| 
      
 32 
     | 
    
         
            +
                assert_equal @attributes.to_h.slice(:age, :height),         @attributes.where(type: :integer).to_h
         
     | 
| 
      
 33 
     | 
    
         
            +
                assert_equal @attributes.to_h.slice(:name, :date_of_birth), @attributes.not(type: :integer).to_h
         
     | 
| 
      
 34 
     | 
    
         
            +
                assert_equal @attributes.to_h.slice(:name),                 @attributes.where(:default).not(type: :integer).to_h
         
     | 
| 
      
 35 
     | 
    
         
            +
              end
         
     | 
| 
      
 36 
     | 
    
         
            +
             
     | 
| 
      
 37 
     | 
    
         
            +
              test 'attributes can be diffed' do
         
     | 
| 
      
 38 
     | 
    
         
            +
                diff = @attributes.where(:default).diff(@attributes)
         
     | 
| 
      
 39 
     | 
    
         
            +
             
     | 
| 
      
 40 
     | 
    
         
            +
                assert_equal @attributes.to_h.slice(:age, :date_of_birth), diff[:added].to_h
         
     | 
| 
      
 41 
     | 
    
         
            +
                assert_equal({},                                           diff[:removed].to_h)
         
     | 
| 
      
 42 
     | 
    
         
            +
                assert_equal({},                                           diff[:changed].to_h)
         
     | 
| 
      
 43 
     | 
    
         
            +
             
     | 
| 
      
 44 
     | 
    
         
            +
                diff = @attributes.diff(@attributes.where(:default))
         
     | 
| 
      
 45 
     | 
    
         
            +
             
     | 
| 
      
 46 
     | 
    
         
            +
                assert_equal({},                                           diff[:added].to_h)
         
     | 
| 
      
 47 
     | 
    
         
            +
                assert_equal @attributes.to_h.slice(:age, :date_of_birth), diff[:removed].to_h
         
     | 
| 
      
 48 
     | 
    
         
            +
                assert_equal({},                                           diff[:changed].to_h)
         
     | 
| 
      
 49 
     | 
    
         
            +
             
     | 
| 
      
 50 
     | 
    
         
            +
                diff_attributes = Whiteprint::Attributes.new
         
     | 
| 
      
 51 
     | 
    
         
            +
             
     | 
| 
      
 52 
     | 
    
         
            +
                diff_attributes.add name: 'name',           type: :string,  default: 'Joe'
         
     | 
| 
      
 53 
     | 
    
         
            +
                diff_attributes.add name: 'weight',         type: :integer
         
     | 
| 
      
 54 
     | 
    
         
            +
                diff_attributes.add name: 'height',         type: :integer, default: 160
         
     | 
| 
      
 55 
     | 
    
         
            +
             
     | 
| 
      
 56 
     | 
    
         
            +
                diff = @attributes.diff(diff_attributes)
         
     | 
| 
      
 57 
     | 
    
         
            +
             
     | 
| 
      
 58 
     | 
    
         
            +
                assert_equal diff_attributes.to_h.slice(:weight),          diff[:added].to_h
         
     | 
| 
      
 59 
     | 
    
         
            +
                assert_equal @attributes.to_h.slice(:age, :date_of_birth), diff[:removed].to_h
         
     | 
| 
      
 60 
     | 
    
         
            +
                assert_equal diff_attributes.to_h.slice(:name, :height),   diff[:changed].to_h
         
     | 
| 
      
 61 
     | 
    
         
            +
              end
         
     | 
| 
      
 62 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,125 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'test_helper'
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            class WhiteprintTest < ActiveSupport::TestCase
         
     | 
| 
      
 4 
     | 
    
         
            +
              def setup
         
     | 
| 
      
 5 
     | 
    
         
            +
                @model     = Class.new
         
     | 
| 
      
 6 
     | 
    
         
            +
                @whiteprint = ::Whiteprint::Base.new(@model)
         
     | 
| 
      
 7 
     | 
    
         
            +
              end
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
              test 'a whiteprint is tied to a model' do
         
     | 
| 
      
 10 
     | 
    
         
            +
                assert_equal @model, @whiteprint.model
         
     | 
| 
      
 11 
     | 
    
         
            +
              end
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
              test 'a whiteprint is initialized with an empty set of attributes' do
         
     | 
| 
      
 14 
     | 
    
         
            +
                assert_equal({}, @whiteprint.attributes.to_h)
         
     | 
| 
      
 15 
     | 
    
         
            +
              end
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
              test 'a whiteprint saves attributes with a type and options' do
         
     | 
| 
      
 18 
     | 
    
         
            +
                @whiteprint.string  :name, default: 'John'
         
     | 
| 
      
 19 
     | 
    
         
            +
                @whiteprint.integer 'age'
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
      
 21 
     | 
    
         
            +
                assert_equal({ name: :name, type: :string,  default: 'John' }, @whiteprint.attributes.name.to_h)
         
     | 
| 
      
 22 
     | 
    
         
            +
                assert_equal({ name: :age,  type: :integer },                  @whiteprint.attributes.age.to_h)
         
     | 
| 
      
 23 
     | 
    
         
            +
              end
         
     | 
| 
      
 24 
     | 
    
         
            +
             
     | 
| 
      
 25 
     | 
    
         
            +
              test 'attributes can be accessed like a hash with indifferent access, but they can also be accessed as methods' do
         
     | 
| 
      
 26 
     | 
    
         
            +
                @whiteprint.string :name, default: 'John'
         
     | 
| 
      
 27 
     | 
    
         
            +
             
     | 
| 
      
 28 
     | 
    
         
            +
                assert_equal :string, @whiteprint.attributes['name'][:type]
         
     | 
| 
      
 29 
     | 
    
         
            +
                assert_equal :string, @whiteprint.attributes.name.type
         
     | 
| 
      
 30 
     | 
    
         
            +
                assert_equal 'John',  @whiteprint.attributes[:name]['default']
         
     | 
| 
      
 31 
     | 
    
         
            +
                assert_equal 'John',  @whiteprint.attributes.name.default
         
     | 
| 
      
 32 
     | 
    
         
            +
              end
         
     | 
| 
      
 33 
     | 
    
         
            +
            end
         
     | 
| 
      
 34 
     | 
    
         
            +
             
     | 
| 
      
 35 
     | 
    
         
            +
            class WhiteprintModelTest < ActiveSupport::TestCase
         
     | 
| 
      
 36 
     | 
    
         
            +
              test 'a model responds to whiteprint (and schema) if Whiteprint::Model is included' do
         
     | 
| 
      
 37 
     | 
    
         
            +
                model = Class.new do
         
     | 
| 
      
 38 
     | 
    
         
            +
                  include Whiteprint::Model
         
     | 
| 
      
 39 
     | 
    
         
            +
                end
         
     | 
| 
      
 40 
     | 
    
         
            +
                assert_respond_to model, :whiteprint
         
     | 
| 
      
 41 
     | 
    
         
            +
                assert_respond_to model, :schema
         
     | 
| 
      
 42 
     | 
    
         
            +
              end
         
     | 
| 
      
 43 
     | 
    
         
            +
             
     | 
| 
      
 44 
     | 
    
         
            +
              test 'if a model inherits from ActiveRecord::Base has_whiteprint does the same as including Whiteprint::Model' do
         
     | 
| 
      
 45 
     | 
    
         
            +
                model = Class.new(ActiveRecord::Base) do
         
     | 
| 
      
 46 
     | 
    
         
            +
                  has_whiteprint
         
     | 
| 
      
 47 
     | 
    
         
            +
                end
         
     | 
| 
      
 48 
     | 
    
         
            +
             
     | 
| 
      
 49 
     | 
    
         
            +
                assert model < Whiteprint::Model
         
     | 
| 
      
 50 
     | 
    
         
            +
              end
         
     | 
| 
      
 51 
     | 
    
         
            +
             
     | 
| 
      
 52 
     | 
    
         
            +
              test 'a model can add attribtues to its whiteprint by passing the whiteprint method a block' do
         
     | 
| 
      
 53 
     | 
    
         
            +
                model = Class.new do
         
     | 
| 
      
 54 
     | 
    
         
            +
                  include Whiteprint::Model
         
     | 
| 
      
 55 
     | 
    
         
            +
             
     | 
| 
      
 56 
     | 
    
         
            +
                  whiteprint do
         
     | 
| 
      
 57 
     | 
    
         
            +
                    string  :name, default: 'John'
         
     | 
| 
      
 58 
     | 
    
         
            +
                    integer :age
         
     | 
| 
      
 59 
     | 
    
         
            +
                  end
         
     | 
| 
      
 60 
     | 
    
         
            +
                end
         
     | 
| 
      
 61 
     | 
    
         
            +
             
     | 
| 
      
 62 
     | 
    
         
            +
                assert_instance_of ::Whiteprint::Base, model.whiteprint
         
     | 
| 
      
 63 
     | 
    
         
            +
                assert_equal({ name: :name, type: :string,  default: 'John' }, model.whiteprint.attributes.name.to_h)
         
     | 
| 
      
 64 
     | 
    
         
            +
                assert_equal({ name: :age,  type: :integer },                  model.whiteprint.attributes.age.to_h)
         
     | 
| 
      
 65 
     | 
    
         
            +
              end
         
     | 
| 
      
 66 
     | 
    
         
            +
             
     | 
| 
      
 67 
     | 
    
         
            +
              test "attributes can also be added to a model's whiteprint via composition" do
         
     | 
| 
      
 68 
     | 
    
         
            +
                concern = Module.new do
         
     | 
| 
      
 69 
     | 
    
         
            +
                  extend ActiveSupport::Concern
         
     | 
| 
      
 70 
     | 
    
         
            +
                  include Whiteprint::Model
         
     | 
| 
      
 71 
     | 
    
         
            +
             
     | 
| 
      
 72 
     | 
    
         
            +
                  included do
         
     | 
| 
      
 73 
     | 
    
         
            +
                    whiteprint do
         
     | 
| 
      
 74 
     | 
    
         
            +
                      string  :name, default: 'John'
         
     | 
| 
      
 75 
     | 
    
         
            +
                    end
         
     | 
| 
      
 76 
     | 
    
         
            +
                  end
         
     | 
| 
      
 77 
     | 
    
         
            +
                end
         
     | 
| 
      
 78 
     | 
    
         
            +
             
     | 
| 
      
 79 
     | 
    
         
            +
                model = Class.new do
         
     | 
| 
      
 80 
     | 
    
         
            +
                  include Whiteprint::Model
         
     | 
| 
      
 81 
     | 
    
         
            +
                  include concern
         
     | 
| 
      
 82 
     | 
    
         
            +
             
     | 
| 
      
 83 
     | 
    
         
            +
                  whiteprint do
         
     | 
| 
      
 84 
     | 
    
         
            +
                    integer :age
         
     | 
| 
      
 85 
     | 
    
         
            +
                  end
         
     | 
| 
      
 86 
     | 
    
         
            +
                end
         
     | 
| 
      
 87 
     | 
    
         
            +
             
     | 
| 
      
 88 
     | 
    
         
            +
                assert_equal({ name: :name, type: :string,  default: 'John' }, model.whiteprint.attributes.name.to_h)
         
     | 
| 
      
 89 
     | 
    
         
            +
                assert_equal({ name: :age,  type: :integer },                  model.whiteprint.attributes.age.to_h)
         
     | 
| 
      
 90 
     | 
    
         
            +
              end
         
     | 
| 
      
 91 
     | 
    
         
            +
             
     | 
| 
      
 92 
     | 
    
         
            +
              test 'an adapter can be set by the user or is automatically determined if possible' do
         
     | 
| 
      
 93 
     | 
    
         
            +
                model = Class.new do
         
     | 
| 
      
 94 
     | 
    
         
            +
                  include Whiteprint::Model
         
     | 
| 
      
 95 
     | 
    
         
            +
             
     | 
| 
      
 96 
     | 
    
         
            +
                  whiteprint(adapter: :active_record) do
         
     | 
| 
      
 97 
     | 
    
         
            +
                  end
         
     | 
| 
      
 98 
     | 
    
         
            +
                end
         
     | 
| 
      
 99 
     | 
    
         
            +
             
     | 
| 
      
 100 
     | 
    
         
            +
                assert_instance_of ::Whiteprint::Adapters::ActiveRecord, model.whiteprint
         
     | 
| 
      
 101 
     | 
    
         
            +
             
     | 
| 
      
 102 
     | 
    
         
            +
                model = Class.new(ActiveRecord::Base) do
         
     | 
| 
      
 103 
     | 
    
         
            +
                  include Whiteprint::Model
         
     | 
| 
      
 104 
     | 
    
         
            +
             
     | 
| 
      
 105 
     | 
    
         
            +
                  whiteprint do
         
     | 
| 
      
 106 
     | 
    
         
            +
                  end
         
     | 
| 
      
 107 
     | 
    
         
            +
                end
         
     | 
| 
      
 108 
     | 
    
         
            +
             
     | 
| 
      
 109 
     | 
    
         
            +
                assert_instance_of ::Whiteprint::Adapters::ActiveRecord, model.whiteprint
         
     | 
| 
      
 110 
     | 
    
         
            +
             
     | 
| 
      
 111 
     | 
    
         
            +
                model = Class.new(ActiveRecord::Base) do
         
     | 
| 
      
 112 
     | 
    
         
            +
                  include Whiteprint::Model
         
     | 
| 
      
 113 
     | 
    
         
            +
             
     | 
| 
      
 114 
     | 
    
         
            +
                  whiteprint(adapter: :base) do
         
     | 
| 
      
 115 
     | 
    
         
            +
                  end
         
     | 
| 
      
 116 
     | 
    
         
            +
                end
         
     | 
| 
      
 117 
     | 
    
         
            +
             
     | 
| 
      
 118 
     | 
    
         
            +
                assert_instance_of ::Whiteprint::Base, model.whiteprint
         
     | 
| 
      
 119 
     | 
    
         
            +
              end
         
     | 
| 
      
 120 
     | 
    
         
            +
             
     | 
| 
      
 121 
     | 
    
         
            +
              def teardown
         
     | 
| 
      
 122 
     | 
    
         
            +
                Whiteprint.models = []
         
     | 
| 
      
 123 
     | 
    
         
            +
                Whiteprint::Migrator.eager_load!
         
     | 
| 
      
 124 
     | 
    
         
            +
              end
         
     | 
| 
      
 125 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,51 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'test_helper'
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            class ChangesTreeTest < ActiveSupport::TestCase
         
     | 
| 
      
 4 
     | 
    
         
            +
              def setup
         
     | 
| 
      
 5 
     | 
    
         
            +
                @model = Class.new do
         
     | 
| 
      
 6 
     | 
    
         
            +
                  include Whiteprint::Model
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
                  whiteprint(adapter: :test) do
         
     | 
| 
      
 9 
     | 
    
         
            +
                    string  :name,  default: 'John'
         
     | 
| 
      
 10 
     | 
    
         
            +
                    integer :age,   default: 0
         
     | 
| 
      
 11 
     | 
    
         
            +
                    date    :date_of_birth
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
                    persisted do
         
     | 
| 
      
 14 
     | 
    
         
            +
                      string  :name
         
     | 
| 
      
 15 
     | 
    
         
            +
                      integer :age,   default: 0
         
     | 
| 
      
 16 
     | 
    
         
            +
                      integer :weight
         
     | 
| 
      
 17 
     | 
    
         
            +
                    end
         
     | 
| 
      
 18 
     | 
    
         
            +
                  end
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
      
 20 
     | 
    
         
            +
                  def self.table_name
         
     | 
| 
      
 21 
     | 
    
         
            +
                    'persons'
         
     | 
| 
      
 22 
     | 
    
         
            +
                  end
         
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
      
 24 
     | 
    
         
            +
                  def self.table_exists?
         
     | 
| 
      
 25 
     | 
    
         
            +
                    true
         
     | 
| 
      
 26 
     | 
    
         
            +
                  end
         
     | 
| 
      
 27 
     | 
    
         
            +
                end
         
     | 
| 
      
 28 
     | 
    
         
            +
              end
         
     | 
| 
      
 29 
     | 
    
         
            +
             
     | 
| 
      
 30 
     | 
    
         
            +
              test 'the test adapter can set its persisted attributes with a block' do
         
     | 
| 
      
 31 
     | 
    
         
            +
                assert_equal Whiteprint::Attribute.new(name: :name, type: :string),             @model.whiteprint.persisted_attributes.name
         
     | 
| 
      
 32 
     | 
    
         
            +
                assert_equal Whiteprint::Attribute.new(name: :age, type: :integer, default: 0), @model.whiteprint.persisted_attributes.age
         
     | 
| 
      
 33 
     | 
    
         
            +
                assert_equal Whiteprint::Attribute.new(name: :weight, type: :integer),          @model.whiteprint.persisted_attributes.weight
         
     | 
| 
      
 34 
     | 
    
         
            +
              end
         
     | 
| 
      
 35 
     | 
    
         
            +
             
     | 
| 
      
 36 
     | 
    
         
            +
              test 'a whiteprint can generate a changes_tree with all the differences between the persisted attributes and the actual attributes' do
         
     | 
| 
      
 37 
     | 
    
         
            +
                changes_tree = @model.whiteprint.changes_tree
         
     | 
| 
      
 38 
     | 
    
         
            +
             
     | 
| 
      
 39 
     | 
    
         
            +
                attributes = [
         
     | 
| 
      
 40 
     | 
    
         
            +
                  { name: :date_of_birth, type: :date, options: {}, kind: :added },
         
     | 
| 
      
 41 
     | 
    
         
            +
                  { name: :name, type: :string, options: { default: 'John' }, kind: :changed },
         
     | 
| 
      
 42 
     | 
    
         
            +
                  { name: :weight, type: :integer, options: {}, kind: :removed }
         
     | 
| 
      
 43 
     | 
    
         
            +
                ]
         
     | 
| 
      
 44 
     | 
    
         
            +
                assert_equal({ table_name: 'persons', table_exists: true, attributes: attributes }, changes_tree)
         
     | 
| 
      
 45 
     | 
    
         
            +
              end
         
     | 
| 
      
 46 
     | 
    
         
            +
             
     | 
| 
      
 47 
     | 
    
         
            +
              def teardown
         
     | 
| 
      
 48 
     | 
    
         
            +
                Whiteprint.models = []
         
     | 
| 
      
 49 
     | 
    
         
            +
                Whiteprint::Migrator.eager_load!
         
     | 
| 
      
 50 
     | 
    
         
            +
              end
         
     | 
| 
      
 51 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,32 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'test_helper'
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            class ExplanationTest < ActiveSupport::TestCase
         
     | 
| 
      
 4 
     | 
    
         
            +
              test 'the changes whiteprint is about to process can be visualized in a table' do
         
     | 
| 
      
 5 
     | 
    
         
            +
                user_explanation = <<-TXT.sub(/\n$/, '')
         
     | 
| 
      
 6 
     | 
    
         
            +
            +--------+---------------+---------+------------------+-------------------+------------------------+
         
     | 
| 
      
 7 
     | 
    
         
            +
            |                                     1. Make changes to users                                     |
         
     | 
| 
      
 8 
     | 
    
         
            +
            +--------+---------------+---------+------------------+-------------------+------------------------+
         
     | 
| 
      
 9 
     | 
    
         
            +
            | action | name          | type    | type (currently) | options           | options (currently)    |
         
     | 
| 
      
 10 
     | 
    
         
            +
            +--------+---------------+---------+------------------+-------------------+------------------------+
         
     | 
| 
      
 11 
     | 
    
         
            +
            | change | name          | string  | string           | {:default=>"Joe"} | {:default=>"John"}     |
         
     | 
| 
      
 12 
     | 
    
         
            +
            | change | age           | integer | integer          | {:default=>10}    | {:default=>0}          |
         
     | 
| 
      
 13 
     | 
    
         
            +
            | remove | date_of_birth |         |                  |                   |                        |
         
     | 
| 
      
 14 
     | 
    
         
            +
            +--------+---------------+---------+------------------+-------------------+------------------------+
         
     | 
| 
      
 15 
     | 
    
         
            +
            TXT
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
                car_explanation = <<-TXT.sub(/\n$/, '')
         
     | 
| 
      
 18 
     | 
    
         
            +
            +---------------------------+------------------------+---------------------------------------------+
         
     | 
| 
      
 19 
     | 
    
         
            +
            |                                    1. Create a new table cars                                    |
         
     | 
| 
      
 20 
     | 
    
         
            +
            +---------------------------+------------------------+---------------------------------------------+
         
     | 
| 
      
 21 
     | 
    
         
            +
            | name                      | type                   | options                                     |
         
     | 
| 
      
 22 
     | 
    
         
            +
            +---------------------------+------------------------+---------------------------------------------+
         
     | 
| 
      
 23 
     | 
    
         
            +
            | brand                     | string                 | {:default=>"BMW"}                           |
         
     | 
| 
      
 24 
     | 
    
         
            +
            | price                     | decimal                | {:precision=>5, :scale=>10}                 |
         
     | 
| 
      
 25 
     | 
    
         
            +
            | timestamps                |                        |                                             |
         
     | 
| 
      
 26 
     | 
    
         
            +
            +---------------------------+------------------------+---------------------------------------------+
         
     | 
| 
      
 27 
     | 
    
         
            +
                TXT
         
     | 
| 
      
 28 
     | 
    
         
            +
             
     | 
| 
      
 29 
     | 
    
         
            +
                assert_equal user_explanation, User.whiteprint.explanation.to_s
         
     | 
| 
      
 30 
     | 
    
         
            +
                assert_equal car_explanation,  Car.whiteprint.explanation.to_s
         
     | 
| 
      
 31 
     | 
    
         
            +
              end
         
     | 
| 
      
 32 
     | 
    
         
            +
            end
         
     |