Skip to content

Repository files navigation

Whiteprint

by 10KB

Whiteprint keeps track of the attributes of your models. It:

  • Generates migrations for you if you update your model's whiteprint (only ActiveRecord at the moment)
  • Provides you with helpers to use in your serializers or permitted attributes definition
  • Can be extended with plugins
  • Has support for inheritance and composition

Installation

Add this line to your application's Gemfile:

gem 'whiteprint'

And then execute:

$ bundle

Or install it yourself as:

$ gem install whiteprint

Usage

1. Add Whiteprint to your model

classCarincludeWhiteprint::Modelend

Alternatively, in an ActiveRecord model you could also use has_whiteprint.

classCar < ActiveRecord::Basehas_whiteprintend

2. Add some attributes

classCar < ActiveRecord::BaseincludeWhiteprint::Modelwhiteprintdostring:brand,default: 'BMW'string:nametext:descriptiondecimal:price,precision: 5,scale: 10endend

3. Generate a migration

Let Whiteprint generate a migration to update your database schema for you (only ActiveRecord at the moment). Run:

rake whiteprint:migrate

Whiteprint will check all your models for changes and list them in your terminal. If multiple models have changes it will ask you if you want to apply these changes in one or separate migrations.

Whiteprint has detected 1 changes to your models.
+----------------------------+------------------------+--------------------------------------------+
| 1. Create a new table cars |
+----------------------------+------------------------+--------------------------------------------+
| name | type | options |
+----------------------------+------------------------+--------------------------------------------+
| brand | string | {:default=>"BMW"} |
| name | string | {} |
| description | text | {} |
| price | decimal | {:precision=>10, :scale=>5} |
| timestamps | | |
+----------------------------+------------------------+--------------------------------------------+
Migrations:
1. In one migration
2. In separate migrations
How would you like to process these changes?
> 1
How would you like to name this migration?
> Create cars

Your migration wil be created and migrated.

# db/migrate/*********_create_cars.rbclassCreateCars < ActiveRecord::Migrationdefchangecreate_table:carsdo |t|
t.string:brand,{:default=>"BMW"}t.string:name,{}t.text:description,{}t.decimal:price,{:precision=>10,:scale=>5}t.timestampsendendend
== 20160905153022 CreateCars: migrating =======================================
-- create_table(:cars)
-> 0.0081s
== 20160905153022 CreateCars: migrated (0.0082s) ==============================

4. Make some changes to your model

If we make some changes to our Car model and run whiteprint:migrate again, Whiteprint will detect these changes and create a migration to update your table.

classCar < ActiveRecord::BaseincludeWhiteprint::Modelwhiteprintdostring:brand,default: 'Ford'string:namedecimal:price,precision: 10,scale: 5references:colorendend
> rake whiteprint:migrate
Whiteprint has detected 1 changes to your models.
+--------+-------------+------------+------------------+--------------------+----------------------+
| 1. Make changes to cars |
+--------+-------------+------------+------------------+--------------------+----------------------+
| action | name | type | type (currently) | options | options (currently) |
+--------+-------------+------------+------------------+--------------------+----------------------+
| added | color | references | | {} | |
| change | brand | string | string | {:default=>"Ford"} | {:default=>"BMW"} |
| remove | description | | | | |
+--------+-------------+------------+------------------+--------------------+----------------------+
Migrations:
1. In one migration
2. In separate migrations
How would you like to process these changes?
1
How would you like to name this migration?
Add color change default brand and remove description for cars
== 20160905162923 AddColorChangeDefaultBrandAndRemoveDescriptionForCars: migrating
-- change_table(:cars)
-> 0.0032s
== 20160905162923 AddColorChangeDefaultBrandAndRemoveDescriptionForCars: migrated (0.0034s)

Adapters

Whiteprint is made to be persistence layer agnostic, but at this moment only an ActiveRecord adapter is implemented. If you would like to implement an adapter for another persistence layer please contact us. We'd love to help you.

An example of a Whiteprint adapter:

moduleWhiteprintmoduleAdaptersclassMyOwnAdapater < ::Whiteprint::Baseclass << selfdefapplicable?(model)# method used to automatically select an adapter for a model.# for example:model < MyOrm::Baseenddefgenerate_migration(name,trees)# create a migration here given a set of trees with changes# look at the activerecord adapter for further implementation detailsendenddefpersisted_attributes# this method has to return the current attributes of the persistance layer# return an instance of Whiteprint::Attributesend# The whiteprint do ... end block in your model is executed in the context of your adapter instance# you can add methods to add functionality to your adapter. For example:defaddress(name)@attributes.addname: "#{name}_street",type: :text@attributes.addname: "#{name}_house_number",type: :integer@attributes.addname: "#{name}_city",type: :textend# And then you could do:# class Company < MyOrm::Base# include Whiteprint::Model## whiteprint do# address :office# end# endendendend

ActiveRecord Adapter

The ActiveRecord adapter has some special properties which are explained in this section.

Default id and timestamps

By default the adapter will add id and timestamps columns. You can disable this behaviour by passing arguments to the whiteprint method.

Model without an id:

whiteprint(id: false)do# ...end

Model without timestamps:

whiteprint(timestamps: false)do# ...end

References

Adding an references columns will automatically set a belongs_to association on the model. Any options for the association can be passed in the whiteprint block.

whiteprintdoreferences:fileable,polymorphic: trueend

You can disable this behaviour by passing auto_belongs_to: false to the whiteprint method.

Has and belongs to many

The activerecord adapter has support for a has_and_belongs_to_many attribute. This won't add a column to your model's table, but instead create a join table and set the association.

whiteprintdohas_and_belongs_to_many:categoriesend

habtm is added as an alias

Method as default value

You can specify a symbol as the default value for an attribute for dynamic defaults.

classCar < ActiveRecord::BaseincludeWhiteprint::Modelwhiteprintdoreferences:user,default: :current_userendprivatedefcurrent_userUser.currentendend

Accessor

You can use the accessor type to add attr_accessors to your model

classUser < ActiveRecord::BaseincludeWhiteprint::Modelwhiteprintdotext:password_digestaccessor:passwordaccessor:password_confirmationendend

Attributes

The whiteprint instance of a model can be accessed using the whiteprint method: Model.whiteprint. The attributes of a whiteprint are available using the attributes method: Model.whiteprint.attributes. These attributes are an instance of Whiteprint::Attributes and have several helper methods available.

for_serializer

The for_serializer helper lists all attributes that aren't private or associations.

classCar < ActiveRecord::BaseincludeWhiteprint::Modelwhiteprintdostring:brand,default: 'Ford'string:namedecimal:price,precision: 10,scale: 5,private: truereferences:colorendendCar.whiteprint.attributes.for_serializer# [:id, :created_at, :updated_at, :brand, :name]# usage exampleclassCarSerializer < ActiveModel::Serializerattributes *Car.whiteprint.attributes.for_serializerend

for_permitted

The for_serializer helper lists all attributes that aren't private or readonly in a format suitable for Rails' strong paramters.

classCar < ActiveRecord::BaseincludeWhiteprint::Modelwhiteprintdostring:brand,default: 'Ford'string:name,readonly: truetext:specs,array: truedecimal:price,precision: 10,scale: 5,private: truereferences:colorhabtm:owners,class_name: 'User'endendCar.whiteprint.attributes.for_permitted# [:id, :brand, {:specs=>[]}, :color_id, {:owner_ids=>[]}]# usage exampledefpermitted_paramsparams.require(:car).permit(*Car.whiteprint.attributes.for_permitted)end

for_meta

The for_meta helper lists all meta info that is specified for attributes. The meta_attribute_options config determines which options should be listed by this helper.

Whiteprint.configdo |c|
c.meta_attribute_options=[:enum,:label]endclassCar < ActiveRecord::BaseincludeWhiteprint::Modelwhiteprintdostring:brand,default: 'Ford',enum: {"Ford"=>"Ford","BMW"=>"BMW","Audi"=>"Audi"},label: 'Merk'string:name,label: 'Naam'text:specs,array: truedecimal:price,precision: 10,scale: 5,private: truereferences:colorhabtm:owners,class_name: 'User'endendCar.whiteprint.attributes.for_meta# {:brand=>{:enum=>{"Ford"=>"Ford", "BMW"=>"BMW", "Audi"=>"Audi"}, :label=>"Merk"}, :name=>{:label=>"Naam"}}# example usagerenderjson: @car,meta: Car.whiteprint.attributes.for_meta

Composability

Whiteprints are inherited and can be composed.

classAnimalincludeWhiteprint::Modelwhiteprintdotext:nametext:descriptionendendmoduleMammalextendActiveSupport::Concernincludeddowhiteprintdointeger:gestation_periodendendendclassDog < AnimalincludeMammalwhiteprintdostring:breedendendclassCat < AnimalincludeMammalwhiteprintdoboolean:domestic,default: trueendendCat.whiteprint.attributes.to_a.map(&:to_h)# [{:name=>:name, :type=>:text}, {:name=>:description, :type=>:text}, {:name=>:gestation_period, :type=>:integer}, {:name=>:domestic, :type=>:boolean, :default=>true}]Dog.whiteprint.attributes.to_a.map(&:to_h)#[{:name=>:name, :type=>:text}, {:name=>:description, :type=>:text}, {:name=>:gestation_period, :type=>:integer}, {:name=>:breed, :type=>:string}]

Configuration

Whiteprint.configdo |c|
# which adapter to use if none is applicablec.default_adapter=:base# Models have to be loaded before whiteprint:migrate runs. Set to true to let Whiteprint do this for you.c.eager_load=false# default true for Rails projects# Define which path(s) contain whiteprint modelsc.eager_load_paths=[]# Define which attribute options are persistedc.persisted_attribute_options={array: false,limit: nil,precision: nil,scale: nil,polymorphic: false,null: true,default: nil}# Define the attribute options for the for_meta gelperc.meta_attribute_options=[:enum]# Define if changes should be run in a single or separately migrations. One of: :ask, :separately, :togetherc.migration_strategy=:ask# Define if migrations should be automatically added to gitc.add_migration_to_git=falseend

Origin

Whiteprint is extracted from an application framework we use internally. Right now, our framework is lacking tests and documentation, but we intend to open source more parts of our framework in the future.

About

No description, website, or topics provided.

Resources

Code of conduct

Stars

0 stars

Watchers

2 watching

Forks

Releases

Packages

Used by

Contributors

Languages